diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2012-01-18 06:15:51 -0500 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2012-01-24 19:40:29 -0500 |
commit | 6a75ce167c53b41f15088d3c2c7e51c89dc8798a (patch) | |
tree | 78c811b59a0ca61ac3b34118a726c0c6554bd68e /fs/proc/proc_sysctl.c | |
parent | 076c3eed2c31773200b082568957fd8852ae93d7 (diff) |
sysctl: Rewrite proc_sys_readdir in terms of first_entry and next_entry
Replace sysctl_head_next with first_entry and next_entry. These new
iterators operate at the level of sysctl table entries and filter
out any sysctl tables that should not be shown.
Utilizing two specialized functions instead of a single function removes
conditionals for handling awkward special cases that only come up
at the beginning of iteration, making the iterators easier to read
and understand.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Diffstat (limited to 'fs/proc/proc_sysctl.c')
-rw-r--r-- | fs/proc/proc_sysctl.c | 98 |
1 files changed, 62 insertions, 36 deletions
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 3b63f298ce28..d9c3ae6afe4c 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -243,31 +243,25 @@ static struct ctl_table *lookup_entry(struct ctl_table_header **phead, | |||
243 | return entry; | 243 | return entry; |
244 | } | 244 | } |
245 | 245 | ||
246 | static struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces, | 246 | static struct ctl_table_header *next_usable_entry(struct ctl_table *dir, |
247 | struct ctl_table_header *prev) | 247 | struct ctl_table_root *root, struct list_head *tmp) |
248 | { | 248 | { |
249 | struct ctl_table_root *root; | 249 | struct nsproxy *namespaces = current->nsproxy; |
250 | struct list_head *header_list; | 250 | struct list_head *header_list; |
251 | struct ctl_table_header *head; | 251 | struct ctl_table_header *head; |
252 | struct list_head *tmp; | ||
253 | 252 | ||
254 | spin_lock(&sysctl_lock); | 253 | goto next; |
255 | if (prev) { | ||
256 | head = prev; | ||
257 | tmp = &prev->ctl_entry; | ||
258 | unuse_table(prev); | ||
259 | goto next; | ||
260 | } | ||
261 | tmp = &root_table_header.ctl_entry; | ||
262 | for (;;) { | 254 | for (;;) { |
263 | head = list_entry(tmp, struct ctl_table_header, ctl_entry); | 255 | head = list_entry(tmp, struct ctl_table_header, ctl_entry); |
256 | root = head->root; | ||
264 | 257 | ||
265 | if (!use_table(head)) | 258 | if (head->attached_to != dir || |
259 | !head->attached_by->procname || | ||
260 | !use_table(head)) | ||
266 | goto next; | 261 | goto next; |
267 | spin_unlock(&sysctl_lock); | 262 | |
268 | return head; | 263 | return head; |
269 | next: | 264 | next: |
270 | root = head->root; | ||
271 | tmp = tmp->next; | 265 | tmp = tmp->next; |
272 | header_list = lookup_header_list(root, namespaces); | 266 | header_list = lookup_header_list(root, namespaces); |
273 | if (tmp != header_list) | 267 | if (tmp != header_list) |
@@ -283,13 +277,53 @@ static struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces, | |||
283 | tmp = header_list->next; | 277 | tmp = header_list->next; |
284 | } | 278 | } |
285 | out: | 279 | out: |
286 | spin_unlock(&sysctl_lock); | ||
287 | return NULL; | 280 | return NULL; |
288 | } | 281 | } |
289 | 282 | ||
290 | static struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev) | 283 | static void first_entry( |
284 | struct ctl_table_header *dir_head, struct ctl_table *dir, | ||
285 | struct ctl_table_header **phead, struct ctl_table **pentry) | ||
291 | { | 286 | { |
292 | return __sysctl_head_next(current->nsproxy, prev); | 287 | struct ctl_table_header *head = dir_head; |
288 | struct ctl_table *entry = dir; | ||
289 | |||
290 | spin_lock(&sysctl_lock); | ||
291 | if (entry->procname) { | ||
292 | use_table(head); | ||
293 | } else { | ||
294 | head = next_usable_entry(dir, &sysctl_table_root, | ||
295 | &sysctl_table_root.default_set.list); | ||
296 | if (head) | ||
297 | entry = head->attached_by; | ||
298 | } | ||
299 | spin_unlock(&sysctl_lock); | ||
300 | *phead = head; | ||
301 | *pentry = entry; | ||
302 | } | ||
303 | |||
304 | static void next_entry(struct ctl_table *dir, | ||
305 | struct ctl_table_header **phead, struct ctl_table **pentry) | ||
306 | { | ||
307 | struct ctl_table_header *head = *phead; | ||
308 | struct ctl_table *entry = *pentry; | ||
309 | |||
310 | entry++; | ||
311 | if (!entry->procname) { | ||
312 | struct ctl_table_root *root = head->root; | ||
313 | struct list_head *tmp = &head->ctl_entry; | ||
314 | if (head->attached_to != dir) { | ||
315 | root = &sysctl_table_root; | ||
316 | tmp = &sysctl_table_root.default_set.list; | ||
317 | } | ||
318 | spin_lock(&sysctl_lock); | ||
319 | unuse_table(head); | ||
320 | head = next_usable_entry(dir, root, tmp); | ||
321 | spin_unlock(&sysctl_lock); | ||
322 | if (head) | ||
323 | entry = head->attached_by; | ||
324 | } | ||
325 | *phead = head; | ||
326 | *pentry = entry; | ||
293 | } | 327 | } |
294 | 328 | ||
295 | void register_sysctl_root(struct ctl_table_root *root) | 329 | void register_sysctl_root(struct ctl_table_root *root) |
@@ -533,20 +567,17 @@ static int scan(struct ctl_table_header *head, ctl_table *table, | |||
533 | unsigned long *pos, struct file *file, | 567 | unsigned long *pos, struct file *file, |
534 | void *dirent, filldir_t filldir) | 568 | void *dirent, filldir_t filldir) |
535 | { | 569 | { |
570 | int res; | ||
536 | 571 | ||
537 | for (; table->procname; table++, (*pos)++) { | 572 | if ((*pos)++ < file->f_pos) |
538 | int res; | 573 | return 0; |
539 | 574 | ||
540 | if (*pos < file->f_pos) | 575 | res = proc_sys_fill_cache(file, dirent, filldir, head, table); |
541 | continue; | ||
542 | 576 | ||
543 | res = proc_sys_fill_cache(file, dirent, filldir, head, table); | 577 | if (res == 0) |
544 | if (res) | 578 | file->f_pos = *pos; |
545 | return res; | ||
546 | 579 | ||
547 | file->f_pos = *pos + 1; | 580 | return res; |
548 | } | ||
549 | return 0; | ||
550 | } | 581 | } |
551 | 582 | ||
552 | static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir) | 583 | static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir) |
@@ -556,6 +587,7 @@ static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
556 | struct ctl_table_header *head = grab_header(inode); | 587 | struct ctl_table_header *head = grab_header(inode); |
557 | struct ctl_table *table = PROC_I(inode)->sysctl_entry; | 588 | struct ctl_table *table = PROC_I(inode)->sysctl_entry; |
558 | struct ctl_table_header *h = NULL; | 589 | struct ctl_table_header *h = NULL; |
590 | struct ctl_table *entry; | ||
559 | unsigned long pos; | 591 | unsigned long pos; |
560 | int ret = -EINVAL; | 592 | int ret = -EINVAL; |
561 | 593 | ||
@@ -585,14 +617,8 @@ static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
585 | } | 617 | } |
586 | pos = 2; | 618 | pos = 2; |
587 | 619 | ||
588 | ret = scan(head, table, &pos, filp, dirent, filldir); | 620 | for (first_entry(head, table, &h, &entry); h; next_entry(table, &h, &entry)) { |
589 | if (ret) | 621 | ret = scan(h, entry, &pos, filp, dirent, filldir); |
590 | goto out; | ||
591 | |||
592 | for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) { | ||
593 | if (h->attached_to != table) | ||
594 | continue; | ||
595 | ret = scan(h, h->attached_by, &pos, filp, dirent, filldir); | ||
596 | if (ret) { | 622 | if (ret) { |
597 | sysctl_head_finish(h); | 623 | sysctl_head_finish(h); |
598 | break; | 624 | break; |