summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Dobriyan <adobriyan@gmail.com>2018-04-10 19:32:20 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-11 13:28:34 -0400
commit4f1134370a29a5f2d0f4b4be4c5e2fddd38f0f9d (patch)
tree0fcae1f568cf1c2870f615e214f3e92a77afcd30
parent05c3f29283af9e3da0ab7414f666cb37f530950a (diff)
proc: use slower rb_first()
In a typical for /proc "open+read+close" usecase, dentry is looked up successfully on open only to be killed in dput() on close. In fact dentries which aren't /proc/*/... and /proc/sys/* were almost NEVER CACHED. Simple printk in proc_lookup_de() shows that. Now that ->delete hook intelligently picks which dentries should live in dcache and which should not, rbtree caching is not necessary as dcache does it job, at last! As a side effect, struct proc_dir_entry shrinks by one pointer which can go into inline name. Link: http://lkml.kernel.org/r/20180314231032.GA15854@avx2 Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Acked-by: Davidlohr Bueso <dbueso@suse.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> 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>
-rw-r--r--fs/proc/generic.c26
-rw-r--r--fs/proc/internal.h6
-rw-r--r--fs/proc/proc_net.c2
-rw-r--r--fs/proc/root.c2
4 files changed, 17 insertions, 19 deletions
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index fc0333fd5676..04c4804cbdef 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -52,8 +52,8 @@ static int proc_match(const char *name, struct proc_dir_entry *de, unsigned int
52 52
53static struct proc_dir_entry *pde_subdir_first(struct proc_dir_entry *dir) 53static struct proc_dir_entry *pde_subdir_first(struct proc_dir_entry *dir)
54{ 54{
55 return rb_entry_safe(rb_first_cached(&dir->subdir), 55 return rb_entry_safe(rb_first(&dir->subdir), struct proc_dir_entry,
56 struct proc_dir_entry, subdir_node); 56 subdir_node);
57} 57}
58 58
59static struct proc_dir_entry *pde_subdir_next(struct proc_dir_entry *dir) 59static struct proc_dir_entry *pde_subdir_next(struct proc_dir_entry *dir)
@@ -66,7 +66,7 @@ static struct proc_dir_entry *pde_subdir_find(struct proc_dir_entry *dir,
66 const char *name, 66 const char *name,
67 unsigned int len) 67 unsigned int len)
68{ 68{
69 struct rb_node *node = dir->subdir.rb_root.rb_node; 69 struct rb_node *node = dir->subdir.rb_node;
70 70
71 while (node) { 71 while (node) {
72 struct proc_dir_entry *de = rb_entry(node, 72 struct proc_dir_entry *de = rb_entry(node,
@@ -87,9 +87,8 @@ static struct proc_dir_entry *pde_subdir_find(struct proc_dir_entry *dir,
87static bool pde_subdir_insert(struct proc_dir_entry *dir, 87static bool pde_subdir_insert(struct proc_dir_entry *dir,
88 struct proc_dir_entry *de) 88 struct proc_dir_entry *de)
89{ 89{
90 struct rb_root_cached *root = &dir->subdir; 90 struct rb_root *root = &dir->subdir;
91 struct rb_node **new = &root->rb_root.rb_node, *parent = NULL; 91 struct rb_node **new = &root->rb_node, *parent = NULL;
92 bool leftmost = true;
93 92
94 /* Figure out where to put new node */ 93 /* Figure out where to put new node */
95 while (*new) { 94 while (*new) {
@@ -101,16 +100,15 @@ static bool pde_subdir_insert(struct proc_dir_entry *dir,
101 parent = *new; 100 parent = *new;
102 if (result < 0) 101 if (result < 0)
103 new = &(*new)->rb_left; 102 new = &(*new)->rb_left;
104 else if (result > 0) { 103 else if (result > 0)
105 new = &(*new)->rb_right; 104 new = &(*new)->rb_right;
106 leftmost = false; 105 else
107 } else
108 return false; 106 return false;
109 } 107 }
110 108
111 /* Add new node and rebalance tree. */ 109 /* Add new node and rebalance tree. */
112 rb_link_node(&de->subdir_node, parent, new); 110 rb_link_node(&de->subdir_node, parent, new);
113 rb_insert_color_cached(&de->subdir_node, root, leftmost); 111 rb_insert_color(&de->subdir_node, root);
114 return true; 112 return true;
115} 113}
116 114
@@ -401,7 +399,7 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
401 ent->namelen = qstr.len; 399 ent->namelen = qstr.len;
402 ent->mode = mode; 400 ent->mode = mode;
403 ent->nlink = nlink; 401 ent->nlink = nlink;
404 ent->subdir = RB_ROOT_CACHED; 402 ent->subdir = RB_ROOT;
405 refcount_set(&ent->refcnt, 1); 403 refcount_set(&ent->refcnt, 1);
406 spin_lock_init(&ent->pde_unload_lock); 404 spin_lock_init(&ent->pde_unload_lock);
407 INIT_LIST_HEAD(&ent->pde_openers); 405 INIT_LIST_HEAD(&ent->pde_openers);
@@ -577,7 +575,7 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
577 575
578 de = pde_subdir_find(parent, fn, len); 576 de = pde_subdir_find(parent, fn, len);
579 if (de) 577 if (de)
580 rb_erase_cached(&de->subdir_node, &parent->subdir); 578 rb_erase(&de->subdir_node, &parent->subdir);
581 write_unlock(&proc_subdir_lock); 579 write_unlock(&proc_subdir_lock);
582 if (!de) { 580 if (!de) {
583 WARN(1, "name '%s'\n", name); 581 WARN(1, "name '%s'\n", name);
@@ -614,13 +612,13 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent)
614 write_unlock(&proc_subdir_lock); 612 write_unlock(&proc_subdir_lock);
615 return -ENOENT; 613 return -ENOENT;
616 } 614 }
617 rb_erase_cached(&root->subdir_node, &parent->subdir); 615 rb_erase(&root->subdir_node, &parent->subdir);
618 616
619 de = root; 617 de = root;
620 while (1) { 618 while (1) {
621 next = pde_subdir_first(de); 619 next = pde_subdir_first(de);
622 if (next) { 620 if (next) {
623 rb_erase_cached(&next->subdir_node, &de->subdir); 621 rb_erase(&next->subdir_node, &de->subdir);
624 de = next; 622 de = next;
625 continue; 623 continue;
626 } 624 }
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index b7024f174778..0f1692e63cb6 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -51,15 +51,15 @@ struct proc_dir_entry {
51 kgid_t gid; 51 kgid_t gid;
52 loff_t size; 52 loff_t size;
53 struct proc_dir_entry *parent; 53 struct proc_dir_entry *parent;
54 struct rb_root_cached subdir; 54 struct rb_root subdir;
55 struct rb_node subdir_node; 55 struct rb_node subdir_node;
56 char *name; 56 char *name;
57 umode_t mode; 57 umode_t mode;
58 u8 namelen; 58 u8 namelen;
59#ifdef CONFIG_64BIT 59#ifdef CONFIG_64BIT
60#define SIZEOF_PDE_INLINE_NAME (192-147) 60#define SIZEOF_PDE_INLINE_NAME (192-139)
61#else 61#else
62#define SIZEOF_PDE_INLINE_NAME (128-91) 62#define SIZEOF_PDE_INLINE_NAME (128-87)
63#endif 63#endif
64 char inline_name[SIZEOF_PDE_INLINE_NAME]; 64 char inline_name[SIZEOF_PDE_INLINE_NAME];
65} __randomize_layout; 65} __randomize_layout;
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c
index e5fe3d400737..1763f370489d 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_CACHED; 199 netd->subdir = RB_ROOT;
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 76c996457ff9..61b7340b357a 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -203,7 +203,7 @@ struct proc_dir_entry proc_root = {
203 .proc_iops = &proc_root_inode_operations, 203 .proc_iops = &proc_root_inode_operations,
204 .proc_fops = &proc_root_operations, 204 .proc_fops = &proc_root_operations,
205 .parent = &proc_root, 205 .parent = &proc_root,
206 .subdir = RB_ROOT_CACHED, 206 .subdir = RB_ROOT,
207 .name = proc_root.inline_name, 207 .name = proc_root.inline_name,
208 .inline_name = "/proc", 208 .inline_name = "/proc",
209}; 209};