diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2012-01-10 00:42:02 -0500 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2012-01-24 19:40:29 -0500 |
commit | 076c3eed2c31773200b082568957fd8852ae93d7 (patch) | |
tree | 76ddb1483d7a4a04d7910810e8f1dda7be43bf5a /fs | |
parent | a194558e8698621a9ce7f2c6a720123e644af131 (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.c | 102 |
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 | ||
50 | static DEFINE_SPINLOCK(sysctl_lock); | 50 | static DEFINE_SPINLOCK(sysctl_lock); |
51 | 51 | ||
52 | static 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 | |||
67 | static 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 | |||
52 | static void init_header(struct ctl_table_header *head, | 101 | static 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 | ||
220 | static 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 | |||
171 | static struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces, | 246 | static 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 | ||
287 | static 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 | |||
302 | static struct ctl_table_header *grab_header(struct inode *inode) | 362 | static 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 | ||