aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-10 15:19:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-10 22:54:09 -0400
commit94753db5ed9ad97582ef453127d9626a7a2be602 (patch)
treeebf9b6cce17c3f4348a598988cb398a9807b3db7 /fs/dcache.c
parent8c01a529b861ba97c7d78368e6a5d4d42e946f75 (diff)
vfs: do the careful dentry name access for all dentry_cmp cases
Commit 12f8ad4b0533 ("vfs: clean up __d_lookup_rcu() and dentry_cmp() interfaces") did the careful ACCESS_ONCE() of the dentry name only for the word-at-a-time case, even though the issue is generic. Admittedly I don't really see gcc ever reloading the value in the middle of the loop, so the ACCESS_ONCE() protects us from a fairly theoretical issue. But better safe than sorry. Also, this consolidates the common parts of the word-at-a-time and bytewise logic, which includes checking the length. We'll be changing that later. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
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);