aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2012-01-10 00:42:02 -0500
committerEric W. Biederman <ebiederm@xmission.com>2012-01-24 19:40:29 -0500
commit076c3eed2c31773200b082568957fd8852ae93d7 (patch)
tree76ddb1483d7a4a04d7910810e8f1dda7be43bf5a /fs
parenta194558e8698621a9ce7f2c6a720123e644af131 (diff)
sysctl: Rewrite proc_sys_lookup introducing find_entry and lookup_entry.
Replace the helpers that proc_sys_lookup uses with helpers that work in terms of an entire sysctl directory. This is worse for sysctl_lock hold times but it is much better for code clarity and the code cleanups to come. find_in_table is no longer needed so it is removed. find_entry a general helper to find entries in a directory is added. lookup_entry is a simple wrapper around find_entry that takes the sysctl_lock increases the use count if an entry is found and drops the sysctl_lock. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/proc/proc_sysctl.c102
1 files changed, 76 insertions, 26 deletions
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 88d1b06cc5c0..3b63f298ce28 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -49,6 +49,55 @@ static struct ctl_table_root sysctl_table_root = {
49 49
50static DEFINE_SPINLOCK(sysctl_lock); 50static DEFINE_SPINLOCK(sysctl_lock);
51 51
52static int namecmp(const char *name1, int len1, const char *name2, int len2)
53{
54 int minlen;
55 int cmp;
56
57 minlen = len1;
58 if (minlen > len2)
59 minlen = len2;
60
61 cmp = memcmp(name1, name2, minlen);
62 if (cmp == 0)
63 cmp = len1 - len2;
64 return cmp;
65}
66
67static struct ctl_table *find_entry(struct ctl_table_header **phead,
68 struct ctl_table_set *set,
69 struct ctl_table_header *dir_head, struct ctl_table *dir,
70 const char *name, int namelen)
71{
72 struct ctl_table_header *head;
73 struct ctl_table *entry;
74
75 if (dir_head->set == set) {
76 for (entry = dir; entry->procname; entry++) {
77 const char *procname = entry->procname;
78 if (namecmp(procname, strlen(procname), name, namelen) == 0) {
79 *phead = dir_head;
80 return entry;
81 }
82 }
83 }
84
85 list_for_each_entry(head, &set->list, ctl_entry) {
86 if (head->unregistering)
87 continue;
88 if (head->attached_to != dir)
89 continue;
90 for (entry = head->attached_by; entry->procname; entry++) {
91 const char *procname = entry->procname;
92 if (namecmp(procname, strlen(procname), name, namelen) == 0) {
93 *phead = head;
94 return entry;
95 }
96 }
97 }
98 return NULL;
99}
100
52static void init_header(struct ctl_table_header *head, 101static void init_header(struct ctl_table_header *head,
53 struct ctl_table_root *root, struct ctl_table_set *set, 102 struct ctl_table_root *root, struct ctl_table_set *set,
54 struct ctl_table *table) 103 struct ctl_table *table)
@@ -168,6 +217,32 @@ lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces)
168 return &set->list; 217 return &set->list;
169} 218}
170 219
220static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
221 struct ctl_table_header *dir_head,
222 struct ctl_table *dir,
223 const char *name, int namelen)
224{
225 struct ctl_table_header *head;
226 struct ctl_table *entry;
227 struct ctl_table_root *root;
228 struct ctl_table_set *set;
229
230 spin_lock(&sysctl_lock);
231 root = &sysctl_table_root;
232 do {
233 set = lookup_header_set(root, current->nsproxy);
234 entry = find_entry(&head, set, dir_head, dir, name, namelen);
235 if (entry && use_table(head))
236 *phead = head;
237 else
238 entry = NULL;
239 root = list_entry(root->root_list.next,
240 struct ctl_table_root, root_list);
241 } while (!entry && root != &sysctl_table_root);
242 spin_unlock(&sysctl_lock);
243 return entry;
244}
245
171static struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces, 246static struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
172 struct ctl_table_header *prev) 247 struct ctl_table_header *prev)
173{ 248{
@@ -284,21 +359,6 @@ out:
284 return inode; 359 return inode;
285} 360}
286 361
287static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name)
288{
289 for ( ; p->procname; p++) {
290 if (strlen(p->procname) != name->len)
291 continue;
292
293 if (memcmp(p->procname, name->name, name->len) != 0)
294 continue;
295
296 /* I have a match */
297 return p;
298 }
299 return NULL;
300}
301
302static struct ctl_table_header *grab_header(struct inode *inode) 362static struct ctl_table_header *grab_header(struct inode *inode)
303{ 363{
304 struct ctl_table_header *head = PROC_I(inode)->sysctl; 364 struct ctl_table_header *head = PROC_I(inode)->sysctl;
@@ -328,17 +388,7 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
328 388
329 table = table ? table->child : &head->ctl_table[1]; 389 table = table ? table->child : &head->ctl_table[1];
330 390
331 p = find_in_table(table, name); 391 p = lookup_entry(&h, head, table, name->name, name->len);
332 if (!p) {
333 for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) {
334 if (h->attached_to != table)
335 continue;
336 p = find_in_table(h->attached_by, name);
337 if (p)
338 break;
339 }
340 }
341
342 if (!p) 392 if (!p)
343 goto out; 393 goto out;
344 394