aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c54
1 files changed, 26 insertions, 28 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index c4d2ff8b4912..5c09ad7b4a15 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -153,30 +153,9 @@ int proc_nr_dentry(ctl_table *table, int write, void __user *buffer,
153 * In contrast, 'ct' and 'tcount' can be from a pathname, and do 153 * In contrast, 'ct' and 'tcount' can be from a pathname, and do
154 * need the careful unaligned handling. 154 * need the careful unaligned handling.
155 */ 155 */
156static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *ct, unsigned tcount) 156static inline int dentry_string_cmp(const unsigned char *cs, const unsigned char *ct, unsigned tcount)
157{ 157{
158 unsigned long a,b,mask; 158 unsigned long a,b,mask;
159 const unsigned char *cs;
160
161 if (unlikely(dentry->d_name.len != tcount))
162 return 1;
163 /*
164 * Be careful about RCU walk racing with rename:
165 * use ACCESS_ONCE to fetch the name pointer.
166 *
167 * NOTE! Even if a rename will mean that the length
168 * was not loaded atomically, we don't care. The
169 * RCU walk will check the sequence count eventually,
170 * and catch it. And we won't overrun the buffer,
171 * because we're reading the name pointer atomically,
172 * and a dentry name is guaranteed to be properly
173 * terminated with a NUL byte.
174 *
175 * End result: even if 'len' is wrong, we'll exit
176 * early because the data cannot match (there can
177 * be no NUL in the ct/tcount data)
178 */
179 cs = ACCESS_ONCE(dentry->d_name.name);
180 159
181 for (;;) { 160 for (;;) {
182 a = *(unsigned long *)cs; 161 a = *(unsigned long *)cs;
@@ -197,13 +176,8 @@ static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *c
197 176
198#else 177#else
199 178
200static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *ct, unsigned tcount) 179static inline int dentry_string_cmp(const unsigned char *cs, const unsigned char *ct, unsigned tcount)
201{ 180{
202 const unsigned char *cs = dentry->d_name.name;
203
204 if (dentry->d_name.len != tcount)
205 return 1;
206
207 do { 181 do {
208 if (*cs != *ct) 182 if (*cs != *ct)
209 return 1; 183 return 1;
@@ -216,6 +190,30 @@ static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *c
216 190
217#endif 191#endif
218 192
193static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *ct, unsigned tcount)
194{
195 if (dentry->d_name.len != tcount)
196 return 1;
197
198 /*
199 * Be careful about RCU walk racing with rename:
200 * use ACCESS_ONCE to fetch the name pointer.
201 *
202 * NOTE! Even if a rename will mean that the length
203 * was not loaded atomically, we don't care. The
204 * RCU walk will check the sequence count eventually,
205 * and catch it. And we won't overrun the buffer,
206 * because we're reading the name pointer atomically,
207 * and a dentry name is guaranteed to be properly
208 * terminated with a NUL byte.
209 *
210 * End result: even if 'len' is wrong, we'll exit
211 * early because the data cannot match (there can
212 * be no NUL in the ct/tcount data)
213 */
214 return dentry_string_cmp(ACCESS_ONCE(dentry->d_name.name), ct, tcount);
215}
216
219static void __d_free(struct rcu_head *head) 217static void __d_free(struct rcu_head *head)
220{ 218{
221 struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); 219 struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);