|
@@ -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;
|
|
|
}
|
|
|
|