[PATCH] sysctl: factor out sysctl_head_next from do_sysctl
The current logic to walk through the list of sysctl table headers is slightly painful and implement in a way it cannot be used by code outside sysctl.c I am in the process of implementing a version of the sysctl proc support that instead of using the proc generic non-caching monster, just uses the existing sysctl data structure as backing store for building the dcache entries and for doing directory reads. To use the existing data structures however I need a way to get at them. [akpm@osdl.org: warning fix] Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
0b4d414714
commit
805b5d5e06
|
@ -924,6 +924,10 @@ enum
|
|||
#ifdef __KERNEL__
|
||||
#include <linux/list.h>
|
||||
|
||||
/* For the /proc/sys support */
|
||||
extern struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev);
|
||||
extern void sysctl_head_finish(struct ctl_table_header *prev);
|
||||
|
||||
extern void sysctl_init(void);
|
||||
|
||||
typedef struct ctl_table ctl_table;
|
||||
|
|
|
@ -1070,6 +1070,42 @@ static void start_unregistering(struct ctl_table_header *p)
|
|||
list_del_init(&p->ctl_entry);
|
||||
}
|
||||
|
||||
void sysctl_head_finish(struct ctl_table_header *head)
|
||||
{
|
||||
if (!head)
|
||||
return;
|
||||
spin_lock(&sysctl_lock);
|
||||
unuse_table(head);
|
||||
spin_unlock(&sysctl_lock);
|
||||
}
|
||||
|
||||
struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev)
|
||||
{
|
||||
struct ctl_table_header *head;
|
||||
struct list_head *tmp;
|
||||
spin_lock(&sysctl_lock);
|
||||
if (prev) {
|
||||
tmp = &prev->ctl_entry;
|
||||
unuse_table(prev);
|
||||
goto next;
|
||||
}
|
||||
tmp = &root_table_header.ctl_entry;
|
||||
for (;;) {
|
||||
head = list_entry(tmp, struct ctl_table_header, ctl_entry);
|
||||
|
||||
if (!use_table(head))
|
||||
goto next;
|
||||
spin_unlock(&sysctl_lock);
|
||||
return head;
|
||||
next:
|
||||
tmp = tmp->next;
|
||||
if (tmp == &root_table_header.ctl_entry)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&sysctl_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void __init sysctl_init(void)
|
||||
{
|
||||
#ifdef CONFIG_PROC_SYSCTL
|
||||
|
@ -1081,7 +1117,7 @@ void __init sysctl_init(void)
|
|||
int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
|
||||
void __user *newval, size_t newlen)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct ctl_table_header *head;
|
||||
int error = -ENOTDIR;
|
||||
|
||||
if (nlen <= 0 || nlen >= CTL_MAXNAME)
|
||||
|
@ -1091,26 +1127,16 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol
|
|||
if (!oldlenp || get_user(old_len, oldlenp))
|
||||
return -EFAULT;
|
||||
}
|
||||
spin_lock(&sysctl_lock);
|
||||
tmp = &root_table_header.ctl_entry;
|
||||
do {
|
||||
struct ctl_table_header *head =
|
||||
list_entry(tmp, struct ctl_table_header, ctl_entry);
|
||||
|
||||
if (!use_table(head))
|
||||
continue;
|
||||
|
||||
spin_unlock(&sysctl_lock);
|
||||
|
||||
for (head = sysctl_head_next(NULL); head;
|
||||
head = sysctl_head_next(head)) {
|
||||
error = parse_table(name, nlen, oldval, oldlenp,
|
||||
newval, newlen, head->ctl_table);
|
||||
|
||||
spin_lock(&sysctl_lock);
|
||||
unuse_table(head);
|
||||
if (error != -ENOTDIR)
|
||||
if (error != -ENOTDIR) {
|
||||
sysctl_head_finish(head);
|
||||
break;
|
||||
} while ((tmp = tmp->next) != &root_table_header.ctl_entry);
|
||||
spin_unlock(&sysctl_lock);
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue