Commit 1ead0e79bfedd4b563b8ea7c585ca3884b0c89a7

Authored by Al Viro
Committed by Linus Torvalds
1 parent e8577d1f03

fat: fix oops on corrupted vfat fs

a) don't bother with ->d_time for positives - we only check it for
   negatives anyway.

b) make sure to set it at unlink and rmdir time - at *that* point
   soon-to-be negative dentry matches then-current directory contents

c) don't go into renaming of old alias in vfat_lookup() unless it
   has the same parent (which it will, unless we are seeing corrupted
   image)

[hirofumi@mail.parknet.co.jp: make change minimum, don't call d_move() for dir]
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: <stable@vger.kernel.org>	[3.17.x]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 1 changed file with 11 additions and 9 deletions Side-by-side Diff

... ... @@ -736,7 +736,12 @@
736 736 }
737 737  
738 738 alias = d_find_alias(inode);
739   - if (alias && !vfat_d_anon_disconn(alias)) {
  739 + /*
  740 + * Checking "alias->d_parent == dentry->d_parent" to make sure
  741 + * FS is not corrupted (especially double linked dir).
  742 + */
  743 + if (alias && alias->d_parent == dentry->d_parent &&
  744 + !vfat_d_anon_disconn(alias)) {
740 745 /*
741 746 * This inode has non anonymous-DCACHE_DISCONNECTED
742 747 * dentry. This means, the user did ->lookup() by an
... ... @@ -755,12 +760,9 @@
755 760  
756 761 out:
757 762 mutex_unlock(&MSDOS_SB(sb)->s_lock);
758   - dentry->d_time = dentry->d_parent->d_inode->i_version;
759   - dentry = d_splice_alias(inode, dentry);
760   - if (dentry)
761   - dentry->d_time = dentry->d_parent->d_inode->i_version;
762   - return dentry;
763   -
  763 + if (!inode)
  764 + dentry->d_time = dir->i_version;
  765 + return d_splice_alias(inode, dentry);
764 766 error:
765 767 mutex_unlock(&MSDOS_SB(sb)->s_lock);
766 768 return ERR_PTR(err);
... ... @@ -793,7 +795,6 @@
793 795 inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
794 796 /* timestamp is already written, so mark_inode_dirty() is unneeded. */
795 797  
796   - dentry->d_time = dentry->d_parent->d_inode->i_version;
797 798 d_instantiate(dentry, inode);
798 799 out:
799 800 mutex_unlock(&MSDOS_SB(sb)->s_lock);
... ... @@ -824,6 +825,7 @@
824 825 clear_nlink(inode);
825 826 inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
826 827 fat_detach(inode);
  828 + dentry->d_time = dir->i_version;
827 829 out:
828 830 mutex_unlock(&MSDOS_SB(sb)->s_lock);
829 831  
... ... @@ -849,6 +851,7 @@
849 851 clear_nlink(inode);
850 852 inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
851 853 fat_detach(inode);
  854 + dentry->d_time = dir->i_version;
852 855 out:
853 856 mutex_unlock(&MSDOS_SB(sb)->s_lock);
854 857  
... ... @@ -889,7 +892,6 @@
889 892 inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
890 893 /* timestamp is already written, so mark_inode_dirty() is unneeded. */
891 894  
892   - dentry->d_time = dentry->d_parent->d_inode->i_version;
893 895 d_instantiate(dentry, inode);
894 896  
895 897 mutex_unlock(&MSDOS_SB(sb)->s_lock);