aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavidlohr Bueso <dave@stgolabs.net>2017-09-08 19:15:15 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-09-08 21:26:49 -0400
commit410bd5ecb276593e7ec1552014083215d4a43c3a (patch)
tree3d507f3ba123be043d8a4e7582c8a48a0f71cb07
parentf2686bb48618718c7141f117e2d607594e959bfc (diff)
procfs: use faster rb_first_cached()
... such that we can avoid the tree walks to get the node with the smallest key. Semantically the same, as the previously used rb_first(), but O(1). The main overhead is the extra footprint for the cached rb_node pointer, which should not matter for procfs. Link: http://lkml.kernel.org/r/20170719014603.19029-14-dave@stgolabs.net Signed-off-by: Davidlohr Bueso <dbueso@suse.de> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/proc/generic.c26
-rw-r--r--fs/proc/internal.h2
-rw-r--r--fs/proc/proc_net.c2
-rw-r--r--fs/proc/root.c2
4 files changed, 17 insertions, 15 deletions
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 85566abe6f83..793a67574668 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -40,8 +40,8 @@ static int proc_match(unsigned int len, const char *name, struct proc_dir_entry
40 40
41static struct proc_dir_entry *pde_subdir_first(struct proc_dir_entry *dir) 41static struct proc_dir_entry *pde_subdir_first(struct proc_dir_entry *dir)
42{ 42{
43 return rb_entry_safe(rb_first(&dir->subdir), struct proc_dir_entry, 43 return rb_entry_safe(rb_first_cached(&dir->subdir),
44 subdir_node); 44 struct proc_dir_entry, subdir_node);
45} 45}
46 46
47static struct proc_dir_entry *pde_subdir_next(struct proc_dir_entry *dir) 47static struct proc_dir_entry *pde_subdir_next(struct proc_dir_entry *dir)
@@ -54,7 +54,7 @@ static struct proc_dir_entry *pde_subdir_find(struct proc_dir_entry *dir,
54 const char *name, 54 const char *name,
55 unsigned int len) 55 unsigned int len)
56{ 56{
57 struct rb_node *node = dir->subdir.rb_node; 57 struct rb_node *node = dir->subdir.rb_root.rb_node;
58 58
59 while (node) { 59 while (node) {
60 struct proc_dir_entry *de = rb_entry(node, 60 struct proc_dir_entry *de = rb_entry(node,
@@ -75,8 +75,9 @@ static struct proc_dir_entry *pde_subdir_find(struct proc_dir_entry *dir,
75static bool pde_subdir_insert(struct proc_dir_entry *dir, 75static bool pde_subdir_insert(struct proc_dir_entry *dir,
76 struct proc_dir_entry *de) 76 struct proc_dir_entry *de)
77{ 77{
78 struct rb_root *root = &dir->subdir; 78 struct rb_root_cached *root = &dir->subdir;
79 struct rb_node **new = &root->rb_node, *parent = NULL; 79 struct rb_node **new = &root->rb_root.rb_node, *parent = NULL;
80 bool leftmost = true;
80 81
81 /* Figure out where to put new node */ 82 /* Figure out where to put new node */
82 while (*new) { 83 while (*new) {
@@ -88,15 +89,16 @@ static bool pde_subdir_insert(struct proc_dir_entry *dir,
88 parent = *new; 89 parent = *new;
89 if (result < 0) 90 if (result < 0)
90 new = &(*new)->rb_left; 91 new = &(*new)->rb_left;
91 else if (result > 0) 92 else if (result > 0) {
92 new = &(*new)->rb_right; 93 new = &(*new)->rb_right;
93 else 94 leftmost = false;
95 } else
94 return false; 96 return false;
95 } 97 }
96 98
97 /* Add new node and rebalance tree. */ 99 /* Add new node and rebalance tree. */
98 rb_link_node(&de->subdir_node, parent, new); 100 rb_link_node(&de->subdir_node, parent, new);
99 rb_insert_color(&de->subdir_node, root); 101 rb_insert_color_cached(&de->subdir_node, root, leftmost);
100 return true; 102 return true;
101} 103}
102 104
@@ -369,7 +371,7 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
369 ent->namelen = qstr.len; 371 ent->namelen = qstr.len;
370 ent->mode = mode; 372 ent->mode = mode;
371 ent->nlink = nlink; 373 ent->nlink = nlink;
372 ent->subdir = RB_ROOT; 374 ent->subdir = RB_ROOT_CACHED;
373 atomic_set(&ent->count, 1); 375 atomic_set(&ent->count, 1);
374 spin_lock_init(&ent->pde_unload_lock); 376 spin_lock_init(&ent->pde_unload_lock);
375 INIT_LIST_HEAD(&ent->pde_openers); 377 INIT_LIST_HEAD(&ent->pde_openers);
@@ -553,7 +555,7 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
553 555
554 de = pde_subdir_find(parent, fn, len); 556 de = pde_subdir_find(parent, fn, len);
555 if (de) 557 if (de)
556 rb_erase(&de->subdir_node, &parent->subdir); 558 rb_erase_cached(&de->subdir_node, &parent->subdir);
557 write_unlock(&proc_subdir_lock); 559 write_unlock(&proc_subdir_lock);
558 if (!de) { 560 if (!de) {
559 WARN(1, "name '%s'\n", name); 561 WARN(1, "name '%s'\n", name);
@@ -590,13 +592,13 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent)
590 write_unlock(&proc_subdir_lock); 592 write_unlock(&proc_subdir_lock);
591 return -ENOENT; 593 return -ENOENT;
592 } 594 }
593 rb_erase(&root->subdir_node, &parent->subdir); 595 rb_erase_cached(&root->subdir_node, &parent->subdir);
594 596
595 de = root; 597 de = root;
596 while (1) { 598 while (1) {
597 next = pde_subdir_first(de); 599 next = pde_subdir_first(de);
598 if (next) { 600 if (next) {
599 rb_erase(&next->subdir_node, &de->subdir); 601 rb_erase_cached(&next->subdir_node, &de->subdir);
600 de = next; 602 de = next;
601 continue; 603 continue;
602 } 604 }
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 2cbfcd32e884..a34195e92b20 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -40,7 +40,7 @@ struct proc_dir_entry {
40 const struct inode_operations *proc_iops; 40 const struct inode_operations *proc_iops;
41 const struct file_operations *proc_fops; 41 const struct file_operations *proc_fops;
42 struct proc_dir_entry *parent; 42 struct proc_dir_entry *parent;
43 struct rb_root subdir; 43 struct rb_root_cached subdir;
44 struct rb_node subdir_node; 44 struct rb_node subdir_node;
45 void *data; 45 void *data;
46 atomic_t count; /* use count */ 46 atomic_t count; /* use count */
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c
index d72fc40241d9..a2bf369c923d 100644
--- a/fs/proc/proc_net.c
+++ b/fs/proc/proc_net.c
@@ -196,7 +196,7 @@ static __net_init int proc_net_ns_init(struct net *net)
196 if (!netd) 196 if (!netd)
197 goto out; 197 goto out;
198 198
199 netd->subdir = RB_ROOT; 199 netd->subdir = RB_ROOT_CACHED;
200 netd->data = net; 200 netd->data = net;
201 netd->nlink = 2; 201 netd->nlink = 2;
202 netd->namelen = 3; 202 netd->namelen = 3;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index deecb397daa3..926fb27f4ca2 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -210,7 +210,7 @@ struct proc_dir_entry proc_root = {
210 .proc_iops = &proc_root_inode_operations, 210 .proc_iops = &proc_root_inode_operations,
211 .proc_fops = &proc_root_operations, 211 .proc_fops = &proc_root_operations,
212 .parent = &proc_root, 212 .parent = &proc_root,
213 .subdir = RB_ROOT, 213 .subdir = RB_ROOT_CACHED,
214 .name = "/proc", 214 .name = "/proc",
215}; 215};
216 216