aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sysctl.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-09-22 07:08:57 -0400
committerIngo Molnar <mingo@elte.hu>2008-09-22 07:08:57 -0400
commit0b88641f1bafdbd087d5e63987a30cc0eadd63b9 (patch)
tree81dcf756db373444140bb2623584710c628e3048 /kernel/sysctl.c
parentfbdbf709938d155c719c76b9894d28342632c797 (diff)
parent72d31053f62c4bc464c2783974926969614a8649 (diff)
Merge commit 'v2.6.27-rc7' into x86/debug
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r--kernel/sysctl.c183
1 files changed, 161 insertions, 22 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 2a7b9d88706b..50ec0886fa3d 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -43,6 +43,7 @@
43#include <linux/limits.h> 43#include <linux/limits.h>
44#include <linux/dcache.h> 44#include <linux/dcache.h>
45#include <linux/syscalls.h> 45#include <linux/syscalls.h>
46#include <linux/vmstat.h>
46#include <linux/nfs_fs.h> 47#include <linux/nfs_fs.h>
47#include <linux/acpi.h> 48#include <linux/acpi.h>
48#include <linux/reboot.h> 49#include <linux/reboot.h>
@@ -80,7 +81,6 @@ extern int sysctl_drop_caches;
80extern int percpu_pagelist_fraction; 81extern int percpu_pagelist_fraction;
81extern int compat_log; 82extern int compat_log;
82extern int maps_protect; 83extern int maps_protect;
83extern int sysctl_stat_interval;
84extern int latencytop_enabled; 84extern int latencytop_enabled;
85extern int sysctl_nr_open_min, sysctl_nr_open_max; 85extern int sysctl_nr_open_min, sysctl_nr_open_max;
86#ifdef CONFIG_RCU_TORTURE_TEST 86#ifdef CONFIG_RCU_TORTURE_TEST
@@ -159,13 +159,15 @@ static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *
159static struct ctl_table root_table[]; 159static struct ctl_table root_table[];
160static struct ctl_table_root sysctl_table_root; 160static struct ctl_table_root sysctl_table_root;
161static struct ctl_table_header root_table_header = { 161static struct ctl_table_header root_table_header = {
162 .count = 1,
162 .ctl_table = root_table, 163 .ctl_table = root_table,
163 .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.header_list), 164 .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),
164 .root = &sysctl_table_root, 165 .root = &sysctl_table_root,
166 .set = &sysctl_table_root.default_set,
165}; 167};
166static struct ctl_table_root sysctl_table_root = { 168static struct ctl_table_root sysctl_table_root = {
167 .root_list = LIST_HEAD_INIT(sysctl_table_root.root_list), 169 .root_list = LIST_HEAD_INIT(sysctl_table_root.root_list),
168 .header_list = LIST_HEAD_INIT(root_table_header.ctl_entry), 170 .default_set.list = LIST_HEAD_INIT(root_table_header.ctl_entry),
169}; 171};
170 172
171static struct ctl_table kern_table[]; 173static struct ctl_table kern_table[];
@@ -624,7 +626,7 @@ static struct ctl_table kern_table[] = {
624 { 626 {
625 .ctl_name = KERN_PRINTK_RATELIMIT, 627 .ctl_name = KERN_PRINTK_RATELIMIT,
626 .procname = "printk_ratelimit", 628 .procname = "printk_ratelimit",
627 .data = &printk_ratelimit_jiffies, 629 .data = &printk_ratelimit_state.interval,
628 .maxlen = sizeof(int), 630 .maxlen = sizeof(int),
629 .mode = 0644, 631 .mode = 0644,
630 .proc_handler = &proc_dointvec_jiffies, 632 .proc_handler = &proc_dointvec_jiffies,
@@ -633,7 +635,7 @@ static struct ctl_table kern_table[] = {
633 { 635 {
634 .ctl_name = KERN_PRINTK_RATELIMIT_BURST, 636 .ctl_name = KERN_PRINTK_RATELIMIT_BURST,
635 .procname = "printk_ratelimit_burst", 637 .procname = "printk_ratelimit_burst",
636 .data = &printk_ratelimit_burst, 638 .data = &printk_ratelimit_state.burst,
637 .maxlen = sizeof(int), 639 .maxlen = sizeof(int),
638 .mode = 0644, 640 .mode = 0644,
639 .proc_handler = &proc_dointvec, 641 .proc_handler = &proc_dointvec,
@@ -959,7 +961,7 @@ static struct ctl_table vm_table[] = {
959#ifdef CONFIG_HUGETLB_PAGE 961#ifdef CONFIG_HUGETLB_PAGE
960 { 962 {
961 .procname = "nr_hugepages", 963 .procname = "nr_hugepages",
962 .data = &max_huge_pages, 964 .data = NULL,
963 .maxlen = sizeof(unsigned long), 965 .maxlen = sizeof(unsigned long),
964 .mode = 0644, 966 .mode = 0644,
965 .proc_handler = &hugetlb_sysctl_handler, 967 .proc_handler = &hugetlb_sysctl_handler,
@@ -985,10 +987,12 @@ static struct ctl_table vm_table[] = {
985 { 987 {
986 .ctl_name = CTL_UNNUMBERED, 988 .ctl_name = CTL_UNNUMBERED,
987 .procname = "nr_overcommit_hugepages", 989 .procname = "nr_overcommit_hugepages",
988 .data = &sysctl_overcommit_huge_pages, 990 .data = NULL,
989 .maxlen = sizeof(sysctl_overcommit_huge_pages), 991 .maxlen = sizeof(unsigned long),
990 .mode = 0644, 992 .mode = 0644,
991 .proc_handler = &hugetlb_overcommit_handler, 993 .proc_handler = &hugetlb_overcommit_handler,
994 .extra1 = (void *)&hugetlb_zero,
995 .extra2 = (void *)&hugetlb_infinity,
992 }, 996 },
993#endif 997#endif
994 { 998 {
@@ -1384,6 +1388,9 @@ static void start_unregistering(struct ctl_table_header *p)
1384 spin_unlock(&sysctl_lock); 1388 spin_unlock(&sysctl_lock);
1385 wait_for_completion(&wait); 1389 wait_for_completion(&wait);
1386 spin_lock(&sysctl_lock); 1390 spin_lock(&sysctl_lock);
1391 } else {
1392 /* anything non-NULL; we'll never dereference it */
1393 p->unregistering = ERR_PTR(-EINVAL);
1387 } 1394 }
1388 /* 1395 /*
1389 * do not remove from the list until nobody holds it; walking the 1396 * do not remove from the list until nobody holds it; walking the
@@ -1392,6 +1399,32 @@ static void start_unregistering(struct ctl_table_header *p)
1392 list_del_init(&p->ctl_entry); 1399 list_del_init(&p->ctl_entry);
1393} 1400}
1394 1401
1402void sysctl_head_get(struct ctl_table_header *head)
1403{
1404 spin_lock(&sysctl_lock);
1405 head->count++;
1406 spin_unlock(&sysctl_lock);
1407}
1408
1409void sysctl_head_put(struct ctl_table_header *head)
1410{
1411 spin_lock(&sysctl_lock);
1412 if (!--head->count)
1413 kfree(head);
1414 spin_unlock(&sysctl_lock);
1415}
1416
1417struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head)
1418{
1419 if (!head)
1420 BUG();
1421 spin_lock(&sysctl_lock);
1422 if (!use_table(head))
1423 head = ERR_PTR(-ENOENT);
1424 spin_unlock(&sysctl_lock);
1425 return head;
1426}
1427
1395void sysctl_head_finish(struct ctl_table_header *head) 1428void sysctl_head_finish(struct ctl_table_header *head)
1396{ 1429{
1397 if (!head) 1430 if (!head)
@@ -1401,14 +1434,20 @@ void sysctl_head_finish(struct ctl_table_header *head)
1401 spin_unlock(&sysctl_lock); 1434 spin_unlock(&sysctl_lock);
1402} 1435}
1403 1436
1437static struct ctl_table_set *
1438lookup_header_set(struct ctl_table_root *root, struct nsproxy *namespaces)
1439{
1440 struct ctl_table_set *set = &root->default_set;
1441 if (root->lookup)
1442 set = root->lookup(root, namespaces);
1443 return set;
1444}
1445
1404static struct list_head * 1446static struct list_head *
1405lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces) 1447lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces)
1406{ 1448{
1407 struct list_head *header_list; 1449 struct ctl_table_set *set = lookup_header_set(root, namespaces);
1408 header_list = &root->header_list; 1450 return &set->list;
1409 if (root->lookup)
1410 header_list = root->lookup(root, namespaces);
1411 return header_list;
1412} 1451}
1413 1452
1414struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces, 1453struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
@@ -1478,9 +1517,9 @@ static int do_sysctl_strategy(struct ctl_table_root *root,
1478 int op = 0, rc; 1517 int op = 0, rc;
1479 1518
1480 if (oldval) 1519 if (oldval)
1481 op |= 004; 1520 op |= MAY_READ;
1482 if (newval) 1521 if (newval)
1483 op |= 002; 1522 op |= MAY_WRITE;
1484 if (sysctl_perm(root, table, op)) 1523 if (sysctl_perm(root, table, op))
1485 return -EPERM; 1524 return -EPERM;
1486 1525
@@ -1522,7 +1561,7 @@ repeat:
1522 if (n == table->ctl_name) { 1561 if (n == table->ctl_name) {
1523 int error; 1562 int error;
1524 if (table->child) { 1563 if (table->child) {
1525 if (sysctl_perm(root, table, 001)) 1564 if (sysctl_perm(root, table, MAY_EXEC))
1526 return -EPERM; 1565 return -EPERM;
1527 name++; 1566 name++;
1528 nlen--; 1567 nlen--;
@@ -1597,7 +1636,7 @@ static int test_perm(int mode, int op)
1597 mode >>= 6; 1636 mode >>= 6;
1598 else if (in_egroup_p(0)) 1637 else if (in_egroup_p(0))
1599 mode >>= 3; 1638 mode >>= 3;
1600 if ((mode & op & 0007) == op) 1639 if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0)
1601 return 0; 1640 return 0;
1602 return -EACCES; 1641 return -EACCES;
1603} 1642}
@@ -1607,7 +1646,7 @@ int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
1607 int error; 1646 int error;
1608 int mode; 1647 int mode;
1609 1648
1610 error = security_sysctl(table, op); 1649 error = security_sysctl(table, op & (MAY_READ | MAY_WRITE | MAY_EXEC));
1611 if (error) 1650 if (error)
1612 return error; 1651 return error;
1613 1652
@@ -1642,6 +1681,54 @@ static __init int sysctl_init(void)
1642 1681
1643core_initcall(sysctl_init); 1682core_initcall(sysctl_init);
1644 1683
1684static struct ctl_table *is_branch_in(struct ctl_table *branch,
1685 struct ctl_table *table)
1686{
1687 struct ctl_table *p;
1688 const char *s = branch->procname;
1689
1690 /* branch should have named subdirectory as its first element */
1691 if (!s || !branch->child)
1692 return NULL;
1693
1694 /* ... and nothing else */
1695 if (branch[1].procname || branch[1].ctl_name)
1696 return NULL;
1697
1698 /* table should contain subdirectory with the same name */
1699 for (p = table; p->procname || p->ctl_name; p++) {
1700 if (!p->child)
1701 continue;
1702 if (p->procname && strcmp(p->procname, s) == 0)
1703 return p;
1704 }
1705 return NULL;
1706}
1707
1708/* see if attaching q to p would be an improvement */
1709static void try_attach(struct ctl_table_header *p, struct ctl_table_header *q)
1710{
1711 struct ctl_table *to = p->ctl_table, *by = q->ctl_table;
1712 struct ctl_table *next;
1713 int is_better = 0;
1714 int not_in_parent = !p->attached_by;
1715
1716 while ((next = is_branch_in(by, to)) != NULL) {
1717 if (by == q->attached_by)
1718 is_better = 1;
1719 if (to == p->attached_by)
1720 not_in_parent = 1;
1721 by = by->child;
1722 to = next->child;
1723 }
1724
1725 if (is_better && not_in_parent) {
1726 q->attached_by = by;
1727 q->attached_to = to;
1728 q->parent = p;
1729 }
1730}
1731
1645/** 1732/**
1646 * __register_sysctl_paths - register a sysctl hierarchy 1733 * __register_sysctl_paths - register a sysctl hierarchy
1647 * @root: List of sysctl headers to register on 1734 * @root: List of sysctl headers to register on
@@ -1718,10 +1805,10 @@ struct ctl_table_header *__register_sysctl_paths(
1718 struct nsproxy *namespaces, 1805 struct nsproxy *namespaces,
1719 const struct ctl_path *path, struct ctl_table *table) 1806 const struct ctl_path *path, struct ctl_table *table)
1720{ 1807{
1721 struct list_head *header_list;
1722 struct ctl_table_header *header; 1808 struct ctl_table_header *header;
1723 struct ctl_table *new, **prevp; 1809 struct ctl_table *new, **prevp;
1724 unsigned int n, npath; 1810 unsigned int n, npath;
1811 struct ctl_table_set *set;
1725 1812
1726 /* Count the path components */ 1813 /* Count the path components */
1727 for (npath = 0; path[npath].ctl_name || path[npath].procname; ++npath) 1814 for (npath = 0; path[npath].ctl_name || path[npath].procname; ++npath)
@@ -1763,6 +1850,7 @@ struct ctl_table_header *__register_sysctl_paths(
1763 header->unregistering = NULL; 1850 header->unregistering = NULL;
1764 header->root = root; 1851 header->root = root;
1765 sysctl_set_parent(NULL, header->ctl_table); 1852 sysctl_set_parent(NULL, header->ctl_table);
1853 header->count = 1;
1766#ifdef CONFIG_SYSCTL_SYSCALL_CHECK 1854#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
1767 if (sysctl_check_table(namespaces, header->ctl_table)) { 1855 if (sysctl_check_table(namespaces, header->ctl_table)) {
1768 kfree(header); 1856 kfree(header);
@@ -1770,8 +1858,20 @@ struct ctl_table_header *__register_sysctl_paths(
1770 } 1858 }
1771#endif 1859#endif
1772 spin_lock(&sysctl_lock); 1860 spin_lock(&sysctl_lock);
1773 header_list = lookup_header_list(root, namespaces); 1861 header->set = lookup_header_set(root, namespaces);
1774 list_add_tail(&header->ctl_entry, header_list); 1862 header->attached_by = header->ctl_table;
1863 header->attached_to = root_table;
1864 header->parent = &root_table_header;
1865 for (set = header->set; set; set = set->parent) {
1866 struct ctl_table_header *p;
1867 list_for_each_entry(p, &set->list, ctl_entry) {
1868 if (p->unregistering)
1869 continue;
1870 try_attach(p, header);
1871 }
1872 }
1873 header->parent->count++;
1874 list_add_tail(&header->ctl_entry, &header->set->list);
1775 spin_unlock(&sysctl_lock); 1875 spin_unlock(&sysctl_lock);
1776 1876
1777 return header; 1877 return header;
@@ -1826,8 +1926,37 @@ void unregister_sysctl_table(struct ctl_table_header * header)
1826 1926
1827 spin_lock(&sysctl_lock); 1927 spin_lock(&sysctl_lock);
1828 start_unregistering(header); 1928 start_unregistering(header);
1929 if (!--header->parent->count) {
1930 WARN_ON(1);
1931 kfree(header->parent);
1932 }
1933 if (!--header->count)
1934 kfree(header);
1935 spin_unlock(&sysctl_lock);
1936}
1937
1938int sysctl_is_seen(struct ctl_table_header *p)
1939{
1940 struct ctl_table_set *set = p->set;
1941 int res;
1942 spin_lock(&sysctl_lock);
1943 if (p->unregistering)
1944 res = 0;
1945 else if (!set->is_seen)
1946 res = 1;
1947 else
1948 res = set->is_seen(set);
1829 spin_unlock(&sysctl_lock); 1949 spin_unlock(&sysctl_lock);
1830 kfree(header); 1950 return res;
1951}
1952
1953void setup_sysctl_set(struct ctl_table_set *p,
1954 struct ctl_table_set *parent,
1955 int (*is_seen)(struct ctl_table_set *))
1956{
1957 INIT_LIST_HEAD(&p->list);
1958 p->parent = parent ? parent : &sysctl_table_root.default_set;
1959 p->is_seen = is_seen;
1831} 1960}
1832 1961
1833#else /* !CONFIG_SYSCTL */ 1962#else /* !CONFIG_SYSCTL */
@@ -1846,6 +1975,16 @@ void unregister_sysctl_table(struct ctl_table_header * table)
1846{ 1975{
1847} 1976}
1848 1977
1978void setup_sysctl_set(struct ctl_table_set *p,
1979 struct ctl_table_set *parent,
1980 int (*is_seen)(struct ctl_table_set *))
1981{
1982}
1983
1984void sysctl_head_put(struct ctl_table_header *head)
1985{
1986}
1987
1849#endif /* CONFIG_SYSCTL */ 1988#endif /* CONFIG_SYSCTL */
1850 1989
1851/* 1990/*