aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/proc_sysctl.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2011-12-29 11:24:29 -0500
committerEric W. Biederman <ebiederm@xmission.com>2012-01-24 19:40:29 -0500
commit7ec66d06362da7684a4948c4c2bf1f8546425df4 (patch)
treea16212ae2d23a46890c6d89068eaa9b2eb0f6e37 /fs/proc/proc_sysctl.c
parent9eb47c26f09e27506d343ef52e634b2a50ee21ef (diff)
sysctl: Stop requiring explicit management of sysctl directories
Simplify the code and the sysctl semantics by autogenerating sysctl directories when a sysctl table is registered that needs the directories and autodeleting the directories when there are no more sysctl tables registered that need them. Autogenerating directories keeps sysctl tables from depending on each other, removing all of the arcane register/unregister ordering constraints and makes it impossible to get the order wrong when reigsering and unregistering sysctl tables. Autogenerating directories yields one unique entity that dentries can point to, retaining the current effective use of the dcache. Add struct ctl_dir as the type of these new autogenerated directories. The attached_by and attached_to fields in ctl_table_header are removed as they are no longer needed. The child field in ctl_table is no longer needed by the core of the sysctl code. ctl_table.child can be removed once all of the existing users have been updated. Benchmark before: make-dummies 0 999 -> 0.7s rmmod dummy -> 0.07s make-dummies 0 9999 -> 1m10s rmmod dummy -> 0.4s Benchmark after: make-dummies 0 999 -> 0.44s rmmod dummy -> 0.065s make-dummies 0 9999 -> 1m36s rmmod dummy -> 0.4s Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Diffstat (limited to 'fs/proc/proc_sysctl.c')
-rw-r--r--fs/proc/proc_sysctl.c342
1 files changed, 143 insertions, 199 deletions
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 65c13dddceae..3c0767d5a55f 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -28,28 +28,31 @@ void proc_sys_poll_notify(struct ctl_table_poll *poll)
28static struct ctl_table root_table[] = { 28static struct ctl_table root_table[] = {
29 { 29 {
30 .procname = "", 30 .procname = "",
31 .mode = S_IRUGO|S_IXUGO, 31 .mode = S_IFDIR|S_IRUGO|S_IXUGO,
32 .child = &root_table[1],
33 }, 32 },
34 { } 33 { }
35}; 34};
36static struct ctl_table_root sysctl_table_root; 35static struct ctl_table_root sysctl_table_root;
37static struct ctl_table_header root_table_header = { 36static struct ctl_dir sysctl_root_dir = {
38 {{.count = 1, 37 .header = {
39 .nreg = 1, 38 {{.count = 1,
40 .ctl_table = root_table, 39 .nreg = 1,
41 .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),}}, 40 .ctl_table = root_table,
42 .root = &sysctl_table_root, 41 .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),}},
43 .set = &sysctl_table_root.default_set, 42 .root = &sysctl_table_root,
43 .set = &sysctl_table_root.default_set,
44 },
44}; 45};
45static struct ctl_table_root sysctl_table_root = { 46static struct ctl_table_root sysctl_table_root = {
46 .root_list = LIST_HEAD_INIT(sysctl_table_root.root_list), 47 .root_list = LIST_HEAD_INIT(sysctl_table_root.root_list),
47 .default_set.list = LIST_HEAD_INIT(root_table_header.ctl_entry), 48 .default_set.list = LIST_HEAD_INIT(sysctl_root_dir.header.ctl_entry),
48 .default_set.root = &sysctl_table_root, 49 .default_set.root = &sysctl_table_root,
49}; 50};
50 51
51static DEFINE_SPINLOCK(sysctl_lock); 52static DEFINE_SPINLOCK(sysctl_lock);
52 53
54static void drop_sysctl_table(struct ctl_table_header *header);
55
53static int namecmp(const char *name1, int len1, const char *name2, int len2) 56static int namecmp(const char *name1, int len1, const char *name2, int len2)
54{ 57{
55 int minlen; 58 int minlen;
@@ -66,29 +69,18 @@ static int namecmp(const char *name1, int len1, const char *name2, int len2)
66} 69}
67 70
68static struct ctl_table *find_entry(struct ctl_table_header **phead, 71static struct ctl_table *find_entry(struct ctl_table_header **phead,
69 struct ctl_table_set *set, 72 struct ctl_table_set *set, struct ctl_dir *dir,
70 struct ctl_table_header *dir_head, struct ctl_table *dir,
71 const char *name, int namelen) 73 const char *name, int namelen)
72{ 74{
73 struct ctl_table_header *head; 75 struct ctl_table_header *head;
74 struct ctl_table *entry; 76 struct ctl_table *entry;
75 77
76 if (dir_head->set == set) {
77 for (entry = dir; entry->procname; entry++) {
78 const char *procname = entry->procname;
79 if (namecmp(procname, strlen(procname), name, namelen) == 0) {
80 *phead = dir_head;
81 return entry;
82 }
83 }
84 }
85
86 list_for_each_entry(head, &set->list, ctl_entry) { 78 list_for_each_entry(head, &set->list, ctl_entry) {
87 if (head->unregistering) 79 if (head->unregistering)
88 continue; 80 continue;
89 if (head->attached_to != dir) 81 if (head->parent != dir)
90 continue; 82 continue;
91 for (entry = head->attached_by; entry->procname; entry++) { 83 for (entry = head->ctl_table; entry->procname; entry++) {
92 const char *procname = entry->procname; 84 const char *procname = entry->procname;
93 if (namecmp(procname, strlen(procname), name, namelen) == 0) { 85 if (namecmp(procname, strlen(procname), name, namelen) == 0) {
94 *phead = head; 86 *phead = head;
@@ -103,6 +95,7 @@ static void init_header(struct ctl_table_header *head,
103 struct ctl_table_root *root, struct ctl_table_set *set, 95 struct ctl_table_root *root, struct ctl_table_set *set,
104 struct ctl_table *table) 96 struct ctl_table *table)
105{ 97{
98 head->ctl_table = table;
106 head->ctl_table_arg = table; 99 head->ctl_table_arg = table;
107 INIT_LIST_HEAD(&head->ctl_entry); 100 INIT_LIST_HEAD(&head->ctl_entry);
108 head->used = 0; 101 head->used = 0;
@@ -119,9 +112,10 @@ static void erase_header(struct ctl_table_header *head)
119 list_del_init(&head->ctl_entry); 112 list_del_init(&head->ctl_entry);
120} 113}
121 114
122static void insert_header(struct ctl_table_header *header) 115static void insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
123{ 116{
124 header->parent->count++; 117 header->parent = dir;
118 header->parent->header.nreg++;
125 list_add_tail(&header->ctl_entry, &header->set->list); 119 list_add_tail(&header->ctl_entry, &header->set->list);
126} 120}
127 121
@@ -219,8 +213,7 @@ lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces)
219} 213}
220 214
221static struct ctl_table *lookup_entry(struct ctl_table_header **phead, 215static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
222 struct ctl_table_header *dir_head, 216 struct ctl_dir *dir,
223 struct ctl_table *dir,
224 const char *name, int namelen) 217 const char *name, int namelen)
225{ 218{
226 struct ctl_table_header *head; 219 struct ctl_table_header *head;
@@ -232,7 +225,7 @@ static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
232 root = &sysctl_table_root; 225 root = &sysctl_table_root;
233 do { 226 do {
234 set = lookup_header_set(root, current->nsproxy); 227 set = lookup_header_set(root, current->nsproxy);
235 entry = find_entry(&head, set, dir_head, dir, name, namelen); 228 entry = find_entry(&head, set, dir, name, namelen);
236 if (entry && use_table(head)) 229 if (entry && use_table(head))
237 *phead = head; 230 *phead = head;
238 else 231 else
@@ -244,7 +237,7 @@ static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
244 return entry; 237 return entry;
245} 238}
246 239
247static struct ctl_table_header *next_usable_entry(struct ctl_table *dir, 240static struct ctl_table_header *next_usable_entry(struct ctl_dir *dir,
248 struct ctl_table_root *root, struct list_head *tmp) 241 struct ctl_table_root *root, struct list_head *tmp)
249{ 242{
250 struct nsproxy *namespaces = current->nsproxy; 243 struct nsproxy *namespaces = current->nsproxy;
@@ -256,8 +249,8 @@ static struct ctl_table_header *next_usable_entry(struct ctl_table *dir,
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; 250 root = head->root;
258 251
259 if (head->attached_to != dir || 252 if (head->parent != dir ||
260 !head->attached_by->procname || 253 !head->ctl_table->procname ||
261 !use_table(head)) 254 !use_table(head))
262 goto next; 255 goto next;
263 256
@@ -281,47 +274,35 @@ out:
281 return NULL; 274 return NULL;
282} 275}
283 276
284static void first_entry( 277static void first_entry(struct ctl_dir *dir,
285 struct ctl_table_header *dir_head, struct ctl_table *dir,
286 struct ctl_table_header **phead, struct ctl_table **pentry) 278 struct ctl_table_header **phead, struct ctl_table **pentry)
287{ 279{
288 struct ctl_table_header *head = dir_head; 280 struct ctl_table_header *head;
289 struct ctl_table *entry = dir; 281 struct ctl_table *entry = NULL;
290 282
291 spin_lock(&sysctl_lock); 283 spin_lock(&sysctl_lock);
292 if (entry->procname) { 284 head = next_usable_entry(dir, &sysctl_table_root,
293 use_table(head); 285 &sysctl_table_root.default_set.list);
294 } else {
295 head = next_usable_entry(dir, &sysctl_table_root,
296 &sysctl_table_root.default_set.list);
297 if (head)
298 entry = head->attached_by;
299 }
300 spin_unlock(&sysctl_lock); 286 spin_unlock(&sysctl_lock);
287 if (head)
288 entry = head->ctl_table;
301 *phead = head; 289 *phead = head;
302 *pentry = entry; 290 *pentry = entry;
303} 291}
304 292
305static void next_entry(struct ctl_table *dir, 293static void next_entry(struct ctl_table_header **phead, struct ctl_table **pentry)
306 struct ctl_table_header **phead, struct ctl_table **pentry)
307{ 294{
308 struct ctl_table_header *head = *phead; 295 struct ctl_table_header *head = *phead;
309 struct ctl_table *entry = *pentry; 296 struct ctl_table *entry = *pentry;
310 297
311 entry++; 298 entry++;
312 if (!entry->procname) { 299 if (!entry->procname) {
313 struct ctl_table_root *root = head->root;
314 struct list_head *tmp = &head->ctl_entry;
315 if (head->attached_to != dir) {
316 root = &sysctl_table_root;
317 tmp = &sysctl_table_root.default_set.list;
318 }
319 spin_lock(&sysctl_lock); 300 spin_lock(&sysctl_lock);
320 unuse_table(head); 301 unuse_table(head);
321 head = next_usable_entry(dir, root, tmp); 302 head = next_usable_entry(head->parent, head->root, &head->ctl_entry);
322 spin_unlock(&sysctl_lock); 303 spin_unlock(&sysctl_lock);
323 if (head) 304 if (head)
324 entry = head->attached_by; 305 entry = head->ctl_table;
325 } 306 }
326 *phead = head; 307 *phead = head;
327 *pentry = entry; 308 *pentry = entry;
@@ -381,7 +362,7 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
381 362
382 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; 363 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
383 inode->i_mode = table->mode; 364 inode->i_mode = table->mode;
384 if (!table->child) { 365 if (!S_ISDIR(table->mode)) {
385 inode->i_mode |= S_IFREG; 366 inode->i_mode |= S_IFREG;
386 inode->i_op = &proc_sys_inode_operations; 367 inode->i_op = &proc_sys_inode_operations;
387 inode->i_fop = &proc_sys_file_operations; 368 inode->i_fop = &proc_sys_file_operations;
@@ -398,7 +379,7 @@ static struct ctl_table_header *grab_header(struct inode *inode)
398{ 379{
399 struct ctl_table_header *head = PROC_I(inode)->sysctl; 380 struct ctl_table_header *head = PROC_I(inode)->sysctl;
400 if (!head) 381 if (!head)
401 head = &root_table_header; 382 head = &sysctl_root_dir.header;
402 return sysctl_head_grab(head); 383 return sysctl_head_grab(head);
403} 384}
404 385
@@ -406,24 +387,19 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
406 struct nameidata *nd) 387 struct nameidata *nd)
407{ 388{
408 struct ctl_table_header *head = grab_header(dir); 389 struct ctl_table_header *head = grab_header(dir);
409 struct ctl_table *table = PROC_I(dir)->sysctl_entry;
410 struct ctl_table_header *h = NULL; 390 struct ctl_table_header *h = NULL;
411 struct qstr *name = &dentry->d_name; 391 struct qstr *name = &dentry->d_name;
412 struct ctl_table *p; 392 struct ctl_table *p;
413 struct inode *inode; 393 struct inode *inode;
414 struct dentry *err = ERR_PTR(-ENOENT); 394 struct dentry *err = ERR_PTR(-ENOENT);
395 struct ctl_dir *ctl_dir;
415 396
416 if (IS_ERR(head)) 397 if (IS_ERR(head))
417 return ERR_CAST(head); 398 return ERR_CAST(head);
418 399
419 if (table && !table->child) { 400 ctl_dir = container_of(head, struct ctl_dir, header);
420 WARN_ON(1);
421 goto out;
422 }
423 401
424 table = table ? table->child : &head->ctl_table[1]; 402 p = lookup_entry(&h, ctl_dir, name->name, name->len);
425
426 p = lookup_entry(&h, head, table, name->name, name->len);
427 if (!p) 403 if (!p)
428 goto out; 404 goto out;
429 405
@@ -586,21 +562,16 @@ static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
586 struct dentry *dentry = filp->f_path.dentry; 562 struct dentry *dentry = filp->f_path.dentry;
587 struct inode *inode = dentry->d_inode; 563 struct inode *inode = dentry->d_inode;
588 struct ctl_table_header *head = grab_header(inode); 564 struct ctl_table_header *head = grab_header(inode);
589 struct ctl_table *table = PROC_I(inode)->sysctl_entry;
590 struct ctl_table_header *h = NULL; 565 struct ctl_table_header *h = NULL;
591 struct ctl_table *entry; 566 struct ctl_table *entry;
567 struct ctl_dir *ctl_dir;
592 unsigned long pos; 568 unsigned long pos;
593 int ret = -EINVAL; 569 int ret = -EINVAL;
594 570
595 if (IS_ERR(head)) 571 if (IS_ERR(head))
596 return PTR_ERR(head); 572 return PTR_ERR(head);
597 573
598 if (table && !table->child) { 574 ctl_dir = container_of(head, struct ctl_dir, header);
599 WARN_ON(1);
600 goto out;
601 }
602
603 table = table ? table->child : &head->ctl_table[1];
604 575
605 ret = 0; 576 ret = 0;
606 /* Avoid a switch here: arm builds fail with missing __cmpdi2 */ 577 /* Avoid a switch here: arm builds fail with missing __cmpdi2 */
@@ -618,7 +589,7 @@ static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
618 } 589 }
619 pos = 2; 590 pos = 2;
620 591
621 for (first_entry(head, table, &h, &entry); h; next_entry(table, &h, &entry)) { 592 for (first_entry(ctl_dir, &h, &entry); h; next_entry(&h, &entry)) {
622 ret = scan(h, entry, &pos, filp, dirent, filldir); 593 ret = scan(h, entry, &pos, filp, dirent, filldir);
623 if (ret) { 594 if (ret) {
624 sysctl_head_finish(h); 595 sysctl_head_finish(h);
@@ -779,52 +750,86 @@ static const struct dentry_operations proc_sys_dentry_operations = {
779 .d_compare = proc_sys_compare, 750 .d_compare = proc_sys_compare,
780}; 751};
781 752
782static struct ctl_table *is_branch_in(struct ctl_table *branch, 753static struct ctl_dir *find_subdir(struct ctl_table_set *set, struct ctl_dir *dir,
783 struct ctl_table *table) 754 const char *name, int namelen)
784{ 755{
785 struct ctl_table *p; 756 struct ctl_table_header *head;
786 const char *s = branch->procname; 757 struct ctl_table *entry;
787 758
788 /* branch should have named subdirectory as its first element */ 759 entry = find_entry(&head, set, dir, name, namelen);
789 if (!s || !branch->child) 760 if (!entry)
790 return NULL; 761 return ERR_PTR(-ENOENT);
762 if (S_ISDIR(entry->mode))
763 return container_of(head, struct ctl_dir, header);
764 return ERR_PTR(-ENOTDIR);
765}
766
767static struct ctl_dir *new_dir(struct ctl_table_set *set,
768 const char *name, int namelen)
769{
770 struct ctl_table *table;
771 struct ctl_dir *new;
772 char *new_name;
791 773
792 /* ... and nothing else */ 774 new = kzalloc(sizeof(*new) + sizeof(struct ctl_table)*2 +
793 if (branch[1].procname) 775 namelen + 1, GFP_KERNEL);
776 if (!new)
794 return NULL; 777 return NULL;
795 778
796 /* table should contain subdirectory with the same name */ 779 table = (struct ctl_table *)(new + 1);
797 for (p = table; p->procname; p++) { 780 new_name = (char *)(table + 2);
798 if (!p->child) 781 memcpy(new_name, name, namelen);
799 continue; 782 new_name[namelen] = '\0';
800 if (p->procname && strcmp(p->procname, s) == 0) 783 table[0].procname = new_name;
801 return p; 784 table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO;
802 } 785 init_header(&new->header, set->root, set, table);
803 return NULL; 786
787 return new;
804} 788}
805 789
806/* see if attaching q to p would be an improvement */ 790static struct ctl_dir *get_subdir(struct ctl_table_set *set,
807static void try_attach(struct ctl_table_header *p, struct ctl_table_header *q) 791 struct ctl_dir *dir, const char *name, int namelen)
808{ 792{
809 struct ctl_table *to = p->ctl_table, *by = q->ctl_table; 793 struct ctl_dir *subdir, *new = NULL;
810 struct ctl_table *next;
811 int is_better = 0;
812 int not_in_parent = !p->attached_by;
813
814 while ((next = is_branch_in(by, to)) != NULL) {
815 if (by == q->attached_by)
816 is_better = 1;
817 if (to == p->attached_by)
818 not_in_parent = 1;
819 by = by->child;
820 to = next->child;
821 }
822 794
823 if (is_better && not_in_parent) { 795 spin_lock(&sysctl_lock);
824 q->attached_by = by; 796 subdir = find_subdir(dir->header.set, dir, name, namelen);
825 q->attached_to = to; 797 if (!IS_ERR(subdir))
826 q->parent = p; 798 goto found;
799 if ((PTR_ERR(subdir) == -ENOENT) && set != dir->header.set)
800 subdir = find_subdir(set, dir, name, namelen);
801 if (!IS_ERR(subdir))
802 goto found;
803 if (PTR_ERR(subdir) != -ENOENT)
804 goto failed;
805
806 spin_unlock(&sysctl_lock);
807 new = new_dir(set, name, namelen);
808 spin_lock(&sysctl_lock);
809 subdir = ERR_PTR(-ENOMEM);
810 if (!new)
811 goto failed;
812
813 subdir = find_subdir(set, dir, name, namelen);
814 if (!IS_ERR(subdir))
815 goto found;
816 if (PTR_ERR(subdir) != -ENOENT)
817 goto failed;
818
819 insert_header(dir, &new->header);
820 subdir = new;
821found:
822 subdir->header.nreg++;
823failed:
824 if (unlikely(IS_ERR(subdir))) {
825 printk(KERN_ERR "sysctl could not get directory: %*.*s %ld\n",
826 namelen, namelen, name, PTR_ERR(subdir));
827 } 827 }
828 drop_sysctl_table(&dir->header);
829 if (new)
830 drop_sysctl_table(&new->header);
831 spin_unlock(&sysctl_lock);
832 return subdir;
828} 833}
829 834
830static int sysctl_check_table_dups(const char *path, struct ctl_table *old, 835static int sysctl_check_table_dups(const char *path, struct ctl_table *old,
@@ -846,24 +851,14 @@ static int sysctl_check_table_dups(const char *path, struct ctl_table *old,
846} 851}
847 852
848static int sysctl_check_dups(struct nsproxy *namespaces, 853static int sysctl_check_dups(struct nsproxy *namespaces,
849 struct ctl_table_header *header, 854 struct ctl_dir *dir,
850 const char *path, struct ctl_table *table) 855 const char *path, struct ctl_table *table)
851{ 856{
852 struct ctl_table_root *root; 857 struct ctl_table_root *root;
853 struct ctl_table_set *set; 858 struct ctl_table_set *set;
854 struct ctl_table_header *dir_head, *head; 859 struct ctl_table_header *head;
855 struct ctl_table *dir_table;
856 int error = 0; 860 int error = 0;
857 861
858 /* No dups if we are the only member of our directory */
859 if (header->attached_by != table)
860 return 0;
861
862 dir_head = header->parent;
863 dir_table = header->attached_to;
864
865 error = sysctl_check_table_dups(path, dir_table, table);
866
867 root = &sysctl_table_root; 862 root = &sysctl_table_root;
868 do { 863 do {
869 set = lookup_header_set(root, namespaces); 864 set = lookup_header_set(root, namespaces);
@@ -871,9 +866,9 @@ static int sysctl_check_dups(struct nsproxy *namespaces,
871 list_for_each_entry(head, &set->list, ctl_entry) { 866 list_for_each_entry(head, &set->list, ctl_entry) {
872 if (head->unregistering) 867 if (head->unregistering)
873 continue; 868 continue;
874 if (head->attached_to != dir_table) 869 if (head->parent != dir)
875 continue; 870 continue;
876 error = sysctl_check_table_dups(path, head->attached_by, 871 error = sysctl_check_table_dups(path, head->ctl_table,
877 table); 872 table);
878 } 873 }
879 root = list_entry(root->root_list.next, 874 root = list_entry(root->root_list.next,
@@ -977,47 +972,25 @@ struct ctl_table_header *__register_sysctl_table(
977 const char *path, struct ctl_table *table) 972 const char *path, struct ctl_table *table)
978{ 973{
979 struct ctl_table_header *header; 974 struct ctl_table_header *header;
980 struct ctl_table *new, **prevp;
981 const char *name, *nextname; 975 const char *name, *nextname;
982 unsigned int npath = 0;
983 struct ctl_table_set *set; 976 struct ctl_table_set *set;
984 size_t path_bytes = 0; 977 struct ctl_dir *dir;
985 char *new_name;
986
987 /* Count the path components */
988 for (name = path; name; name = nextname) {
989 int namelen;
990 nextname = strchr(name, '/');
991 if (nextname) {
992 namelen = nextname - name;
993 nextname++;
994 } else {
995 namelen = strlen(name);
996 }
997 if (namelen == 0)
998 continue;
999 path_bytes += namelen + 1;
1000 npath++;
1001 }
1002 978
1003 /* 979 header = kzalloc(sizeof(struct ctl_table_header), GFP_KERNEL);
1004 * For each path component, allocate a 2-element ctl_table array.
1005 * The first array element will be filled with the sysctl entry
1006 * for this, the second will be the sentinel (procname == 0).
1007 *
1008 * We allocate everything in one go so that we don't have to
1009 * worry about freeing additional memory in unregister_sysctl_table.
1010 */
1011 header = kzalloc(sizeof(struct ctl_table_header) + path_bytes +
1012 (2 * npath * sizeof(struct ctl_table)), GFP_KERNEL);
1013 if (!header) 980 if (!header)
1014 return NULL; 981 return NULL;
1015 982
1016 new = (struct ctl_table *) (header + 1); 983 init_header(header, root, NULL, table);
1017 new_name = (char *)(new + (2 * npath)); 984 if (sysctl_check_table(path, table))
985 goto fail;
986
987 spin_lock(&sysctl_lock);
988 header->set = set = lookup_header_set(root, namespaces);
989 dir = &sysctl_root_dir;
990 dir->header.nreg++;
991 spin_unlock(&sysctl_lock);
1018 992
1019 /* Now connect the dots */ 993 /* Find the directory for the ctl_table */
1020 prevp = &header->ctl_table;
1021 for (name = path; name; name = nextname) { 994 for (name = path; name; name = nextname) {
1022 int namelen; 995 int namelen;
1023 nextname = strchr(name, '/'); 996 nextname = strchr(name, '/');
@@ -1029,51 +1002,21 @@ struct ctl_table_header *__register_sysctl_table(
1029 } 1002 }
1030 if (namelen == 0) 1003 if (namelen == 0)
1031 continue; 1004 continue;
1032 memcpy(new_name, name, namelen);
1033 new_name[namelen] = '\0';
1034
1035 new->procname = new_name;
1036 new->mode = 0555;
1037
1038 *prevp = new;
1039 prevp = &new->child;
1040 1005
1041 new += 2; 1006 dir = get_subdir(set, dir, name, namelen);
1042 new_name += namelen + 1; 1007 if (IS_ERR(dir))
1008 goto fail;
1043 } 1009 }
1044 *prevp = table;
1045
1046 init_header(header, root, NULL, table);
1047 if (sysctl_check_table(path, table))
1048 goto fail;
1049
1050 spin_lock(&sysctl_lock); 1010 spin_lock(&sysctl_lock);
1051 header->set = lookup_header_set(root, namespaces); 1011 if (sysctl_check_dups(namespaces, dir, path, table))
1052 header->attached_by = header->ctl_table; 1012 goto fail_put_dir_locked;
1053 header->attached_to = &root_table[1]; 1013 insert_header(dir, header);
1054 header->parent = &root_table_header; 1014 drop_sysctl_table(&dir->header);
1055 set = header->set;
1056 root = header->root;
1057 for (;;) {
1058 struct ctl_table_header *p;
1059 list_for_each_entry(p, &set->list, ctl_entry) {
1060 if (p->unregistering)
1061 continue;
1062 try_attach(p, header);
1063 }
1064 if (root == &sysctl_table_root)
1065 break;
1066 root = list_entry(root->root_list.prev,
1067 struct ctl_table_root, root_list);
1068 set = lookup_header_set(root, namespaces);
1069 }
1070 if (sysctl_check_dups(namespaces, header, path, table))
1071 goto fail_locked;
1072 insert_header(header);
1073 spin_unlock(&sysctl_lock); 1015 spin_unlock(&sysctl_lock);
1074 1016
1075 return header; 1017 return header;
1076fail_locked: 1018fail_put_dir_locked:
1019 drop_sysctl_table(&dir->header);
1077 spin_unlock(&sysctl_lock); 1020 spin_unlock(&sysctl_lock);
1078fail: 1021fail:
1079 kfree(header); 1022 kfree(header);
@@ -1299,16 +1242,17 @@ EXPORT_SYMBOL(register_sysctl_table);
1299 1242
1300static void drop_sysctl_table(struct ctl_table_header *header) 1243static void drop_sysctl_table(struct ctl_table_header *header)
1301{ 1244{
1245 struct ctl_dir *parent = header->parent;
1246
1302 if (--header->nreg) 1247 if (--header->nreg)
1303 return; 1248 return;
1304 1249
1305 start_unregistering(header); 1250 start_unregistering(header);
1306 if (!--header->parent->count) {
1307 WARN_ON(1);
1308 kfree_rcu(header->parent, rcu);
1309 }
1310 if (!--header->count) 1251 if (!--header->count)
1311 kfree_rcu(header, rcu); 1252 kfree_rcu(header, rcu);
1253
1254 if (parent)
1255 drop_sysctl_table(&parent->header);
1312} 1256}
1313 1257
1314/** 1258/**