Commit 8045e2985012bdb95d832dfbcceae1815880a6ed
1 parent
3c8ad49b01
Exists in
master
and in
7 other branches
fat: Fix vfat_lookup()
After d_find_alias(), vfat_lookup() checks !(->d_flags & DCACHE_DISCONNECTED) without IS_ROOT(). This means it hits non-anonymous but disconnected dentry. (NOTE: d_splice_alias() doesn't clear DCACHE_DISCONNECTED) But, vfat_lookup() has interest to alias if it was non-anonymous. So, this adds vfat_d_anon_disconn() helper to check it correctly. Another bug is refcnt leak. It needs dput() for uninterested alias. Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Showing 1 changed file with 16 additions and 5 deletions Side-by-side Diff
fs/fat/namei_vfat.c
... | ... | @@ -701,6 +701,15 @@ |
701 | 701 | return fat_search_long(dir, qname->name, len, sinfo); |
702 | 702 | } |
703 | 703 | |
704 | +/* | |
705 | + * (nfsd's) anonymous disconnected dentry? | |
706 | + * NOTE: !IS_ROOT() is not anonymous (I.e. d_splice_alias() did the job). | |
707 | + */ | |
708 | +static int vfat_d_anon_disconn(struct dentry *dentry) | |
709 | +{ | |
710 | + return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); | |
711 | +} | |
712 | + | |
704 | 713 | static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, |
705 | 714 | struct nameidata *nd) |
706 | 715 | { |
707 | 716 | |
... | ... | @@ -729,11 +738,11 @@ |
729 | 738 | } |
730 | 739 | |
731 | 740 | alias = d_find_alias(inode); |
732 | - if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) { | |
741 | + if (alias && !vfat_d_anon_disconn(alias)) { | |
733 | 742 | /* |
734 | - * This inode has non DCACHE_DISCONNECTED dentry. This | |
735 | - * means, the user did ->lookup() by an another name | |
736 | - * (longname vs 8.3 alias of it) in past. | |
743 | + * This inode has non anonymous-DCACHE_DISCONNECTED | |
744 | + * dentry. This means, the user did ->lookup() by an | |
745 | + * another name (longname vs 8.3 alias of it) in past. | |
737 | 746 | * |
738 | 747 | * Switch to new one for reason of locality if possible. |
739 | 748 | */ |
... | ... | @@ -743,7 +752,9 @@ |
743 | 752 | iput(inode); |
744 | 753 | unlock_super(sb); |
745 | 754 | return alias; |
746 | - } | |
755 | + } else | |
756 | + dput(alias); | |
757 | + | |
747 | 758 | out: |
748 | 759 | unlock_super(sb); |
749 | 760 | dentry->d_op = sb->s_root->d_op; |