Skip to content

Commit 6a75ce1

Browse files
committed
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>
1 parent 076c3ee commit 6a75ce1

File tree

1 file changed

+62
-36
lines changed

1 file changed

+62
-36
lines changed

fs/proc/proc_sysctl.c

Lines changed: 62 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -243,31 +243,25 @@ static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
243243
return entry;
244244
}
245245

246-
static struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
247-
struct ctl_table_header *prev)
246+
static struct ctl_table_header *next_usable_entry(struct ctl_table *dir,
247+
struct ctl_table_root *root, struct list_head *tmp)
248248
{
249-
struct ctl_table_root *root;
249+
struct nsproxy *namespaces = current->nsproxy;
250250
struct list_head *header_list;
251251
struct ctl_table_header *head;
252-
struct list_head *tmp;
253252

254-
spin_lock(&sysctl_lock);
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;
253+
goto next;
262254
for (;;) {
263255
head = list_entry(tmp, struct ctl_table_header, ctl_entry);
256+
root = head->root;
264257

265-
if (!use_table(head))
258+
if (head->attached_to != dir ||
259+
!head->attached_by->procname ||
260+
!use_table(head))
266261
goto next;
267-
spin_unlock(&sysctl_lock);
262+
268263
return head;
269264
next:
270-
root = head->root;
271265
tmp = tmp->next;
272266
header_list = lookup_header_list(root, namespaces);
273267
if (tmp != header_list)
@@ -283,13 +277,53 @@ static struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
283277
tmp = header_list->next;
284278
}
285279
out:
286-
spin_unlock(&sysctl_lock);
287280
return NULL;
288281
}
289282

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)
291286
{
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;
293327
}
294328

295329
void register_sysctl_root(struct ctl_table_root *root)
@@ -533,20 +567,17 @@ static int scan(struct ctl_table_header *head, ctl_table *table,
533567
unsigned long *pos, struct file *file,
534568
void *dirent, filldir_t filldir)
535569
{
570+
int res;
536571

537-
for (; table->procname; table++, (*pos)++) {
538-
int res;
572+
if ((*pos)++ < file->f_pos)
573+
return 0;
539574

540-
if (*pos < file->f_pos)
541-
continue;
575+
res = proc_sys_fill_cache(file, dirent, filldir, head, table);
542576

543-
res = proc_sys_fill_cache(file, dirent, filldir, head, table);
544-
if (res)
545-
return res;
577+
if (res == 0)
578+
file->f_pos = *pos;
546579

547-
file->f_pos = *pos + 1;
548-
}
549-
return 0;
580+
return res;
550581
}
551582

552583
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)
556587
struct ctl_table_header *head = grab_header(inode);
557588
struct ctl_table *table = PROC_I(inode)->sysctl_entry;
558589
struct ctl_table_header *h = NULL;
590+
struct ctl_table *entry;
559591
unsigned long pos;
560592
int ret = -EINVAL;
561593

@@ -585,14 +617,8 @@ static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
585617
}
586618
pos = 2;
587619

588-
ret = scan(head, table, &pos, filp, dirent, filldir);
589-
if (ret)
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);
620+
for (first_entry(head, table, &h, &entry); h; next_entry(table, &h, &entry)) {
621+
ret = scan(h, entry, &pos, filp, dirent, filldir);
596622
if (ret) {
597623
sysctl_head_finish(h);
598624
break;

0 commit comments

Comments
 (0)