aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sysctl.h4
-rw-r--r--kernel/sysctl.c60
2 files changed, 47 insertions, 17 deletions
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 396b8d984c5d..72ba58b362d8 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -924,6 +924,10 @@ enum
924#ifdef __KERNEL__ 924#ifdef __KERNEL__
925#include <linux/list.h> 925#include <linux/list.h>
926 926
927/* For the /proc/sys support */
928extern struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev);
929extern void sysctl_head_finish(struct ctl_table_header *prev);
930
927extern void sysctl_init(void); 931extern void sysctl_init(void);
928 932
929typedef struct ctl_table ctl_table; 933typedef struct ctl_table ctl_table;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 6ccb6cc19e28..c3e2ac9cb5fb 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1070,6 +1070,42 @@ static void start_unregistering(struct ctl_table_header *p)
1070 list_del_init(&p->ctl_entry); 1070 list_del_init(&p->ctl_entry);
1071} 1071}
1072 1072
1073void sysctl_head_finish(struct ctl_table_header *head)
1074{
1075 if (!head)
1076 return;
1077 spin_lock(&sysctl_lock);
1078 unuse_table(head);
1079 spin_unlock(&sysctl_lock);
1080}
1081
1082struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev)
1083{
1084 struct ctl_table_header *head;
1085 struct list_head *tmp;
1086 spin_lock(&sysctl_lock);
1087 if (prev) {
1088 tmp = &prev->ctl_entry;
1089 unuse_table(prev);
1090 goto next;
1091 }
1092 tmp = &root_table_header.ctl_entry;
1093 for (;;) {
1094 head = list_entry(tmp, struct ctl_table_header, ctl_entry);
1095
1096 if (!use_table(head))
1097 goto next;
1098 spin_unlock(&sysctl_lock);
1099 return head;
1100 next:
1101 tmp = tmp->next;
1102 if (tmp == &root_table_header.ctl_entry)
1103 break;
1104 }
1105 spin_unlock(&sysctl_lock);
1106 return NULL;
1107}
1108
1073void __init sysctl_init(void) 1109void __init sysctl_init(void)
1074{ 1110{
1075#ifdef CONFIG_PROC_SYSCTL 1111#ifdef CONFIG_PROC_SYSCTL
@@ -1081,7 +1117,7 @@ void __init sysctl_init(void)
1081int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, 1117int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
1082 void __user *newval, size_t newlen) 1118 void __user *newval, size_t newlen)
1083{ 1119{
1084 struct list_head *tmp; 1120 struct ctl_table_header *head;
1085 int error = -ENOTDIR; 1121 int error = -ENOTDIR;
1086 1122
1087 if (nlen <= 0 || nlen >= CTL_MAXNAME) 1123 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
1091 if (!oldlenp || get_user(old_len, oldlenp)) 1127 if (!oldlenp || get_user(old_len, oldlenp))
1092 return -EFAULT; 1128 return -EFAULT;
1093 } 1129 }
1094 spin_lock(&sysctl_lock);
1095 tmp = &root_table_header.ctl_entry;
1096 do {
1097 struct ctl_table_header *head =
1098 list_entry(tmp, struct ctl_table_header, ctl_entry);
1099
1100 if (!use_table(head))
1101 continue;
1102
1103 spin_unlock(&sysctl_lock);
1104 1130
1131 for (head = sysctl_head_next(NULL); head;
1132 head = sysctl_head_next(head)) {
1105 error = parse_table(name, nlen, oldval, oldlenp, 1133 error = parse_table(name, nlen, oldval, oldlenp,
1106 newval, newlen, head->ctl_table); 1134 newval, newlen, head->ctl_table);
1107 1135 if (error != -ENOTDIR) {
1108 spin_lock(&sysctl_lock); 1136 sysctl_head_finish(head);
1109 unuse_table(head);
1110 if (error != -ENOTDIR)
1111 break; 1137 break;
1112 } while ((tmp = tmp->next) != &root_table_header.ctl_entry); 1138 }
1113 spin_unlock(&sysctl_lock); 1139 }
1114 return error; 1140 return error;
1115} 1141}
1116 1142