diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-10 15:19:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-10 22:54:09 -0400 |
commit | 94753db5ed9ad97582ef453127d9626a7a2be602 (patch) | |
tree | ebf9b6cce17c3f4348a598988cb398a9807b3db7 /fs/dcache.c | |
parent | 8c01a529b861ba97c7d78368e6a5d4d42e946f75 (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.c | 54 |
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 | */ |
156 | static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *ct, unsigned tcount) | 156 | static 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 | ||
200 | static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *ct, unsigned tcount) | 179 | static 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 | ||
193 | static 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 | |||
219 | static void __d_free(struct rcu_head *head) | 217 | static 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); |