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>
This commit is contained in:
parent
076c3eed2c
commit
6a75ce167c
|
@ -243,31 +243,25 @@ static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
|
static struct ctl_table_header *next_usable_entry(struct ctl_table *dir,
|
||||||
struct ctl_table_header *prev)
|
struct ctl_table_root *root, struct list_head *tmp)
|
||||||
{
|
{
|
||||||
struct ctl_table_root *root;
|
struct nsproxy *namespaces = current->nsproxy;
|
||||||
struct list_head *header_list;
|
struct list_head *header_list;
|
||||||
struct ctl_table_header *head;
|
struct ctl_table_header *head;
|
||||||
struct list_head *tmp;
|
|
||||||
|
|
||||||
spin_lock(&sysctl_lock);
|
goto next;
|
||||||
if (prev) {
|
|
||||||
head = prev;
|
|
||||||
tmp = &prev->ctl_entry;
|
|
||||||
unuse_table(prev);
|
|
||||||
goto next;
|
|
||||||
}
|
|
||||||
tmp = &root_table_header.ctl_entry;
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
head = list_entry(tmp, struct ctl_table_header, ctl_entry);
|
head = list_entry(tmp, struct ctl_table_header, ctl_entry);
|
||||||
|
root = head->root;
|
||||||
|
|
||||||
if (!use_table(head))
|
if (head->attached_to != dir ||
|
||||||
|
!head->attached_by->procname ||
|
||||||
|
!use_table(head))
|
||||||
goto next;
|
goto next;
|
||||||
spin_unlock(&sysctl_lock);
|
|
||||||
return head;
|
return head;
|
||||||
next:
|
next:
|
||||||
root = head->root;
|
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
header_list = lookup_header_list(root, namespaces);
|
header_list = lookup_header_list(root, namespaces);
|
||||||
if (tmp != header_list)
|
if (tmp != header_list)
|
||||||
|
@ -283,13 +277,53 @@ static struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
|
||||||
tmp = header_list->next;
|
tmp = header_list->next;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
spin_unlock(&sysctl_lock);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev)
|
static void first_entry(
|
||||||
|
struct ctl_table_header *dir_head, struct ctl_table *dir,
|
||||||
|
struct ctl_table_header **phead, struct ctl_table **pentry)
|
||||||
{
|
{
|
||||||
return __sysctl_head_next(current->nsproxy, prev);
|
struct ctl_table_header *head = dir_head;
|
||||||
|
struct ctl_table *entry = dir;
|
||||||
|
|
||||||
|
spin_lock(&sysctl_lock);
|
||||||
|
if (entry->procname) {
|
||||||
|
use_table(head);
|
||||||
|
} else {
|
||||||
|
head = next_usable_entry(dir, &sysctl_table_root,
|
||||||
|
&sysctl_table_root.default_set.list);
|
||||||
|
if (head)
|
||||||
|
entry = head->attached_by;
|
||||||
|
}
|
||||||
|
spin_unlock(&sysctl_lock);
|
||||||
|
*phead = head;
|
||||||
|
*pentry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void next_entry(struct ctl_table *dir,
|
||||||
|
struct ctl_table_header **phead, struct ctl_table **pentry)
|
||||||
|
{
|
||||||
|
struct ctl_table_header *head = *phead;
|
||||||
|
struct ctl_table *entry = *pentry;
|
||||||
|
|
||||||
|
entry++;
|
||||||
|
if (!entry->procname) {
|
||||||
|
struct ctl_table_root *root = head->root;
|
||||||
|
struct list_head *tmp = &head->ctl_entry;
|
||||||
|
if (head->attached_to != dir) {
|
||||||
|
root = &sysctl_table_root;
|
||||||
|
tmp = &sysctl_table_root.default_set.list;
|
||||||
|
}
|
||||||
|
spin_lock(&sysctl_lock);
|
||||||
|
unuse_table(head);
|
||||||
|
head = next_usable_entry(dir, root, tmp);
|
||||||
|
spin_unlock(&sysctl_lock);
|
||||||
|
if (head)
|
||||||
|
entry = head->attached_by;
|
||||||
|
}
|
||||||
|
*phead = head;
|
||||||
|
*pentry = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void register_sysctl_root(struct ctl_table_root *root)
|
void register_sysctl_root(struct ctl_table_root *root)
|
||||||
|
@ -533,20 +567,17 @@ static int scan(struct ctl_table_header *head, ctl_table *table,
|
||||||
unsigned long *pos, struct file *file,
|
unsigned long *pos, struct file *file,
|
||||||
void *dirent, filldir_t filldir)
|
void *dirent, filldir_t filldir)
|
||||||
{
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
for (; table->procname; table++, (*pos)++) {
|
if ((*pos)++ < file->f_pos)
|
||||||
int res;
|
return 0;
|
||||||
|
|
||||||
if (*pos < file->f_pos)
|
res = proc_sys_fill_cache(file, dirent, filldir, head, table);
|
||||||
continue;
|
|
||||||
|
|
||||||
res = proc_sys_fill_cache(file, dirent, filldir, head, table);
|
if (res == 0)
|
||||||
if (res)
|
file->f_pos = *pos;
|
||||||
return res;
|
|
||||||
|
|
||||||
file->f_pos = *pos + 1;
|
return res;
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
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)
|
||||||
struct ctl_table_header *head = grab_header(inode);
|
struct ctl_table_header *head = grab_header(inode);
|
||||||
struct ctl_table *table = PROC_I(inode)->sysctl_entry;
|
struct ctl_table *table = PROC_I(inode)->sysctl_entry;
|
||||||
struct ctl_table_header *h = NULL;
|
struct ctl_table_header *h = NULL;
|
||||||
|
struct ctl_table *entry;
|
||||||
unsigned long pos;
|
unsigned long pos;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
@ -585,14 +617,8 @@ static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
}
|
}
|
||||||
pos = 2;
|
pos = 2;
|
||||||
|
|
||||||
ret = scan(head, table, &pos, filp, dirent, filldir);
|
for (first_entry(head, table, &h, &entry); h; next_entry(table, &h, &entry)) {
|
||||||
if (ret)
|
ret = scan(h, entry, &pos, filp, dirent, filldir);
|
||||||
goto out;
|
|
||||||
|
|
||||||
for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) {
|
|
||||||
if (h->attached_to != table)
|
|
||||||
continue;
|
|
||||||
ret = scan(h, h->attached_by, &pos, filp, dirent, filldir);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
sysctl_head_finish(h);
|
sysctl_head_finish(h);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue