aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2011-01-07 01:49:27 -0500
committerNick Piggin <npiggin@kernel.dk>2011-01-07 01:50:19 -0500
commit621e155a3591962420eacdd39f6f0aa29ceb221e (patch)
tree387a9fb396f1bf24514b712c294182e36ba51076 /fs/fat
parentfb2d5b86aff355a27ebfc132d3c99f4a940cc3fe (diff)
fs: change d_compare for rcu-walk
Change d_compare so it may be called from lock-free RCU lookups. This does put significant restrictions on what may be done from the callback, however there don't seem to have been any problems with in-tree fses. If some strange use case pops up that _really_ cannot cope with the rcu-walk rules, we can just add new rcu-unaware callbacks, which would cause name lookup to drop out of rcu-walk mode. For in-tree filesystems, this is just a mechanical change. Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Diffstat (limited to 'fs/fat')
-rw-r--r--fs/fat/namei_msdos.c14
-rw-r--r--fs/fat/namei_vfat.c33
2 files changed, 28 insertions, 19 deletions
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index 3345aabd1dd7..99d3c7ac973c 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -164,16 +164,18 @@ static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
164 * Compare two msdos names. If either of the names are invalid, 164 * Compare two msdos names. If either of the names are invalid,
165 * we fall back to doing the standard name comparison. 165 * we fall back to doing the standard name comparison.
166 */ 166 */
167static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) 167static int msdos_cmp(const struct dentry *parent, const struct inode *pinode,
168 const struct dentry *dentry, const struct inode *inode,
169 unsigned int len, const char *str, const struct qstr *name)
168{ 170{
169 struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options; 171 struct fat_mount_options *options = &MSDOS_SB(parent->d_sb)->options;
170 unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME]; 172 unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
171 int error; 173 int error;
172 174
173 error = msdos_format_name(a->name, a->len, a_msdos_name, options); 175 error = msdos_format_name(name->name, name->len, a_msdos_name, options);
174 if (error) 176 if (error)
175 goto old_compare; 177 goto old_compare;
176 error = msdos_format_name(b->name, b->len, b_msdos_name, options); 178 error = msdos_format_name(str, len, b_msdos_name, options);
177 if (error) 179 if (error)
178 goto old_compare; 180 goto old_compare;
179 error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME); 181 error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
@@ -182,8 +184,8 @@ out:
182 184
183old_compare: 185old_compare:
184 error = 1; 186 error = 1;
185 if (a->len == b->len) 187 if (name->len == len)
186 error = memcmp(a->name, b->name, a->len); 188 error = memcmp(name->name, str, len);
187 goto out; 189 goto out;
188} 190}
189 191
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index b936703b8924..95e00ab84c3f 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -85,15 +85,18 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
85} 85}
86 86
87/* returns the length of a struct qstr, ignoring trailing dots */ 87/* returns the length of a struct qstr, ignoring trailing dots */
88static unsigned int vfat_striptail_len(struct qstr *qstr) 88static unsigned int __vfat_striptail_len(unsigned int len, const char *name)
89{ 89{
90 unsigned int len = qstr->len; 90 while (len && name[len - 1] == '.')
91
92 while (len && qstr->name[len - 1] == '.')
93 len--; 91 len--;
94 return len; 92 return len;
95} 93}
96 94
95static unsigned int vfat_striptail_len(const struct qstr *qstr)
96{
97 return __vfat_striptail_len(qstr->len, qstr->name);
98}
99
97/* 100/*
98 * Compute the hash for the vfat name corresponding to the dentry. 101 * Compute the hash for the vfat name corresponding to the dentry.
99 * Note: if the name is invalid, we leave the hash code unchanged so 102 * Note: if the name is invalid, we leave the hash code unchanged so
@@ -133,16 +136,18 @@ static int vfat_hashi(struct dentry *dentry, struct qstr *qstr)
133/* 136/*
134 * Case insensitive compare of two vfat names. 137 * Case insensitive compare of two vfat names.
135 */ 138 */
136static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b) 139static int vfat_cmpi(const struct dentry *parent, const struct inode *pinode,
140 const struct dentry *dentry, const struct inode *inode,
141 unsigned int len, const char *str, const struct qstr *name)
137{ 142{
138 struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io; 143 struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io;
139 unsigned int alen, blen; 144 unsigned int alen, blen;
140 145
141 /* A filename cannot end in '.' or we treat it like it has none */ 146 /* A filename cannot end in '.' or we treat it like it has none */
142 alen = vfat_striptail_len(a); 147 alen = vfat_striptail_len(name);
143 blen = vfat_striptail_len(b); 148 blen = __vfat_striptail_len(len, str);
144 if (alen == blen) { 149 if (alen == blen) {
145 if (nls_strnicmp(t, a->name, b->name, alen) == 0) 150 if (nls_strnicmp(t, name->name, str, alen) == 0)
146 return 0; 151 return 0;
147 } 152 }
148 return 1; 153 return 1;
@@ -151,15 +156,17 @@ static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b)
151/* 156/*
152 * Case sensitive compare of two vfat names. 157 * Case sensitive compare of two vfat names.
153 */ 158 */
154static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) 159static int vfat_cmp(const struct dentry *parent, const struct inode *pinode,
160 const struct dentry *dentry, const struct inode *inode,
161 unsigned int len, const char *str, const struct qstr *name)
155{ 162{
156 unsigned int alen, blen; 163 unsigned int alen, blen;
157 164
158 /* A filename cannot end in '.' or we treat it like it has none */ 165 /* A filename cannot end in '.' or we treat it like it has none */
159 alen = vfat_striptail_len(a); 166 alen = vfat_striptail_len(name);
160 blen = vfat_striptail_len(b); 167 blen = __vfat_striptail_len(len, str);
161 if (alen == blen) { 168 if (alen == blen) {
162 if (strncmp(a->name, b->name, alen) == 0) 169 if (strncmp(name->name, str, alen) == 0)
163 return 0; 170 return 0;
164 } 171 }
165 return 1; 172 return 1;