aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sysctl.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-07-27 07:40:08 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-27 07:40:08 -0400
commit15d3b4a26291c170563e2b25ded5de1324f93959 (patch)
tree9bea548a7de5215c58a091d58f4eefdb92349f2c /kernel/sysctl.c
parent2c3abab7c95295f319dc8899b74cbd60140fcdfb (diff)
parent8be1a6d6c77ab4532e4476fdb8177030ef48b52c (diff)
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r--kernel/sysctl.c200
1 files changed, 174 insertions, 26 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index b859e6b5a767..911d846f0503 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
@@ -88,12 +88,13 @@ extern int rcutorture_runnable;
88#endif /* #ifdef CONFIG_RCU_TORTURE_TEST */ 88#endif /* #ifdef CONFIG_RCU_TORTURE_TEST */
89 89
90/* Constants used for minimum and maximum */ 90/* Constants used for minimum and maximum */
91#if defined(CONFIG_DETECT_SOFTLOCKUP) || defined(CONFIG_HIGHMEM) 91#if defined(CONFIG_HIGHMEM) || defined(CONFIG_DETECT_SOFTLOCKUP)
92static int one = 1; 92static int one = 1;
93#endif 93#endif
94 94
95#ifdef CONFIG_DETECT_SOFTLOCKUP 95#ifdef CONFIG_DETECT_SOFTLOCKUP
96static int sixty = 60; 96static int sixty = 60;
97static int neg_one = -1;
97#endif 98#endif
98 99
99#ifdef CONFIG_MMU 100#ifdef CONFIG_MMU
@@ -159,12 +160,13 @@ static struct ctl_table root_table[];
159static struct ctl_table_root sysctl_table_root; 160static struct ctl_table_root sysctl_table_root;
160static struct ctl_table_header root_table_header = { 161static struct ctl_table_header root_table_header = {
161 .ctl_table = root_table, 162 .ctl_table = root_table,
162 .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.header_list), 163 .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),
163 .root = &sysctl_table_root, 164 .root = &sysctl_table_root,
165 .set = &sysctl_table_root.default_set,
164}; 166};
165static struct ctl_table_root sysctl_table_root = { 167static struct ctl_table_root sysctl_table_root = {
166 .root_list = LIST_HEAD_INIT(sysctl_table_root.root_list), 168 .root_list = LIST_HEAD_INIT(sysctl_table_root.root_list),
167 .header_list = LIST_HEAD_INIT(root_table_header.ctl_entry), 169 .default_set.list = LIST_HEAD_INIT(root_table_header.ctl_entry),
168}; 170};
169 171
170static struct ctl_table kern_table[]; 172static struct ctl_table kern_table[];
@@ -623,7 +625,7 @@ static struct ctl_table kern_table[] = {
623 { 625 {
624 .ctl_name = KERN_PRINTK_RATELIMIT, 626 .ctl_name = KERN_PRINTK_RATELIMIT,
625 .procname = "printk_ratelimit", 627 .procname = "printk_ratelimit",
626 .data = &printk_ratelimit_jiffies, 628 .data = &printk_ratelimit_state.interval,
627 .maxlen = sizeof(int), 629 .maxlen = sizeof(int),
628 .mode = 0644, 630 .mode = 0644,
629 .proc_handler = &proc_dointvec_jiffies, 631 .proc_handler = &proc_dointvec_jiffies,
@@ -632,7 +634,7 @@ static struct ctl_table kern_table[] = {
632 { 634 {
633 .ctl_name = KERN_PRINTK_RATELIMIT_BURST, 635 .ctl_name = KERN_PRINTK_RATELIMIT_BURST,
634 .procname = "printk_ratelimit_burst", 636 .procname = "printk_ratelimit_burst",
635 .data = &printk_ratelimit_burst, 637 .data = &printk_ratelimit_state.burst,
636 .maxlen = sizeof(int), 638 .maxlen = sizeof(int),
637 .mode = 0644, 639 .mode = 0644,
638 .proc_handler = &proc_dointvec, 640 .proc_handler = &proc_dointvec,
@@ -739,13 +741,24 @@ static struct ctl_table kern_table[] = {
739#ifdef CONFIG_DETECT_SOFTLOCKUP 741#ifdef CONFIG_DETECT_SOFTLOCKUP
740 { 742 {
741 .ctl_name = CTL_UNNUMBERED, 743 .ctl_name = CTL_UNNUMBERED,
744 .procname = "softlockup_panic",
745 .data = &softlockup_panic,
746 .maxlen = sizeof(int),
747 .mode = 0644,
748 .proc_handler = &proc_dointvec_minmax,
749 .strategy = &sysctl_intvec,
750 .extra1 = &zero,
751 .extra2 = &one,
752 },
753 {
754 .ctl_name = CTL_UNNUMBERED,
742 .procname = "softlockup_thresh", 755 .procname = "softlockup_thresh",
743 .data = &softlockup_thresh, 756 .data = &softlockup_thresh,
744 .maxlen = sizeof(unsigned long), 757 .maxlen = sizeof(int),
745 .mode = 0644, 758 .mode = 0644,
746 .proc_handler = &proc_doulongvec_minmax, 759 .proc_handler = &proc_dointvec_minmax,
747 .strategy = &sysctl_intvec, 760 .strategy = &sysctl_intvec,
748 .extra1 = &one, 761 .extra1 = &neg_one,
749 .extra2 = &sixty, 762 .extra2 = &sixty,
750 }, 763 },
751 { 764 {
@@ -947,7 +960,7 @@ static struct ctl_table vm_table[] = {
947#ifdef CONFIG_HUGETLB_PAGE 960#ifdef CONFIG_HUGETLB_PAGE
948 { 961 {
949 .procname = "nr_hugepages", 962 .procname = "nr_hugepages",
950 .data = &max_huge_pages, 963 .data = NULL,
951 .maxlen = sizeof(unsigned long), 964 .maxlen = sizeof(unsigned long),
952 .mode = 0644, 965 .mode = 0644,
953 .proc_handler = &hugetlb_sysctl_handler, 966 .proc_handler = &hugetlb_sysctl_handler,
@@ -973,10 +986,12 @@ static struct ctl_table vm_table[] = {
973 { 986 {
974 .ctl_name = CTL_UNNUMBERED, 987 .ctl_name = CTL_UNNUMBERED,
975 .procname = "nr_overcommit_hugepages", 988 .procname = "nr_overcommit_hugepages",
976 .data = &sysctl_overcommit_huge_pages, 989 .data = NULL,
977 .maxlen = sizeof(sysctl_overcommit_huge_pages), 990 .maxlen = sizeof(unsigned long),
978 .mode = 0644, 991 .mode = 0644,
979 .proc_handler = &hugetlb_overcommit_handler, 992 .proc_handler = &hugetlb_overcommit_handler,
993 .extra1 = (void *)&hugetlb_zero,
994 .extra2 = (void *)&hugetlb_infinity,
980 }, 995 },
981#endif 996#endif
982 { 997 {
@@ -1372,6 +1387,9 @@ static void start_unregistering(struct ctl_table_header *p)
1372 spin_unlock(&sysctl_lock); 1387 spin_unlock(&sysctl_lock);
1373 wait_for_completion(&wait); 1388 wait_for_completion(&wait);
1374 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);
1375 } 1393 }
1376 /* 1394 /*
1377 * 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
@@ -1380,6 +1398,32 @@ static void start_unregistering(struct ctl_table_header *p)
1380 list_del_init(&p->ctl_entry); 1398 list_del_init(&p->ctl_entry);
1381} 1399}
1382 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
1383void sysctl_head_finish(struct ctl_table_header *head) 1427void sysctl_head_finish(struct ctl_table_header *head)
1384{ 1428{
1385 if (!head) 1429 if (!head)
@@ -1389,14 +1433,20 @@ void sysctl_head_finish(struct ctl_table_header *head)
1389 spin_unlock(&sysctl_lock); 1433 spin_unlock(&sysctl_lock);
1390} 1434}
1391 1435
1436static struct ctl_table_set *
1437lookup_header_set(struct ctl_table_root *root, struct nsproxy *namespaces)
1438{
1439 struct ctl_table_set *set = &root->default_set;
1440 if (root->lookup)
1441 set = root->lookup(root, namespaces);
1442 return set;
1443}
1444
1392static struct list_head * 1445static struct list_head *
1393lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces) 1446lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces)
1394{ 1447{
1395 struct list_head *header_list; 1448 struct ctl_table_set *set = lookup_header_set(root, namespaces);
1396 header_list = &root->header_list; 1449 return &set->list;
1397 if (root->lookup)
1398 header_list = root->lookup(root, namespaces);
1399 return header_list;
1400} 1450}
1401 1451
1402struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces, 1452struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
@@ -1466,9 +1516,9 @@ static int do_sysctl_strategy(struct ctl_table_root *root,
1466 int op = 0, rc; 1516 int op = 0, rc;
1467 1517
1468 if (oldval) 1518 if (oldval)
1469 op |= 004; 1519 op |= MAY_READ;
1470 if (newval) 1520 if (newval)
1471 op |= 002; 1521 op |= MAY_WRITE;
1472 if (sysctl_perm(root, table, op)) 1522 if (sysctl_perm(root, table, op))
1473 return -EPERM; 1523 return -EPERM;
1474 1524
@@ -1510,7 +1560,7 @@ repeat:
1510 if (n == table->ctl_name) { 1560 if (n == table->ctl_name) {
1511 int error; 1561 int error;
1512 if (table->child) { 1562 if (table->child) {
1513 if (sysctl_perm(root, table, 001)) 1563 if (sysctl_perm(root, table, MAY_EXEC))
1514 return -EPERM; 1564 return -EPERM;
1515 name++; 1565 name++;
1516 nlen--; 1566 nlen--;
@@ -1585,7 +1635,7 @@ static int test_perm(int mode, int op)
1585 mode >>= 6; 1635 mode >>= 6;
1586 else if (in_egroup_p(0)) 1636 else if (in_egroup_p(0))
1587 mode >>= 3; 1637 mode >>= 3;
1588 if ((mode & op & 0007) == op) 1638 if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0)
1589 return 0; 1639 return 0;
1590 return -EACCES; 1640 return -EACCES;
1591} 1641}
@@ -1595,7 +1645,7 @@ int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
1595 int error; 1645 int error;
1596 int mode; 1646 int mode;
1597 1647
1598 error = security_sysctl(table, op); 1648 error = security_sysctl(table, op & (MAY_READ | MAY_WRITE | MAY_EXEC));
1599 if (error) 1649 if (error)
1600 return error; 1650 return error;
1601 1651
@@ -1630,6 +1680,52 @@ static __init int sysctl_init(void)
1630 1680
1631core_initcall(sysctl_init); 1681core_initcall(sysctl_init);
1632 1682
1683static int is_branch_in(struct ctl_table *branch, struct ctl_table *table)
1684{
1685 struct ctl_table *p;
1686 const char *s = branch->procname;
1687
1688 /* branch should have named subdirectory as its first element */
1689 if (!s || !branch->child)
1690 return 0;
1691
1692 /* ... and nothing else */
1693 if (branch[1].procname || branch[1].ctl_name)
1694 return 0;
1695
1696 /* table should contain subdirectory with the same name */
1697 for (p = table; p->procname || p->ctl_name; p++) {
1698 if (!p->child)
1699 continue;
1700 if (p->procname && strcmp(p->procname, s) == 0)
1701 return 1;
1702 }
1703 return 0;
1704}
1705
1706/* see if attaching q to p would be an improvement */
1707static void try_attach(struct ctl_table_header *p, struct ctl_table_header *q)
1708{
1709 struct ctl_table *to = p->ctl_table, *by = q->ctl_table;
1710 int is_better = 0;
1711 int not_in_parent = !p->attached_by;
1712
1713 while (is_branch_in(by, to)) {
1714 if (by == q->attached_by)
1715 is_better = 1;
1716 if (to == p->attached_by)
1717 not_in_parent = 1;
1718 by = by->child;
1719 to = to->child;
1720 }
1721
1722 if (is_better && not_in_parent) {
1723 q->attached_by = by;
1724 q->attached_to = to;
1725 q->parent = p;
1726 }
1727}
1728
1633/** 1729/**
1634 * __register_sysctl_paths - register a sysctl hierarchy 1730 * __register_sysctl_paths - register a sysctl hierarchy
1635 * @root: List of sysctl headers to register on 1731 * @root: List of sysctl headers to register on
@@ -1706,10 +1802,10 @@ struct ctl_table_header *__register_sysctl_paths(
1706 struct nsproxy *namespaces, 1802 struct nsproxy *namespaces,
1707 const struct ctl_path *path, struct ctl_table *table) 1803 const struct ctl_path *path, struct ctl_table *table)
1708{ 1804{
1709 struct list_head *header_list;
1710 struct ctl_table_header *header; 1805 struct ctl_table_header *header;
1711 struct ctl_table *new, **prevp; 1806 struct ctl_table *new, **prevp;
1712 unsigned int n, npath; 1807 unsigned int n, npath;
1808 struct ctl_table_set *set;
1713 1809
1714 /* Count the path components */ 1810 /* Count the path components */
1715 for (npath = 0; path[npath].ctl_name || path[npath].procname; ++npath) 1811 for (npath = 0; path[npath].ctl_name || path[npath].procname; ++npath)
@@ -1751,6 +1847,7 @@ struct ctl_table_header *__register_sysctl_paths(
1751 header->unregistering = NULL; 1847 header->unregistering = NULL;
1752 header->root = root; 1848 header->root = root;
1753 sysctl_set_parent(NULL, header->ctl_table); 1849 sysctl_set_parent(NULL, header->ctl_table);
1850 header->count = 1;
1754#ifdef CONFIG_SYSCTL_SYSCALL_CHECK 1851#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
1755 if (sysctl_check_table(namespaces, header->ctl_table)) { 1852 if (sysctl_check_table(namespaces, header->ctl_table)) {
1756 kfree(header); 1853 kfree(header);
@@ -1758,8 +1855,20 @@ struct ctl_table_header *__register_sysctl_paths(
1758 } 1855 }
1759#endif 1856#endif
1760 spin_lock(&sysctl_lock); 1857 spin_lock(&sysctl_lock);
1761 header_list = lookup_header_list(root, namespaces); 1858 header->set = lookup_header_set(root, namespaces);
1762 list_add_tail(&header->ctl_entry, header_list); 1859 header->attached_by = header->ctl_table;
1860 header->attached_to = root_table;
1861 header->parent = &root_table_header;
1862 for (set = header->set; set; set = set->parent) {
1863 struct ctl_table_header *p;
1864 list_for_each_entry(p, &set->list, ctl_entry) {
1865 if (p->unregistering)
1866 continue;
1867 try_attach(p, header);
1868 }
1869 }
1870 header->parent->count++;
1871 list_add_tail(&header->ctl_entry, &header->set->list);
1763 spin_unlock(&sysctl_lock); 1872 spin_unlock(&sysctl_lock);
1764 1873
1765 return header; 1874 return header;
@@ -1814,8 +1923,37 @@ void unregister_sysctl_table(struct ctl_table_header * header)
1814 1923
1815 spin_lock(&sysctl_lock); 1924 spin_lock(&sysctl_lock);
1816 start_unregistering(header); 1925 start_unregistering(header);
1926 if (!--header->parent->count) {
1927 WARN_ON(1);
1928 kfree(header->parent);
1929 }
1930 if (!--header->count)
1931 kfree(header);
1932 spin_unlock(&sysctl_lock);
1933}
1934
1935int sysctl_is_seen(struct ctl_table_header *p)
1936{
1937 struct ctl_table_set *set = p->set;
1938 int res;
1939 spin_lock(&sysctl_lock);
1940 if (p->unregistering)
1941 res = 0;
1942 else if (!set->is_seen)
1943 res = 1;
1944 else
1945 res = set->is_seen(set);
1817 spin_unlock(&sysctl_lock); 1946 spin_unlock(&sysctl_lock);
1818 kfree(header); 1947 return res;
1948}
1949
1950void setup_sysctl_set(struct ctl_table_set *p,
1951 struct ctl_table_set *parent,
1952 int (*is_seen)(struct ctl_table_set *))
1953{
1954 INIT_LIST_HEAD(&p->list);
1955 p->parent = parent ? parent : &sysctl_table_root.default_set;
1956 p->is_seen = is_seen;
1819} 1957}
1820 1958
1821#else /* !CONFIG_SYSCTL */ 1959#else /* !CONFIG_SYSCTL */
@@ -1834,6 +1972,16 @@ void unregister_sysctl_table(struct ctl_table_header * table)
1834{ 1972{
1835} 1973}
1836 1974
1975void setup_sysctl_set(struct ctl_table_set *p,
1976 struct ctl_table_set *parent,
1977 int (*is_seen)(struct ctl_table_set *))
1978{
1979}
1980
1981void sysctl_head_put(struct ctl_table_header *head)
1982{
1983}
1984
1837#endif /* CONFIG_SYSCTL */ 1985#endif /* CONFIG_SYSCTL */
1838 1986
1839/* 1987/*