diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-12-02 18:59:37 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-03 12:36:03 -0500 |
commit | 1ead0e79bfedd4b563b8ea7c585ca3884b0c89a7 (patch) | |
tree | 7ef8e695dea004a6c6d8b8f2b602140b2912a014 /fs/fat | |
parent | e8577d1f0329d4842e8302e289fb2c22156abef4 (diff) |
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>
Diffstat (limited to 'fs/fat')
-rw-r--r-- | fs/fat/namei_vfat.c | 20 |
1 files changed, 11 insertions, 9 deletions
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 6df8d3d885e5..b8b92c2f9683 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c | |||
@@ -736,7 +736,12 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, | |||
736 | } | 736 | } |
737 | 737 | ||
738 | alias = d_find_alias(inode); | 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 | * This inode has non anonymous-DCACHE_DISCONNECTED | 746 | * This inode has non anonymous-DCACHE_DISCONNECTED |
742 | * dentry. This means, the user did ->lookup() by an | 747 | * dentry. This means, the user did ->lookup() by an |
@@ -755,12 +760,9 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, | |||
755 | 760 | ||
756 | out: | 761 | out: |
757 | mutex_unlock(&MSDOS_SB(sb)->s_lock); | 762 | mutex_unlock(&MSDOS_SB(sb)->s_lock); |
758 | dentry->d_time = dentry->d_parent->d_inode->i_version; | 763 | if (!inode) |
759 | dentry = d_splice_alias(inode, dentry); | 764 | dentry->d_time = dir->i_version; |
760 | if (dentry) | 765 | return d_splice_alias(inode, dentry); |
761 | dentry->d_time = dentry->d_parent->d_inode->i_version; | ||
762 | return dentry; | ||
763 | |||
764 | error: | 766 | error: |
765 | mutex_unlock(&MSDOS_SB(sb)->s_lock); | 767 | mutex_unlock(&MSDOS_SB(sb)->s_lock); |
766 | return ERR_PTR(err); | 768 | return ERR_PTR(err); |
@@ -793,7 +795,6 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, | |||
793 | inode->i_mtime = inode->i_atime = inode->i_ctime = ts; | 795 | inode->i_mtime = inode->i_atime = inode->i_ctime = ts; |
794 | /* timestamp is already written, so mark_inode_dirty() is unneeded. */ | 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 | d_instantiate(dentry, inode); | 798 | d_instantiate(dentry, inode); |
798 | out: | 799 | out: |
799 | mutex_unlock(&MSDOS_SB(sb)->s_lock); | 800 | mutex_unlock(&MSDOS_SB(sb)->s_lock); |
@@ -824,6 +825,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) | |||
824 | clear_nlink(inode); | 825 | clear_nlink(inode); |
825 | inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; | 826 | inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; |
826 | fat_detach(inode); | 827 | fat_detach(inode); |
828 | dentry->d_time = dir->i_version; | ||
827 | out: | 829 | out: |
828 | mutex_unlock(&MSDOS_SB(sb)->s_lock); | 830 | mutex_unlock(&MSDOS_SB(sb)->s_lock); |
829 | 831 | ||
@@ -849,6 +851,7 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry) | |||
849 | clear_nlink(inode); | 851 | clear_nlink(inode); |
850 | inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; | 852 | inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; |
851 | fat_detach(inode); | 853 | fat_detach(inode); |
854 | dentry->d_time = dir->i_version; | ||
852 | out: | 855 | out: |
853 | mutex_unlock(&MSDOS_SB(sb)->s_lock); | 856 | mutex_unlock(&MSDOS_SB(sb)->s_lock); |
854 | 857 | ||
@@ -889,7 +892,6 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
889 | inode->i_mtime = inode->i_atime = inode->i_ctime = ts; | 892 | inode->i_mtime = inode->i_atime = inode->i_ctime = ts; |
890 | /* timestamp is already written, so mark_inode_dirty() is unneeded. */ | 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 | d_instantiate(dentry, inode); | 895 | d_instantiate(dentry, inode); |
894 | 896 | ||
895 | mutex_unlock(&MSDOS_SB(sb)->s_lock); | 897 | mutex_unlock(&MSDOS_SB(sb)->s_lock); |