aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc
diff options
context:
space:
mode:
authorAlexey Dobriyan <adobriyan@gmail.com>2010-03-05 16:43:59 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2010-03-06 14:26:45 -0500
commite17a5765f20d1219c3f05eb17aab11671978e0ec (patch)
tree6dae8ad2358efac94587dd86104fdccc715fbfde /fs/proc
parent5748150eabdacd3f870c311b63d32f5e312bf624 (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')
-rw-r--r--fs/proc/generic.c31
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 */
294static int xlate_proc_name(const char *name, 294static 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;
325out: 321 return 0;
322}
323
324static 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
330static DEFINE_IDA(proc_inum_ida); 335static 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;