aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/proc_sysctl.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2012-01-18 06:15:51 -0500
committerEric W. Biederman <ebiederm@xmission.com>2012-01-24 19:40:29 -0500
commit6a75ce167c53b41f15088d3c2c7e51c89dc8798a (patch)
tree78c811b59a0ca61ac3b34118a726c0c6554bd68e /fs/proc/proc_sysctl.c
parent076c3eed2c31773200b082568957fd8852ae93d7 (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.c98
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
246static struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces, 246static 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 }
285out: 279out:
286 spin_unlock(&sysctl_lock);
287 return NULL; 280 return NULL;
288} 281}
289 282
290static struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev) 283static 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
304static 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
295void register_sysctl_root(struct ctl_table_root *root) 329void 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
552static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir) 583static 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;