aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2008-07-15 06:33:31 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2008-07-26 20:53:11 -0400
commitae7edecc9b8810770a8e5cb9a466ea4bdcfa8401 (patch)
tree8c0a244f4aea3eca5d8edf45665266b007eb046e /kernel
parentbd7b1533cd6a68c734062aa69394bec7e2b1718e (diff)
[PATCH] sysctl: keep track of tree relationships
In a sense, that's the heart of the series. It's based on the following property of the trees we are actually asked to add: they can be split into stem that is already covered by registered trees and crown that is entirely new. IOW, if a/b and a/c/d are introduced by our tree, then a/c is also introduced by it. That allows to associate tree and table entry with each node in the union; while directory nodes might be covered by many trees, only one will cover the node by its crown. And that will allow much saner logics for /proc/sys in the next patches. This patch introduces the data structures needed to keep track of that. When adding a sysctl table, we find a "parent" one. Which is to say, find the deepest node on its stem that already is present in one of the tables from our table set or its ancestor sets. That table will be our parent and that node in it - attachment point. Add our table to list anchored in parent, have it refer the parent and contents of attachment point. Also remember where its crown lives. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sysctl.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 60d9357e7172..c9a0af887033 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1680,6 +1680,52 @@ static __init int sysctl_init(void)
1680 1680
1681core_initcall(sysctl_init); 1681core_initcall(sysctl_init);
1682 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
1683/** 1729/**
1684 * __register_sysctl_paths - register a sysctl hierarchy 1730 * __register_sysctl_paths - register a sysctl hierarchy
1685 * @root: List of sysctl headers to register on 1731 * @root: List of sysctl headers to register on
@@ -1759,6 +1805,7 @@ struct ctl_table_header *__register_sysctl_paths(
1759 struct ctl_table_header *header; 1805 struct ctl_table_header *header;
1760 struct ctl_table *new, **prevp; 1806 struct ctl_table *new, **prevp;
1761 unsigned int n, npath; 1807 unsigned int n, npath;
1808 struct ctl_table_set *set;
1762 1809
1763 /* Count the path components */ 1810 /* Count the path components */
1764 for (npath = 0; path[npath].ctl_name || path[npath].procname; ++npath) 1811 for (npath = 0; path[npath].ctl_name || path[npath].procname; ++npath)
@@ -1809,6 +1856,18 @@ struct ctl_table_header *__register_sysctl_paths(
1809#endif 1856#endif
1810 spin_lock(&sysctl_lock); 1857 spin_lock(&sysctl_lock);
1811 header->set = lookup_header_set(root, namespaces); 1858 header->set = lookup_header_set(root, namespaces);
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++;
1812 list_add_tail(&header->ctl_entry, &header->set->list); 1871 list_add_tail(&header->ctl_entry, &header->set->list);
1813 spin_unlock(&sysctl_lock); 1872 spin_unlock(&sysctl_lock);
1814 1873
@@ -1864,6 +1923,10 @@ void unregister_sysctl_table(struct ctl_table_header * header)
1864 1923
1865 spin_lock(&sysctl_lock); 1924 spin_lock(&sysctl_lock);
1866 start_unregistering(header); 1925 start_unregistering(header);
1926 if (!--header->parent->count) {
1927 WARN_ON(1);
1928 kfree(header->parent);
1929 }
1867 if (!--header->count) 1930 if (!--header->count)
1868 kfree(header); 1931 kfree(header);
1869 spin_unlock(&sysctl_lock); 1932 spin_unlock(&sysctl_lock);