diff options
author | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:49:27 -0500 |
---|---|---|
committer | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:50:19 -0500 |
commit | 621e155a3591962420eacdd39f6f0aa29ceb221e (patch) | |
tree | 387a9fb396f1bf24514b712c294182e36ba51076 /fs/fat | |
parent | fb2d5b86aff355a27ebfc132d3c99f4a940cc3fe (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.c | 14 | ||||
-rw-r--r-- | fs/fat/namei_vfat.c | 33 |
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 | */ |
167 | static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) | 167 | static 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 | ||
183 | old_compare: | 185 | old_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 */ |
88 | static unsigned int vfat_striptail_len(struct qstr *qstr) | 88 | static 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 | ||
95 | static 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 | */ |
136 | static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b) | 139 | static 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 | */ |
154 | static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) | 159 | static 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; |