aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/generic.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc/generic.c')
-rw-r--r--fs/proc/generic.c163
1 files changed, 104 insertions, 59 deletions
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 317b72641ebf..7fea13229f33 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -31,9 +31,73 @@ static DEFINE_SPINLOCK(proc_subdir_lock);
31 31
32static int proc_match(unsigned int len, const char *name, struct proc_dir_entry *de) 32static int proc_match(unsigned int len, const char *name, struct proc_dir_entry *de)
33{ 33{
34 if (de->namelen != len) 34 if (len < de->namelen)
35 return 0; 35 return -1;
36 return !memcmp(name, de->name, len); 36 if (len > de->namelen)
37 return 1;
38
39 return memcmp(name, de->name, len);
40}
41
42static struct proc_dir_entry *pde_subdir_first(struct proc_dir_entry *dir)
43{
44 return rb_entry_safe(rb_first(&dir->subdir), struct proc_dir_entry,
45 subdir_node);
46}
47
48static struct proc_dir_entry *pde_subdir_next(struct proc_dir_entry *dir)
49{
50 return rb_entry_safe(rb_next(&dir->subdir_node), struct proc_dir_entry,
51 subdir_node);
52}
53
54static struct proc_dir_entry *pde_subdir_find(struct proc_dir_entry *dir,
55 const char *name,
56 unsigned int len)
57{
58 struct rb_node *node = dir->subdir.rb_node;
59
60 while (node) {
61 struct proc_dir_entry *de = container_of(node,
62 struct proc_dir_entry,
63 subdir_node);
64 int result = proc_match(len, name, de);
65
66 if (result < 0)
67 node = node->rb_left;
68 else if (result > 0)
69 node = node->rb_right;
70 else
71 return de;
72 }
73 return NULL;
74}
75
76static bool pde_subdir_insert(struct proc_dir_entry *dir,
77 struct proc_dir_entry *de)
78{
79 struct rb_root *root = &dir->subdir;
80 struct rb_node **new = &root->rb_node, *parent = NULL;
81
82 /* Figure out where to put new node */
83 while (*new) {
84 struct proc_dir_entry *this =
85 container_of(*new, struct proc_dir_entry, subdir_node);
86 int result = proc_match(de->namelen, de->name, this);
87
88 parent = *new;
89 if (result < 0)
90 new = &(*new)->rb_left;
91 else if (result > 0)
92 new = &(*new)->rb_right;
93 else
94 return false;
95 }
96
97 /* Add new node and rebalance tree. */
98 rb_link_node(&de->subdir_node, parent, new);
99 rb_insert_color(&de->subdir_node, root);
100 return true;
37} 101}
38 102
39static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) 103static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
@@ -92,10 +156,7 @@ static int __xlate_proc_name(const char *name, struct proc_dir_entry **ret,
92 break; 156 break;
93 157
94 len = next - cp; 158 len = next - cp;
95 for (de = de->subdir; de ; de = de->next) { 159 de = pde_subdir_find(de, cp, len);
96 if (proc_match(len, cp, de))
97 break;
98 }
99 if (!de) { 160 if (!de) {
100 WARN(1, "name '%s'\n", name); 161 WARN(1, "name '%s'\n", name);
101 return -ENOENT; 162 return -ENOENT;
@@ -183,19 +244,16 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir,
183 struct inode *inode; 244 struct inode *inode;
184 245
185 spin_lock(&proc_subdir_lock); 246 spin_lock(&proc_subdir_lock);
186 for (de = de->subdir; de ; de = de->next) { 247 de = pde_subdir_find(de, dentry->d_name.name, dentry->d_name.len);
187 if (de->namelen != dentry->d_name.len) 248 if (de) {
188 continue; 249 pde_get(de);
189 if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { 250 spin_unlock(&proc_subdir_lock);
190 pde_get(de); 251 inode = proc_get_inode(dir->i_sb, de);
191 spin_unlock(&proc_subdir_lock); 252 if (!inode)
192 inode = proc_get_inode(dir->i_sb, de); 253 return ERR_PTR(-ENOMEM);
193 if (!inode) 254 d_set_d_op(dentry, &simple_dentry_operations);
194 return ERR_PTR(-ENOMEM); 255 d_add(dentry, inode);
195 d_set_d_op(dentry, &simple_dentry_operations); 256 return NULL;
196 d_add(dentry, inode);
197 return NULL;
198 }
199 } 257 }
200 spin_unlock(&proc_subdir_lock); 258 spin_unlock(&proc_subdir_lock);
201 return ERR_PTR(-ENOENT); 259 return ERR_PTR(-ENOENT);
@@ -225,7 +283,7 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *file,
225 return 0; 283 return 0;
226 284
227 spin_lock(&proc_subdir_lock); 285 spin_lock(&proc_subdir_lock);
228 de = de->subdir; 286 de = pde_subdir_first(de);
229 i = ctx->pos - 2; 287 i = ctx->pos - 2;
230 for (;;) { 288 for (;;) {
231 if (!de) { 289 if (!de) {
@@ -234,7 +292,7 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *file,
234 } 292 }
235 if (!i) 293 if (!i)
236 break; 294 break;
237 de = de->next; 295 de = pde_subdir_next(de);
238 i--; 296 i--;
239 } 297 }
240 298
@@ -249,7 +307,7 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *file,
249 } 307 }
250 spin_lock(&proc_subdir_lock); 308 spin_lock(&proc_subdir_lock);
251 ctx->pos++; 309 ctx->pos++;
252 next = de->next; 310 next = pde_subdir_next(de);
253 pde_put(de); 311 pde_put(de);
254 de = next; 312 de = next;
255 } while (de); 313 } while (de);
@@ -286,9 +344,8 @@ static const struct inode_operations proc_dir_inode_operations = {
286 344
287static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) 345static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
288{ 346{
289 struct proc_dir_entry *tmp;
290 int ret; 347 int ret;
291 348
292 ret = proc_alloc_inum(&dp->low_ino); 349 ret = proc_alloc_inum(&dp->low_ino);
293 if (ret) 350 if (ret)
294 return ret; 351 return ret;
@@ -304,21 +361,21 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp
304 dp->proc_iops = &proc_file_inode_operations; 361 dp->proc_iops = &proc_file_inode_operations;
305 } else { 362 } else {
306 WARN_ON(1); 363 WARN_ON(1);
364 proc_free_inum(dp->low_ino);
307 return -EINVAL; 365 return -EINVAL;
308 } 366 }
309 367
310 spin_lock(&proc_subdir_lock); 368 spin_lock(&proc_subdir_lock);
311
312 for (tmp = dir->subdir; tmp; tmp = tmp->next)
313 if (strcmp(tmp->name, dp->name) == 0) {
314 WARN(1, "proc_dir_entry '%s/%s' already registered\n",
315 dir->name, dp->name);
316 break;
317 }
318
319 dp->next = dir->subdir;
320 dp->parent = dir; 369 dp->parent = dir;
321 dir->subdir = dp; 370 if (pde_subdir_insert(dir, dp) == false) {
371 WARN(1, "proc_dir_entry '%s/%s' already registered\n",
372 dir->name, dp->name);
373 spin_unlock(&proc_subdir_lock);
374 if (S_ISDIR(dp->mode))
375 dir->nlink--;
376 proc_free_inum(dp->low_ino);
377 return -EEXIST;
378 }
322 spin_unlock(&proc_subdir_lock); 379 spin_unlock(&proc_subdir_lock);
323 380
324 return 0; 381 return 0;
@@ -354,6 +411,7 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
354 ent->namelen = qstr.len; 411 ent->namelen = qstr.len;
355 ent->mode = mode; 412 ent->mode = mode;
356 ent->nlink = nlink; 413 ent->nlink = nlink;
414 ent->subdir = RB_ROOT;
357 atomic_set(&ent->count, 1); 415 atomic_set(&ent->count, 1);
358 spin_lock_init(&ent->pde_unload_lock); 416 spin_lock_init(&ent->pde_unload_lock);
359 INIT_LIST_HEAD(&ent->pde_openers); 417 INIT_LIST_HEAD(&ent->pde_openers);
@@ -485,7 +543,6 @@ void pde_put(struct proc_dir_entry *pde)
485 */ 543 */
486void remove_proc_entry(const char *name, struct proc_dir_entry *parent) 544void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
487{ 545{
488 struct proc_dir_entry **p;
489 struct proc_dir_entry *de = NULL; 546 struct proc_dir_entry *de = NULL;
490 const char *fn = name; 547 const char *fn = name;
491 unsigned int len; 548 unsigned int len;
@@ -497,14 +554,9 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
497 } 554 }
498 len = strlen(fn); 555 len = strlen(fn);
499 556
500 for (p = &parent->subdir; *p; p=&(*p)->next ) { 557 de = pde_subdir_find(parent, fn, len);
501 if (proc_match(len, fn, *p)) { 558 if (de)
502 de = *p; 559 rb_erase(&de->subdir_node, &parent->subdir);
503 *p = de->next;
504 de->next = NULL;
505 break;
506 }
507 }
508 spin_unlock(&proc_subdir_lock); 560 spin_unlock(&proc_subdir_lock);
509 if (!de) { 561 if (!de) {
510 WARN(1, "name '%s'\n", name); 562 WARN(1, "name '%s'\n", name);
@@ -516,16 +568,15 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
516 if (S_ISDIR(de->mode)) 568 if (S_ISDIR(de->mode))
517 parent->nlink--; 569 parent->nlink--;
518 de->nlink = 0; 570 de->nlink = 0;
519 WARN(de->subdir, "%s: removing non-empty directory " 571 WARN(pde_subdir_first(de),
520 "'%s/%s', leaking at least '%s'\n", __func__, 572 "%s: removing non-empty directory '%s/%s', leaking at least '%s'\n",
521 de->parent->name, de->name, de->subdir->name); 573 __func__, de->parent->name, de->name, pde_subdir_first(de)->name);
522 pde_put(de); 574 pde_put(de);
523} 575}
524EXPORT_SYMBOL(remove_proc_entry); 576EXPORT_SYMBOL(remove_proc_entry);
525 577
526int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) 578int remove_proc_subtree(const char *name, struct proc_dir_entry *parent)
527{ 579{
528 struct proc_dir_entry **p;
529 struct proc_dir_entry *root = NULL, *de, *next; 580 struct proc_dir_entry *root = NULL, *de, *next;
530 const char *fn = name; 581 const char *fn = name;
531 unsigned int len; 582 unsigned int len;
@@ -537,24 +588,18 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent)
537 } 588 }
538 len = strlen(fn); 589 len = strlen(fn);
539 590
540 for (p = &parent->subdir; *p; p=&(*p)->next ) { 591 root = pde_subdir_find(parent, fn, len);
541 if (proc_match(len, fn, *p)) {
542 root = *p;
543 *p = root->next;
544 root->next = NULL;
545 break;
546 }
547 }
548 if (!root) { 592 if (!root) {
549 spin_unlock(&proc_subdir_lock); 593 spin_unlock(&proc_subdir_lock);
550 return -ENOENT; 594 return -ENOENT;
551 } 595 }
596 rb_erase(&root->subdir_node, &parent->subdir);
597
552 de = root; 598 de = root;
553 while (1) { 599 while (1) {
554 next = de->subdir; 600 next = pde_subdir_first(de);
555 if (next) { 601 if (next) {
556 de->subdir = next->next; 602 rb_erase(&next->subdir_node, &de->subdir);
557 next->next = NULL;
558 de = next; 603 de = next;
559 continue; 604 continue;
560 } 605 }