aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sysctl.h6
-rw-r--r--kernel/sysctl.c37
2 files changed, 42 insertions, 1 deletions
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index c1e0cf408af9..956264d09ba0 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -957,6 +957,11 @@ extern void setup_sysctl_set(struct ctl_table_set *p,
957 struct ctl_table_set *parent, 957 struct ctl_table_set *parent,
958 int (*is_seen)(struct ctl_table_set *)); 958 int (*is_seen)(struct ctl_table_set *));
959 959
960struct ctl_table_header;
961
962extern void sysctl_head_get(struct ctl_table_header *);
963extern void sysctl_head_put(struct ctl_table_header *);
964extern struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *);
960extern struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev); 965extern struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev);
961extern struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces, 966extern struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
962 struct ctl_table_header *prev); 967 struct ctl_table_header *prev);
@@ -1073,6 +1078,7 @@ struct ctl_table_header
1073 struct ctl_table *ctl_table; 1078 struct ctl_table *ctl_table;
1074 struct list_head ctl_entry; 1079 struct list_head ctl_entry;
1075 int used; 1080 int used;
1081 int count;
1076 struct completion *unregistering; 1082 struct completion *unregistering;
1077 struct ctl_table *ctl_table_arg; 1083 struct ctl_table *ctl_table_arg;
1078 struct ctl_table_root *root; 1084 struct ctl_table_root *root;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 8ee4a0619fbb..60d9357e7172 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1387,6 +1387,9 @@ static void start_unregistering(struct ctl_table_header *p)
1387 spin_unlock(&sysctl_lock); 1387 spin_unlock(&sysctl_lock);
1388 wait_for_completion(&wait); 1388 wait_for_completion(&wait);
1389 spin_lock(&sysctl_lock); 1389 spin_lock(&sysctl_lock);
1390 } else {
1391 /* anything non-NULL; we'll never dereference it */
1392 p->unregistering = ERR_PTR(-EINVAL);
1390 } 1393 }
1391 /* 1394 /*
1392 * do not remove from the list until nobody holds it; walking the 1395 * do not remove from the list until nobody holds it; walking the
@@ -1395,6 +1398,32 @@ static void start_unregistering(struct ctl_table_header *p)
1395 list_del_init(&p->ctl_entry); 1398 list_del_init(&p->ctl_entry);
1396} 1399}
1397 1400
1401void sysctl_head_get(struct ctl_table_header *head)
1402{
1403 spin_lock(&sysctl_lock);
1404 head->count++;
1405 spin_unlock(&sysctl_lock);
1406}
1407
1408void sysctl_head_put(struct ctl_table_header *head)
1409{
1410 spin_lock(&sysctl_lock);
1411 if (!--head->count)
1412 kfree(head);
1413 spin_unlock(&sysctl_lock);
1414}
1415
1416struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head)
1417{
1418 if (!head)
1419 BUG();
1420 spin_lock(&sysctl_lock);
1421 if (!use_table(head))
1422 head = ERR_PTR(-ENOENT);
1423 spin_unlock(&sysctl_lock);
1424 return head;
1425}
1426
1398void sysctl_head_finish(struct ctl_table_header *head) 1427void sysctl_head_finish(struct ctl_table_header *head)
1399{ 1428{
1400 if (!head) 1429 if (!head)
@@ -1771,6 +1800,7 @@ struct ctl_table_header *__register_sysctl_paths(
1771 header->unregistering = NULL; 1800 header->unregistering = NULL;
1772 header->root = root; 1801 header->root = root;
1773 sysctl_set_parent(NULL, header->ctl_table); 1802 sysctl_set_parent(NULL, header->ctl_table);
1803 header->count = 1;
1774#ifdef CONFIG_SYSCTL_SYSCALL_CHECK 1804#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
1775 if (sysctl_check_table(namespaces, header->ctl_table)) { 1805 if (sysctl_check_table(namespaces, header->ctl_table)) {
1776 kfree(header); 1806 kfree(header);
@@ -1834,8 +1864,9 @@ void unregister_sysctl_table(struct ctl_table_header * header)
1834 1864
1835 spin_lock(&sysctl_lock); 1865 spin_lock(&sysctl_lock);
1836 start_unregistering(header); 1866 start_unregistering(header);
1867 if (!--header->count)
1868 kfree(header);
1837 spin_unlock(&sysctl_lock); 1869 spin_unlock(&sysctl_lock);
1838 kfree(header);
1839} 1870}
1840 1871
1841void setup_sysctl_set(struct ctl_table_set *p, 1872void setup_sysctl_set(struct ctl_table_set *p,
@@ -1869,6 +1900,10 @@ void setup_sysctl_set(struct ctl_table_set *p,
1869{ 1900{
1870} 1901}
1871 1902
1903void sysctl_head_put(struct ctl_table_header *head)
1904{
1905}
1906
1872#endif /* CONFIG_SYSCTL */ 1907#endif /* CONFIG_SYSCTL */
1873 1908
1874/* 1909/*