diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2007-02-14 03:34:11 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-14 11:09:59 -0500 |
commit | 805b5d5e063e7fde5e2eb724e3f4cb18e47cab19 (patch) | |
tree | 920f66deb8d6286ee819ac0402d1771543a12a88 | |
parent | 0b4d414714f0d2f922d39424b0c5c82ad900a381 (diff) |
[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>
-rw-r--r-- | include/linux/sysctl.h | 4 | ||||
-rw-r--r-- | kernel/sysctl.c | 60 |
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 */ | ||
928 | extern struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev); | ||
929 | extern void sysctl_head_finish(struct ctl_table_header *prev); | ||
930 | |||
927 | extern void sysctl_init(void); | 931 | extern void sysctl_init(void); |
928 | 932 | ||
929 | typedef struct ctl_table ctl_table; | 933 | typedef 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 | ||
1073 | void 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 | |||
1082 | struct 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 | |||
1073 | void __init sysctl_init(void) | 1109 | void __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) | |||
1081 | int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, | 1117 | int 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 | ||