aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat
diff options
context:
space:
mode:
authorOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>2008-11-06 15:53:51 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-11-06 18:41:21 -0500
commit1b52467243c7167b3a267ddbcbb14d550f28eb4a (patch)
treef55bae4d0b970216bda77c29094f19575f3b6c42 /fs/fat
parent068f5ae05c51d2cee6b31cb3da06775dd83bd348 (diff)
fat: Fix/Cleanup dcache handling for vfat
- Add comments for handling dcache of vfat. - Separate case-sensitive case and case-insensitive to vfat_revalidate() and vfat_ci_revalidate(). vfat_revalidate() doesn't need to drop case-insensitive negative dentry on creation path. - Current code is missing to set ->d_revalidate to the negative dentry created by unlink/etc.. This sets ->d_revalidate always, and returns 1 for positive dentry. Now, we don't need to change ->d_op dynamically anymore, so this just uses sb->s_root->d_op to set ->d_op. - d_find_alias() may return DCACHE_DISCONNECTED dentry. It's not the interesting dentry there. This checks it. - Add missing LOOKUP_PARENT check. We don't need to drop the valid negative dentry for (LOOKUP_CREATE | LOOKUP_PARENT) lookup. - For consistent filename on creation path, this drops negative dentry if we can't see intent. Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> 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.c124
1 files changed, 80 insertions, 44 deletions
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index 419deabfb9be..d585398f9f6b 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -24,27 +24,67 @@
24#include <linux/namei.h> 24#include <linux/namei.h>
25#include "fat.h" 25#include "fat.h"
26 26
27static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd) 27/*
28 * If new entry was created in the parent, it could create the 8.3
29 * alias (the shortname of logname). So, the parent may have the
30 * negative-dentry which matches the created 8.3 alias.
31 *
32 * If it happened, the negative dentry isn't actually negative
33 * anymore. So, drop it.
34 */
35static int vfat_revalidate_shortname(struct dentry *dentry)
28{ 36{
29 int ret = 1; 37 int ret = 1;
30 38 spin_lock(&dentry->d_lock);
31 if (!dentry->d_inode && 39 if (dentry->d_time != dentry->d_parent->d_inode->i_version)
32 nd && !(nd->flags & LOOKUP_CONTINUE) && (nd->flags & LOOKUP_CREATE))
33 /*
34 * negative dentry is dropped, in order to make sure
35 * to use the name which a user desires if this is
36 * create path.
37 */
38 ret = 0; 40 ret = 0;
39 else { 41 spin_unlock(&dentry->d_lock);
40 spin_lock(&dentry->d_lock);
41 if (dentry->d_time != dentry->d_parent->d_inode->i_version)
42 ret = 0;
43 spin_unlock(&dentry->d_lock);
44 }
45 return ret; 42 return ret;
46} 43}
47 44
45static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
46{
47 /* This is not negative dentry. Always valid. */
48 if (dentry->d_inode)
49 return 1;
50 return vfat_revalidate_shortname(dentry);
51}
52
53static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
54{
55 /*
56 * This is not negative dentry. Always valid.
57 *
58 * Note, rename() to existing directory entry will have ->d_inode,
59 * and will use existing name which isn't specified name by user.
60 *
61 * We may be able to drop this positive dentry here. But dropping
62 * positive dentry isn't good idea. So it's unsupported like
63 * rename("filename", "FILENAME") for now.
64 */
65 if (dentry->d_inode)
66 return 1;
67
68 /*
69 * This may be nfsd (or something), anyway, we can't see the
70 * intent of this. So, since this can be for creation, drop it.
71 */
72 if (!nd)
73 return 0;
74
75 /*
76 * Drop the negative dentry, in order to make sure to use the
77 * case sensitive name which is specified by user if this is
78 * for creation.
79 */
80 if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) {
81 if (nd->flags & LOOKUP_CREATE)
82 return 0;
83 }
84
85 return vfat_revalidate_shortname(dentry);
86}
87
48/* returns the length of a struct qstr, ignoring trailing dots */ 88/* returns the length of a struct qstr, ignoring trailing dots */
49static unsigned int vfat_striptail_len(struct qstr *qstr) 89static unsigned int vfat_striptail_len(struct qstr *qstr)
50{ 90{
@@ -126,25 +166,16 @@ static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
126 return 1; 166 return 1;
127} 167}
128 168
129static struct dentry_operations vfat_dentry_ops[4] = { 169static struct dentry_operations vfat_ci_dentry_ops = {
130 { 170 .d_revalidate = vfat_revalidate_ci,
131 .d_hash = vfat_hashi, 171 .d_hash = vfat_hashi,
132 .d_compare = vfat_cmpi, 172 .d_compare = vfat_cmpi,
133 }, 173};
134 { 174
135 .d_revalidate = vfat_revalidate, 175static struct dentry_operations vfat_dentry_ops = {
136 .d_hash = vfat_hashi, 176 .d_revalidate = vfat_revalidate,
137 .d_compare = vfat_cmpi, 177 .d_hash = vfat_hash,
138 }, 178 .d_compare = vfat_cmp,
139 {
140 .d_hash = vfat_hash,
141 .d_compare = vfat_cmp,
142 },
143 {
144 .d_revalidate = vfat_revalidate,
145 .d_hash = vfat_hash,
146 .d_compare = vfat_cmp,
147 }
148}; 179};
149 180
150/* Characters that are undesirable in an MS-DOS file name */ 181/* Characters that are undesirable in an MS-DOS file name */
@@ -685,29 +716,35 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
685 struct fat_slot_info sinfo; 716 struct fat_slot_info sinfo;
686 struct inode *inode; 717 struct inode *inode;
687 struct dentry *alias; 718 struct dentry *alias;
688 int err, table; 719 int err;
689 720
690 lock_super(sb); 721 lock_super(sb);
691 table = (MSDOS_SB(sb)->options.name_check == 's') ? 2 : 0;
692 dentry->d_op = &vfat_dentry_ops[table];
693 722
694 err = vfat_find(dir, &dentry->d_name, &sinfo); 723 err = vfat_find(dir, &dentry->d_name, &sinfo);
695 if (err) { 724 if (err) {
696 if (err == -ENOENT) { 725 if (err == -ENOENT) {
697 table++;
698 inode = NULL; 726 inode = NULL;
699 goto out; 727 goto out;
700 } 728 }
701 goto error; 729 goto error;
702 } 730 }
731
703 inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); 732 inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
704 brelse(sinfo.bh); 733 brelse(sinfo.bh);
705 if (IS_ERR(inode)) { 734 if (IS_ERR(inode)) {
706 err = PTR_ERR(inode); 735 err = PTR_ERR(inode);
707 goto error; 736 goto error;
708 } 737 }
738
709 alias = d_find_alias(inode); 739 alias = d_find_alias(inode);
710 if (alias) { 740 if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
741 /*
742 * This inode has non DCACHE_DISCONNECTED dentry. This
743 * means, the user did ->lookup() by an another name
744 * (longname vs 8.3 alias of it) in past.
745 *
746 * Switch to new one for reason of locality if possible.
747 */
711 if (d_invalidate(alias) == 0) 748 if (d_invalidate(alias) == 0)
712 dput(alias); 749 dput(alias);
713 else { 750 else {
@@ -715,15 +752,14 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
715 unlock_super(sb); 752 unlock_super(sb);
716 return alias; 753 return alias;
717 } 754 }
718
719 } 755 }
720out: 756out:
721 unlock_super(sb); 757 unlock_super(sb);
722 dentry->d_op = &vfat_dentry_ops[table]; 758 dentry->d_op = sb->s_root->d_op;
723 dentry->d_time = dentry->d_parent->d_inode->i_version; 759 dentry->d_time = dentry->d_parent->d_inode->i_version;
724 dentry = d_splice_alias(inode, dentry); 760 dentry = d_splice_alias(inode, dentry);
725 if (dentry) { 761 if (dentry) {
726 dentry->d_op = &vfat_dentry_ops[table]; 762 dentry->d_op = sb->s_root->d_op;
727 dentry->d_time = dentry->d_parent->d_inode->i_version; 763 dentry->d_time = dentry->d_parent->d_inode->i_version;
728 } 764 }
729 return dentry; 765 return dentry;
@@ -1022,9 +1058,9 @@ static int vfat_fill_super(struct super_block *sb, void *data, int silent)
1022 return res; 1058 return res;
1023 1059
1024 if (MSDOS_SB(sb)->options.name_check != 's') 1060 if (MSDOS_SB(sb)->options.name_check != 's')
1025 sb->s_root->d_op = &vfat_dentry_ops[0]; 1061 sb->s_root->d_op = &vfat_ci_dentry_ops;
1026 else 1062 else
1027 sb->s_root->d_op = &vfat_dentry_ops[2]; 1063 sb->s_root->d_op = &vfat_dentry_ops;
1028 1064
1029 return 0; 1065 return 0;
1030} 1066}