aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc')
-rw-r--r--fs/proc/proc_sysctl.c397
1 files changed, 295 insertions, 102 deletions
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index a78556514a87..ec54a57c4690 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -32,26 +32,26 @@ static struct ctl_table root_table[] = {
32 }, 32 },
33 { } 33 { }
34}; 34};
35static struct ctl_table_root sysctl_table_root; 35static struct ctl_table_root sysctl_table_root = {
36static struct ctl_dir sysctl_root_dir = { 36 .default_set.list = LIST_HEAD_INIT(sysctl_table_root.default_set.dir.header.ctl_entry),
37 .header = { 37 .default_set.dir.header = {
38 {{.count = 1, 38 {{.count = 1,
39 .nreg = 1, 39 .nreg = 1,
40 .ctl_table = root_table, 40 .ctl_table = root_table,
41 .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),}}, 41 .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),}},
42 .ctl_table_arg = root_table,
42 .root = &sysctl_table_root, 43 .root = &sysctl_table_root,
43 .set = &sysctl_table_root.default_set, 44 .set = &sysctl_table_root.default_set,
44 }, 45 },
45}; 46};
46static struct ctl_table_root sysctl_table_root = {
47 .root_list = LIST_HEAD_INIT(sysctl_table_root.root_list),
48 .default_set.list = LIST_HEAD_INIT(sysctl_root_dir.header.ctl_entry),
49 .default_set.root = &sysctl_table_root,
50};
51 47
52static DEFINE_SPINLOCK(sysctl_lock); 48static DEFINE_SPINLOCK(sysctl_lock);
53 49
54static void drop_sysctl_table(struct ctl_table_header *header); 50static void drop_sysctl_table(struct ctl_table_header *header);
51static int sysctl_follow_link(struct ctl_table_header **phead,
52 struct ctl_table **pentry, struct nsproxy *namespaces);
53static int insert_links(struct ctl_table_header *head);
54static void put_links(struct ctl_table_header *header);
55 55
56static void sysctl_print_dir(struct ctl_dir *dir) 56static void sysctl_print_dir(struct ctl_dir *dir)
57{ 57{
@@ -76,9 +76,9 @@ static int namecmp(const char *name1, int len1, const char *name2, int len2)
76} 76}
77 77
78static struct ctl_table *find_entry(struct ctl_table_header **phead, 78static struct ctl_table *find_entry(struct ctl_table_header **phead,
79 struct ctl_table_set *set, struct ctl_dir *dir, 79 struct ctl_dir *dir, const char *name, int namelen)
80 const char *name, int namelen)
81{ 80{
81 struct ctl_table_set *set = dir->header.set;
82 struct ctl_table_header *head; 82 struct ctl_table_header *head;
83 struct ctl_table *entry; 83 struct ctl_table *entry;
84 84
@@ -119,11 +119,21 @@ static void erase_header(struct ctl_table_header *head)
119 list_del_init(&head->ctl_entry); 119 list_del_init(&head->ctl_entry);
120} 120}
121 121
122static void insert_header(struct ctl_dir *dir, struct ctl_table_header *header) 122static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
123{ 123{
124 int err;
125
126 dir->header.nreg++;
124 header->parent = dir; 127 header->parent = dir;
125 header->parent->header.nreg++; 128 err = insert_links(header);
129 if (err)
130 goto fail_links;
126 list_add_tail(&header->ctl_entry, &header->set->list); 131 list_add_tail(&header->ctl_entry, &header->set->list);
132 return 0;
133fail_links:
134 header->parent = NULL;
135 drop_sysctl_table(&dir->header);
136 return err;
127} 137}
128 138
129/* called under sysctl_lock */ 139/* called under sysctl_lock */
@@ -212,72 +222,39 @@ lookup_header_set(struct ctl_table_root *root, struct nsproxy *namespaces)
212 return set; 222 return set;
213} 223}
214 224
215static struct list_head *
216lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces)
217{
218 struct ctl_table_set *set = lookup_header_set(root, namespaces);
219 return &set->list;
220}
221
222static struct ctl_table *lookup_entry(struct ctl_table_header **phead, 225static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
223 struct ctl_dir *dir, 226 struct ctl_dir *dir,
224 const char *name, int namelen) 227 const char *name, int namelen)
225{ 228{
226 struct ctl_table_header *head; 229 struct ctl_table_header *head;
227 struct ctl_table *entry; 230 struct ctl_table *entry;
228 struct ctl_table_root *root;
229 struct ctl_table_set *set;
230 231
231 spin_lock(&sysctl_lock); 232 spin_lock(&sysctl_lock);
232 root = &sysctl_table_root; 233 entry = find_entry(&head, dir, name, namelen);
233 do { 234 if (entry && use_table(head))
234 set = lookup_header_set(root, current->nsproxy); 235 *phead = head;
235 entry = find_entry(&head, set, dir, name, namelen); 236 else
236 if (entry && use_table(head)) 237 entry = NULL;
237 *phead = head;
238 else
239 entry = NULL;
240 root = list_entry(root->root_list.next,
241 struct ctl_table_root, root_list);
242 } while (!entry && root != &sysctl_table_root);
243 spin_unlock(&sysctl_lock); 238 spin_unlock(&sysctl_lock);
244 return entry; 239 return entry;
245} 240}
246 241
247static struct ctl_table_header *next_usable_entry(struct ctl_dir *dir, 242static struct ctl_table_header *next_usable_entry(struct ctl_dir *dir,
248 struct ctl_table_root *root, struct list_head *tmp) 243 struct list_head *tmp)
249{ 244{
250 struct nsproxy *namespaces = current->nsproxy; 245 struct ctl_table_set *set = dir->header.set;
251 struct list_head *header_list;
252 struct ctl_table_header *head; 246 struct ctl_table_header *head;
253 247
254 goto next; 248 for (tmp = tmp->next; tmp != &set->list; tmp = tmp->next) {
255 for (;;) {
256 head = list_entry(tmp, struct ctl_table_header, ctl_entry); 249 head = list_entry(tmp, struct ctl_table_header, ctl_entry);
257 root = head->root;
258 250
259 if (head->parent != dir || 251 if (head->parent != dir ||
260 !head->ctl_table->procname || 252 !head->ctl_table->procname ||
261 !use_table(head)) 253 !use_table(head))
262 goto next;
263
264 return head;
265 next:
266 tmp = tmp->next;
267 header_list = lookup_header_list(root, namespaces);
268 if (tmp != header_list)
269 continue; 254 continue;
270 255
271 do { 256 return head;
272 root = list_entry(root->root_list.next,
273 struct ctl_table_root, root_list);
274 if (root == &sysctl_table_root)
275 goto out;
276 header_list = lookup_header_list(root, namespaces);
277 } while (list_empty(header_list));
278 tmp = header_list->next;
279 } 257 }
280out:
281 return NULL; 258 return NULL;
282} 259}
283 260
@@ -288,8 +265,7 @@ static void first_entry(struct ctl_dir *dir,
288 struct ctl_table *entry = NULL; 265 struct ctl_table *entry = NULL;
289 266
290 spin_lock(&sysctl_lock); 267 spin_lock(&sysctl_lock);
291 head = next_usable_entry(dir, &sysctl_table_root, 268 head = next_usable_entry(dir, &dir->header.set->list);
292 &sysctl_table_root.default_set.list);
293 spin_unlock(&sysctl_lock); 269 spin_unlock(&sysctl_lock);
294 if (head) 270 if (head)
295 entry = head->ctl_table; 271 entry = head->ctl_table;
@@ -306,7 +282,7 @@ static void next_entry(struct ctl_table_header **phead, struct ctl_table **pentr
306 if (!entry->procname) { 282 if (!entry->procname) {
307 spin_lock(&sysctl_lock); 283 spin_lock(&sysctl_lock);
308 unuse_table(head); 284 unuse_table(head);
309 head = next_usable_entry(head->parent, head->root, &head->ctl_entry); 285 head = next_usable_entry(head->parent, &head->ctl_entry);
310 spin_unlock(&sysctl_lock); 286 spin_unlock(&sysctl_lock);
311 if (head) 287 if (head)
312 entry = head->ctl_table; 288 entry = head->ctl_table;
@@ -317,9 +293,6 @@ static void next_entry(struct ctl_table_header **phead, struct ctl_table **pentr
317 293
318void register_sysctl_root(struct ctl_table_root *root) 294void register_sysctl_root(struct ctl_table_root *root)
319{ 295{
320 spin_lock(&sysctl_lock);
321 list_add_tail(&root->root_list, &sysctl_table_root.root_list);
322 spin_unlock(&sysctl_lock);
323} 296}
324 297
325/* 298/*
@@ -386,7 +359,7 @@ static struct ctl_table_header *grab_header(struct inode *inode)
386{ 359{
387 struct ctl_table_header *head = PROC_I(inode)->sysctl; 360 struct ctl_table_header *head = PROC_I(inode)->sysctl;
388 if (!head) 361 if (!head)
389 head = &sysctl_root_dir.header; 362 head = &sysctl_table_root.default_set.dir.header;
390 return sysctl_head_grab(head); 363 return sysctl_head_grab(head);
391} 364}
392 365
@@ -400,6 +373,7 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
400 struct inode *inode; 373 struct inode *inode;
401 struct dentry *err = ERR_PTR(-ENOENT); 374 struct dentry *err = ERR_PTR(-ENOENT);
402 struct ctl_dir *ctl_dir; 375 struct ctl_dir *ctl_dir;
376 int ret;
403 377
404 if (IS_ERR(head)) 378 if (IS_ERR(head))
405 return ERR_CAST(head); 379 return ERR_CAST(head);
@@ -410,6 +384,11 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
410 if (!p) 384 if (!p)
411 goto out; 385 goto out;
412 386
387 ret = sysctl_follow_link(&h, &p, current->nsproxy);
388 err = ERR_PTR(ret);
389 if (ret)
390 goto out;
391
413 err = ERR_PTR(-ENOMEM); 392 err = ERR_PTR(-ENOMEM);
414 inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p); 393 inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p);
415 if (h) 394 if (h)
@@ -547,6 +526,25 @@ static int proc_sys_fill_cache(struct file *filp, void *dirent,
547 return !!filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type); 526 return !!filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type);
548} 527}
549 528
529static int proc_sys_link_fill_cache(struct file *filp, void *dirent,
530 filldir_t filldir,
531 struct ctl_table_header *head,
532 struct ctl_table *table)
533{
534 int err, ret = 0;
535 head = sysctl_head_grab(head);
536
537 /* It is not an error if we can not follow the link ignore it */
538 err = sysctl_follow_link(&head, &table, current->nsproxy);
539 if (err)
540 goto out;
541
542 ret = proc_sys_fill_cache(filp, dirent, filldir, head, table);
543out:
544 sysctl_head_finish(head);
545 return ret;
546}
547
550static int scan(struct ctl_table_header *head, ctl_table *table, 548static int scan(struct ctl_table_header *head, ctl_table *table,
551 unsigned long *pos, struct file *file, 549 unsigned long *pos, struct file *file,
552 void *dirent, filldir_t filldir) 550 void *dirent, filldir_t filldir)
@@ -556,7 +554,10 @@ static int scan(struct ctl_table_header *head, ctl_table *table,
556 if ((*pos)++ < file->f_pos) 554 if ((*pos)++ < file->f_pos)
557 return 0; 555 return 0;
558 556
559 res = proc_sys_fill_cache(file, dirent, filldir, head, table); 557 if (unlikely(S_ISLNK(table->mode)))
558 res = proc_sys_link_fill_cache(file, dirent, filldir, head, table);
559 else
560 res = proc_sys_fill_cache(file, dirent, filldir, head, table);
560 561
561 if (res == 0) 562 if (res == 0)
562 file->f_pos = *pos; 563 file->f_pos = *pos;
@@ -757,13 +758,13 @@ static const struct dentry_operations proc_sys_dentry_operations = {
757 .d_compare = proc_sys_compare, 758 .d_compare = proc_sys_compare,
758}; 759};
759 760
760static struct ctl_dir *find_subdir(struct ctl_table_set *set, struct ctl_dir *dir, 761static struct ctl_dir *find_subdir(struct ctl_dir *dir,
761 const char *name, int namelen) 762 const char *name, int namelen)
762{ 763{
763 struct ctl_table_header *head; 764 struct ctl_table_header *head;
764 struct ctl_table *entry; 765 struct ctl_table *entry;
765 766
766 entry = find_entry(&head, set, dir, name, namelen); 767 entry = find_entry(&head, dir, name, namelen);
767 if (!entry) 768 if (!entry)
768 return ERR_PTR(-ENOENT); 769 return ERR_PTR(-ENOENT);
769 if (S_ISDIR(entry->mode)) 770 if (S_ISDIR(entry->mode))
@@ -772,7 +773,7 @@ static struct ctl_dir *find_subdir(struct ctl_table_set *set, struct ctl_dir *di
772} 773}
773 774
774static struct ctl_dir *new_dir(struct ctl_table_set *set, 775static struct ctl_dir *new_dir(struct ctl_table_set *set,
775 const char *name, int namelen) 776 const char *name, int namelen)
776{ 777{
777 struct ctl_table *table; 778 struct ctl_table *table;
778 struct ctl_dir *new; 779 struct ctl_dir *new;
@@ -789,22 +790,19 @@ static struct ctl_dir *new_dir(struct ctl_table_set *set,
789 new_name[namelen] = '\0'; 790 new_name[namelen] = '\0';
790 table[0].procname = new_name; 791 table[0].procname = new_name;
791 table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO; 792 table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO;
792 init_header(&new->header, set->root, set, table); 793 init_header(&new->header, set->dir.header.root, set, table);
793 794
794 return new; 795 return new;
795} 796}
796 797
797static struct ctl_dir *get_subdir(struct ctl_table_set *set, 798static struct ctl_dir *get_subdir(struct ctl_dir *dir,
798 struct ctl_dir *dir, const char *name, int namelen) 799 const char *name, int namelen)
799{ 800{
801 struct ctl_table_set *set = dir->header.set;
800 struct ctl_dir *subdir, *new = NULL; 802 struct ctl_dir *subdir, *new = NULL;
801 803
802 spin_lock(&sysctl_lock); 804 spin_lock(&sysctl_lock);
803 subdir = find_subdir(dir->header.set, dir, name, namelen); 805 subdir = find_subdir(dir, name, namelen);
804 if (!IS_ERR(subdir))
805 goto found;
806 if ((PTR_ERR(subdir) == -ENOENT) && set != dir->header.set)
807 subdir = find_subdir(set, dir, name, namelen);
808 if (!IS_ERR(subdir)) 806 if (!IS_ERR(subdir))
809 goto found; 807 goto found;
810 if (PTR_ERR(subdir) != -ENOENT) 808 if (PTR_ERR(subdir) != -ENOENT)
@@ -817,13 +815,14 @@ static struct ctl_dir *get_subdir(struct ctl_table_set *set,
817 if (!new) 815 if (!new)
818 goto failed; 816 goto failed;
819 817
820 subdir = find_subdir(set, dir, name, namelen); 818 subdir = find_subdir(dir, name, namelen);
821 if (!IS_ERR(subdir)) 819 if (!IS_ERR(subdir))
822 goto found; 820 goto found;
823 if (PTR_ERR(subdir) != -ENOENT) 821 if (PTR_ERR(subdir) != -ENOENT)
824 goto failed; 822 goto failed;
825 823
826 insert_header(dir, &new->header); 824 if (insert_header(dir, &new->header))
825 goto failed;
827 subdir = new; 826 subdir = new;
828found: 827found:
829 subdir->header.nreg++; 828 subdir->header.nreg++;
@@ -841,6 +840,57 @@ failed:
841 return subdir; 840 return subdir;
842} 841}
843 842
843static struct ctl_dir *xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir)
844{
845 struct ctl_dir *parent;
846 const char *procname;
847 if (!dir->header.parent)
848 return &set->dir;
849 parent = xlate_dir(set, dir->header.parent);
850 if (IS_ERR(parent))
851 return parent;
852 procname = dir->header.ctl_table[0].procname;
853 return find_subdir(parent, procname, strlen(procname));
854}
855
856static int sysctl_follow_link(struct ctl_table_header **phead,
857 struct ctl_table **pentry, struct nsproxy *namespaces)
858{
859 struct ctl_table_header *head;
860 struct ctl_table_root *root;
861 struct ctl_table_set *set;
862 struct ctl_table *entry;
863 struct ctl_dir *dir;
864 int ret;
865
866 /* Get out quickly if not a link */
867 if (!S_ISLNK((*pentry)->mode))
868 return 0;
869
870 ret = 0;
871 spin_lock(&sysctl_lock);
872 root = (*pentry)->data;
873 set = lookup_header_set(root, namespaces);
874 dir = xlate_dir(set, (*phead)->parent);
875 if (IS_ERR(dir))
876 ret = PTR_ERR(dir);
877 else {
878 const char *procname = (*pentry)->procname;
879 head = NULL;
880 entry = find_entry(&head, dir, procname, strlen(procname));
881 ret = -ENOENT;
882 if (entry && use_table(head)) {
883 unuse_table(*phead);
884 *phead = head;
885 *pentry = entry;
886 ret = 0;
887 }
888 }
889
890 spin_unlock(&sysctl_lock);
891 return ret;
892}
893
844static int sysctl_check_table_dups(const char *path, struct ctl_table *old, 894static int sysctl_check_table_dups(const char *path, struct ctl_table *old,
845 struct ctl_table *table) 895 struct ctl_table *table)
846{ 896{
@@ -859,30 +909,21 @@ static int sysctl_check_table_dups(const char *path, struct ctl_table *old,
859 return error; 909 return error;
860} 910}
861 911
862static int sysctl_check_dups(struct nsproxy *namespaces, 912static int sysctl_check_dups(struct ctl_dir *dir,
863 struct ctl_dir *dir,
864 const char *path, struct ctl_table *table) 913 const char *path, struct ctl_table *table)
865{ 914{
866 struct ctl_table_root *root;
867 struct ctl_table_set *set; 915 struct ctl_table_set *set;
868 struct ctl_table_header *head; 916 struct ctl_table_header *head;
869 int error = 0; 917 int error = 0;
870 918
871 root = &sysctl_table_root; 919 set = dir->header.set;
872 do { 920 list_for_each_entry(head, &set->list, ctl_entry) {
873 set = lookup_header_set(root, namespaces); 921 if (head->unregistering)
874 922 continue;
875 list_for_each_entry(head, &set->list, ctl_entry) { 923 if (head->parent != dir)
876 if (head->unregistering) 924 continue;
877 continue; 925 error = sysctl_check_table_dups(path, head->ctl_table, table);
878 if (head->parent != dir) 926 }
879 continue;
880 error = sysctl_check_table_dups(path, head->ctl_table,
881 table);
882 }
883 root = list_entry(root->root_list.next,
884 struct ctl_table_root, root_list);
885 } while (root != &sysctl_table_root);
886 return error; 927 return error;
887} 928}
888 929
@@ -932,6 +973,115 @@ static int sysctl_check_table(const char *path, struct ctl_table *table)
932 return err; 973 return err;
933} 974}
934 975
976static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table *table,
977 struct ctl_table_root *link_root)
978{
979 struct ctl_table *link_table, *entry, *link;
980 struct ctl_table_header *links;
981 char *link_name;
982 int nr_entries, name_bytes;
983
984 name_bytes = 0;
985 nr_entries = 0;
986 for (entry = table; entry->procname; entry++) {
987 nr_entries++;
988 name_bytes += strlen(entry->procname) + 1;
989 }
990
991 links = kzalloc(sizeof(struct ctl_table_header) +
992 sizeof(struct ctl_table)*(nr_entries + 1) +
993 name_bytes,
994 GFP_KERNEL);
995
996 if (!links)
997 return NULL;
998
999 link_table = (struct ctl_table *)(links + 1);
1000 link_name = (char *)&link_table[nr_entries + 1];
1001
1002 for (link = link_table, entry = table; entry->procname; link++, entry++) {
1003 int len = strlen(entry->procname) + 1;
1004 memcpy(link_name, entry->procname, len);
1005 link->procname = link_name;
1006 link->mode = S_IFLNK|S_IRWXUGO;
1007 link->data = link_root;
1008 link_name += len;
1009 }
1010 init_header(links, dir->header.root, dir->header.set, link_table);
1011 links->nreg = nr_entries;
1012
1013 return links;
1014}
1015
1016static bool get_links(struct ctl_dir *dir,
1017 struct ctl_table *table, struct ctl_table_root *link_root)
1018{
1019 struct ctl_table_header *head;
1020 struct ctl_table *entry, *link;
1021
1022 /* Are there links available for every entry in table? */
1023 for (entry = table; entry->procname; entry++) {
1024 const char *procname = entry->procname;
1025 link = find_entry(&head, dir, procname, strlen(procname));
1026 if (!link)
1027 return false;
1028 if (S_ISDIR(link->mode) && S_ISDIR(entry->mode))
1029 continue;
1030 if (S_ISLNK(link->mode) && (link->data == link_root))
1031 continue;
1032 return false;
1033 }
1034
1035 /* The checks passed. Increase the registration count on the links */
1036 for (entry = table; entry->procname; entry++) {
1037 const char *procname = entry->procname;
1038 link = find_entry(&head, dir, procname, strlen(procname));
1039 head->nreg++;
1040 }
1041 return true;
1042}
1043
1044static int insert_links(struct ctl_table_header *head)
1045{
1046 struct ctl_table_set *root_set = &sysctl_table_root.default_set;
1047 struct ctl_dir *core_parent = NULL;
1048 struct ctl_table_header *links;
1049 int err;
1050
1051 if (head->set == root_set)
1052 return 0;
1053
1054 core_parent = xlate_dir(root_set, head->parent);
1055 if (IS_ERR(core_parent))
1056 return 0;
1057
1058 if (get_links(core_parent, head->ctl_table, head->root))
1059 return 0;
1060
1061 core_parent->header.nreg++;
1062 spin_unlock(&sysctl_lock);
1063
1064 links = new_links(core_parent, head->ctl_table, head->root);
1065
1066 spin_lock(&sysctl_lock);
1067 err = -ENOMEM;
1068 if (!links)
1069 goto out;
1070
1071 err = 0;
1072 if (get_links(core_parent, head->ctl_table, head->root)) {
1073 kfree(links);
1074 goto out;
1075 }
1076
1077 err = insert_header(core_parent, links);
1078 if (err)
1079 kfree(links);
1080out:
1081 drop_sysctl_table(&core_parent->header);
1082 return err;
1083}
1084
935/** 1085/**
936 * __register_sysctl_table - register a leaf sysctl table 1086 * __register_sysctl_table - register a leaf sysctl table
937 * @root: List of sysctl headers to register on 1087 * @root: List of sysctl headers to register on
@@ -980,6 +1130,7 @@ struct ctl_table_header *__register_sysctl_table(
980 struct nsproxy *namespaces, 1130 struct nsproxy *namespaces,
981 const char *path, struct ctl_table *table) 1131 const char *path, struct ctl_table *table)
982{ 1132{
1133 struct ctl_table_header *links = NULL;
983 struct ctl_table_header *header; 1134 struct ctl_table_header *header;
984 const char *name, *nextname; 1135 const char *name, *nextname;
985 struct ctl_table_set *set; 1136 struct ctl_table_set *set;
@@ -995,7 +1146,7 @@ struct ctl_table_header *__register_sysctl_table(
995 1146
996 spin_lock(&sysctl_lock); 1147 spin_lock(&sysctl_lock);
997 header->set = set = lookup_header_set(root, namespaces); 1148 header->set = set = lookup_header_set(root, namespaces);
998 dir = &sysctl_root_dir; 1149 dir = &set->dir;
999 dir->header.nreg++; 1150 dir->header.nreg++;
1000 spin_unlock(&sysctl_lock); 1151 spin_unlock(&sysctl_lock);
1001 1152
@@ -1012,22 +1163,28 @@ struct ctl_table_header *__register_sysctl_table(
1012 if (namelen == 0) 1163 if (namelen == 0)
1013 continue; 1164 continue;
1014 1165
1015 dir = get_subdir(set, dir, name, namelen); 1166 dir = get_subdir(dir, name, namelen);
1016 if (IS_ERR(dir)) 1167 if (IS_ERR(dir))
1017 goto fail; 1168 goto fail;
1018 } 1169 }
1170
1019 spin_lock(&sysctl_lock); 1171 spin_lock(&sysctl_lock);
1020 if (sysctl_check_dups(namespaces, dir, path, table)) 1172 if (sysctl_check_dups(dir, path, table))
1173 goto fail_put_dir_locked;
1174
1175 if (insert_header(dir, header))
1021 goto fail_put_dir_locked; 1176 goto fail_put_dir_locked;
1022 insert_header(dir, header); 1177
1023 drop_sysctl_table(&dir->header); 1178 drop_sysctl_table(&dir->header);
1024 spin_unlock(&sysctl_lock); 1179 spin_unlock(&sysctl_lock);
1025 1180
1026 return header; 1181 return header;
1182
1027fail_put_dir_locked: 1183fail_put_dir_locked:
1028 drop_sysctl_table(&dir->header); 1184 drop_sysctl_table(&dir->header);
1029 spin_unlock(&sysctl_lock); 1185 spin_unlock(&sysctl_lock);
1030fail: 1186fail:
1187 kfree(links);
1031 kfree(header); 1188 kfree(header);
1032 dump_stack(); 1189 dump_stack();
1033 return NULL; 1190 return NULL;
@@ -1249,6 +1406,40 @@ struct ctl_table_header *register_sysctl_table(struct ctl_table *table)
1249} 1406}
1250EXPORT_SYMBOL(register_sysctl_table); 1407EXPORT_SYMBOL(register_sysctl_table);
1251 1408
1409static void put_links(struct ctl_table_header *header)
1410{
1411 struct ctl_table_set *root_set = &sysctl_table_root.default_set;
1412 struct ctl_table_root *root = header->root;
1413 struct ctl_dir *parent = header->parent;
1414 struct ctl_dir *core_parent;
1415 struct ctl_table *entry;
1416
1417 if (header->set == root_set)
1418 return;
1419
1420 core_parent = xlate_dir(root_set, parent);
1421 if (IS_ERR(core_parent))
1422 return;
1423
1424 for (entry = header->ctl_table; entry->procname; entry++) {
1425 struct ctl_table_header *link_head;
1426 struct ctl_table *link;
1427 const char *name = entry->procname;
1428
1429 link = find_entry(&link_head, core_parent, name, strlen(name));
1430 if (link &&
1431 ((S_ISDIR(link->mode) && S_ISDIR(entry->mode)) ||
1432 (S_ISLNK(link->mode) && (link->data == root)))) {
1433 drop_sysctl_table(link_head);
1434 }
1435 else {
1436 printk(KERN_ERR "sysctl link missing during unregister: ");
1437 sysctl_print_dir(parent);
1438 printk(KERN_CONT "/%s\n", name);
1439 }
1440 }
1441}
1442
1252static void drop_sysctl_table(struct ctl_table_header *header) 1443static void drop_sysctl_table(struct ctl_table_header *header)
1253{ 1444{
1254 struct ctl_dir *parent = header->parent; 1445 struct ctl_dir *parent = header->parent;
@@ -1256,6 +1447,7 @@ static void drop_sysctl_table(struct ctl_table_header *header)
1256 if (--header->nreg) 1447 if (--header->nreg)
1257 return; 1448 return;
1258 1449
1450 put_links(header);
1259 start_unregistering(header); 1451 start_unregistering(header);
1260 if (!--header->count) 1452 if (!--header->count)
1261 kfree_rcu(header, rcu); 1453 kfree_rcu(header, rcu);
@@ -1301,13 +1493,14 @@ void unregister_sysctl_table(struct ctl_table_header * header)
1301} 1493}
1302EXPORT_SYMBOL(unregister_sysctl_table); 1494EXPORT_SYMBOL(unregister_sysctl_table);
1303 1495
1304void setup_sysctl_set(struct ctl_table_set *p, 1496void setup_sysctl_set(struct ctl_table_set *set,
1305 struct ctl_table_root *root, 1497 struct ctl_table_root *root,
1306 int (*is_seen)(struct ctl_table_set *)) 1498 int (*is_seen)(struct ctl_table_set *))
1307{ 1499{
1308 INIT_LIST_HEAD(&p->list); 1500 memset(set, sizeof(*set), 0);
1309 p->root = root; 1501 INIT_LIST_HEAD(&set->list);
1310 p->is_seen = is_seen; 1502 set->is_seen = is_seen;
1503 init_header(&set->dir.header, root, set, root_table);
1311} 1504}
1312 1505
1313void retire_sysctl_set(struct ctl_table_set *set) 1506void retire_sysctl_set(struct ctl_table_set *set)