diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2010-03-05 16:43:59 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-06 14:26:45 -0500 |
commit | e17a5765f20d1219c3f05eb17aab11671978e0ec (patch) | |
tree | 6dae8ad2358efac94587dd86104fdccc715fbfde /fs/proc/generic.c | |
parent | 5748150eabdacd3f870c311b63d32f5e312bf624 (diff) |
proc: do translation + unlink atomically at remove_proc_entry()
remove_proc_entry() does
lock
lookup parent
unlock
lock
unlink proc entry from lists
unlock
which can be made bit more correct by doing parent translation + unlink
without dropping lock.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/proc/generic.c')
-rw-r--r-- | fs/proc/generic.c | 31 |
1 files changed, 19 insertions, 12 deletions
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 9580abeadeb3..ce2d95477701 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -291,19 +291,17 @@ static const struct inode_operations proc_file_inode_operations = { | |||
291 | * returns the struct proc_dir_entry for "/proc/tty/driver", and | 291 | * returns the struct proc_dir_entry for "/proc/tty/driver", and |
292 | * returns "serial" in residual. | 292 | * returns "serial" in residual. |
293 | */ | 293 | */ |
294 | static int xlate_proc_name(const char *name, | 294 | static int __xlate_proc_name(const char *name, struct proc_dir_entry **ret, |
295 | struct proc_dir_entry **ret, const char **residual) | 295 | const char **residual) |
296 | { | 296 | { |
297 | const char *cp = name, *next; | 297 | const char *cp = name, *next; |
298 | struct proc_dir_entry *de; | 298 | struct proc_dir_entry *de; |
299 | int len; | 299 | int len; |
300 | int rtn = 0; | ||
301 | 300 | ||
302 | de = *ret; | 301 | de = *ret; |
303 | if (!de) | 302 | if (!de) |
304 | de = &proc_root; | 303 | de = &proc_root; |
305 | 304 | ||
306 | spin_lock(&proc_subdir_lock); | ||
307 | while (1) { | 305 | while (1) { |
308 | next = strchr(cp, '/'); | 306 | next = strchr(cp, '/'); |
309 | if (!next) | 307 | if (!next) |
@@ -314,17 +312,24 @@ static int xlate_proc_name(const char *name, | |||
314 | if (proc_match(len, cp, de)) | 312 | if (proc_match(len, cp, de)) |
315 | break; | 313 | break; |
316 | } | 314 | } |
317 | if (!de) { | 315 | if (!de) |
318 | rtn = -ENOENT; | 316 | return -ENOENT; |
319 | goto out; | ||
320 | } | ||
321 | cp += len + 1; | 317 | cp += len + 1; |
322 | } | 318 | } |
323 | *residual = cp; | 319 | *residual = cp; |
324 | *ret = de; | 320 | *ret = de; |
325 | out: | 321 | return 0; |
322 | } | ||
323 | |||
324 | static int xlate_proc_name(const char *name, struct proc_dir_entry **ret, | ||
325 | const char **residual) | ||
326 | { | ||
327 | int rv; | ||
328 | |||
329 | spin_lock(&proc_subdir_lock); | ||
330 | rv = __xlate_proc_name(name, ret, residual); | ||
326 | spin_unlock(&proc_subdir_lock); | 331 | spin_unlock(&proc_subdir_lock); |
327 | return rtn; | 332 | return rv; |
328 | } | 333 | } |
329 | 334 | ||
330 | static DEFINE_IDA(proc_inum_ida); | 335 | static DEFINE_IDA(proc_inum_ida); |
@@ -797,11 +802,13 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
797 | const char *fn = name; | 802 | const char *fn = name; |
798 | int len; | 803 | int len; |
799 | 804 | ||
800 | if (xlate_proc_name(name, &parent, &fn) != 0) | 805 | spin_lock(&proc_subdir_lock); |
806 | if (__xlate_proc_name(name, &parent, &fn) != 0) { | ||
807 | spin_unlock(&proc_subdir_lock); | ||
801 | return; | 808 | return; |
809 | } | ||
802 | len = strlen(fn); | 810 | len = strlen(fn); |
803 | 811 | ||
804 | spin_lock(&proc_subdir_lock); | ||
805 | for (p = &parent->subdir; *p; p=&(*p)->next ) { | 812 | for (p = &parent->subdir; *p; p=&(*p)->next ) { |
806 | if (proc_match(len, fn, *p)) { | 813 | if (proc_match(len, fn, *p)) { |
807 | de = *p; | 814 | de = *p; |