aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-12-02 18:59:37 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-03 12:36:03 -0500
commit1ead0e79bfedd4b563b8ea7c585ca3884b0c89a7 (patch)
tree7ef8e695dea004a6c6d8b8f2b602140b2912a014 /fs/fat
parente8577d1f0329d4842e8302e289fb2c22156abef4 (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.c20
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
756out: 761out:
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
764error: 766error:
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);
798out: 799out:
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;
827out: 829out:
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;
852out: 855out:
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);