diff options
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r-- | kernel/sysctl.c | 37 |
1 files changed, 36 insertions, 1 deletions
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 | ||
1401 | void sysctl_head_get(struct ctl_table_header *head) | ||
1402 | { | ||
1403 | spin_lock(&sysctl_lock); | ||
1404 | head->count++; | ||
1405 | spin_unlock(&sysctl_lock); | ||
1406 | } | ||
1407 | |||
1408 | void 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 | |||
1416 | struct 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 | |||
1398 | void sysctl_head_finish(struct ctl_table_header *head) | 1427 | void 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 | ||
1841 | void setup_sysctl_set(struct ctl_table_set *p, | 1872 | void 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 | ||
1903 | void sysctl_head_put(struct ctl_table_header *head) | ||
1904 | { | ||
1905 | } | ||
1906 | |||
1872 | #endif /* CONFIG_SYSCTL */ | 1907 | #endif /* CONFIG_SYSCTL */ |
1873 | 1908 | ||
1874 | /* | 1909 | /* |