* [v2 027/115] sysctl: remove .child from fs/xfs/
From: Lucian Adrian Grijincu @ 2011-05-08 22:38 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
fs/xfs/linux-2.6/xfs_sysctl.c | 22 +++++-----------------
1 files changed, 5 insertions(+), 17 deletions(-)
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/linux-2.6/xfs_sysctl.c
index ee2d2ad..95f803c 100644
--- a/fs/xfs/linux-2.6/xfs_sysctl.c
+++ b/fs/xfs/linux-2.6/xfs_sysctl.c
@@ -218,28 +218,16 @@ static ctl_table xfs_table[] = {
{}
};
-static ctl_table xfs_dir_table[] = {
- {
- .procname = "xfs",
- .mode = 0555,
- .child = xfs_table
- },
- {}
-};
-
-static ctl_table xfs_root_table[] = {
- {
- .procname = "fs",
- .mode = 0555,
- .child = xfs_dir_table
- },
- {}
+static const __initdata struct ctl_path xfs_path[] = {
+ { .procname = "fs" },
+ { .procname = "xfs" },
+ { }
};
int
xfs_sysctl_register(void)
{
- xfs_table_header = register_sysctl_table(xfs_root_table);
+ xfs_table_header = register_sysctl_paths(xfs_path, xfs_table);
if (!xfs_table_header)
return -ENOMEM;
return 0;
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 025/115] sysctl: remove .child from fs/ocfs2/nm/
From: Lucian Adrian Grijincu @ 2011-05-08 22:38 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
fs/ocfs2/stackglue.c | 36 +++++-------------------------------
1 files changed, 5 insertions(+), 31 deletions(-)
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c
index 39abf89..3cb738a 100644
--- a/fs/ocfs2/stackglue.c
+++ b/fs/ocfs2/stackglue.c
@@ -654,36 +654,10 @@ static ctl_table ocfs2_nm_table[] = {
{ }
};
-static ctl_table ocfs2_mod_table[] = {
- {
- .procname = "nm",
- .data = NULL,
- .maxlen = 0,
- .mode = 0555,
- .child = ocfs2_nm_table
- },
- { }
-};
-
-static ctl_table ocfs2_kern_table[] = {
- {
- .procname = "ocfs2",
- .data = NULL,
- .maxlen = 0,
- .mode = 0555,
- .child = ocfs2_mod_table
- },
- { }
-};
-
-static ctl_table ocfs2_root_table[] = {
- {
- .procname = "fs",
- .data = NULL,
- .maxlen = 0,
- .mode = 0555,
- .child = ocfs2_kern_table
- },
+static const __initdata struct ctl_path ocfs2_nm_path[] = {
+ { .procname = "fs" },
+ { .procname = "ocfs2" },
+ { .procname = "nm" },
{ }
};
@@ -698,7 +672,7 @@ static int __init ocfs2_stack_glue_init(void)
{
strcpy(cluster_stack_name, OCFS2_STACK_PLUGIN_O2CB);
- ocfs2_table_header = register_sysctl_table(ocfs2_root_table);
+ ocfs2_table_header = register_sysctl_paths(ocfs2_nm_path, ocfs2_nm_table);
if (!ocfs2_table_header) {
printk(KERN_ERR
"ocfs2 stack glue: unable to register sysctl\n");
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 021/115] sysctl: remove .child from fscache/
From: Lucian Adrian Grijincu @ 2011-05-08 22:38 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
fs/fscache/main.c | 15 ++++++---------
1 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/fs/fscache/main.c b/fs/fscache/main.c
index f9d8567..7f9c055 100644
--- a/fs/fscache/main.c
+++ b/fs/fscache/main.c
@@ -67,7 +67,7 @@ static int fscache_max_active_sysctl(struct ctl_table *table, int write,
return ret;
}
-ctl_table fscache_sysctls[] = {
+static ctl_table fscache_table[] = {
{
.procname = "object_max_active",
.data = &fscache_object_max_active,
@@ -87,14 +87,11 @@ ctl_table fscache_sysctls[] = {
{}
};
-ctl_table fscache_sysctls_root[] = {
- {
- .procname = "fscache",
- .mode = 0555,
- .child = fscache_sysctls,
- },
- {}
+static const __initdata struct ctl_path fscache_path[] = {
+ { .procname = "fscache" },
+ { }
};
+
#endif
/*
@@ -135,7 +132,7 @@ static int __init fscache_init(void)
#ifdef CONFIG_SYSCTL
ret = -ENOMEM;
- fscache_sysctl_header = register_sysctl_table(fscache_sysctls_root);
+ fscache_sysctl_header = register_sysctl_paths(fscache_path, fscache_table);
if (!fscache_sysctl_header)
goto error_sysctl;
#endif
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 017/115] sysctl: remove .child from kernel/sclp (s390)
From: Lucian Adrian Grijincu @ 2011-05-08 22:38 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
drivers/s390/char/sclp_async.c | 13 ++++---------
1 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/drivers/s390/char/sclp_async.c b/drivers/s390/char/sclp_async.c
index 7ad30e7..43f8b1e 100644
--- a/drivers/s390/char/sclp_async.c
+++ b/drivers/s390/char/sclp_async.c
@@ -106,14 +106,9 @@ static struct ctl_table callhome_table[] = {
{}
};
-static struct ctl_table kern_dir_table[] = {
- {
- .procname = "kernel",
- .maxlen = 0,
- .mode = 0555,
- .child = callhome_table,
- },
- {}
+static const __initdata struct ctl_path kern_path[] = {
+ { .procname = "kernel" },
+ { }
};
/*
@@ -175,7 +170,7 @@ static int __init sclp_async_init(void)
if (!(sclp_async_register.sclp_receive_mask & EVTYP_ASYNC_MASK))
goto out_sclp;
rc = -ENOMEM;
- callhome_sysctl_header = register_sysctl_table(kern_dir_table);
+ callhome_sysctl_header = register_sysctl_paths(kern_path, callhome_table);
if (!callhome_sysctl_header)
goto out_sclp;
request = kzalloc(sizeof(struct sclp_req), GFP_KERNEL);
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 011/115] sysctl: remove .child from dev/ipmi/
From: Lucian Adrian Grijincu @ 2011-05-08 22:38 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
drivers/char/ipmi/ipmi_poweroff.c | 16 ++++------------
1 files changed, 4 insertions(+), 12 deletions(-)
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index 2efa176..ac71d69 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -668,17 +668,9 @@ static ctl_table ipmi_table[] = {
{ }
};
-static ctl_table ipmi_dir_table[] = {
- { .procname = "ipmi",
- .mode = 0555,
- .child = ipmi_table },
- { }
-};
-
-static ctl_table ipmi_root_table[] = {
- { .procname = "dev",
- .mode = 0555,
- .child = ipmi_dir_table },
+static const struct ctl_path ipmi_path[] = {
+ { .procname = "dev" },
+ { .procname = "ipmi" },
{ }
};
@@ -699,7 +691,7 @@ static int __init ipmi_poweroff_init(void)
printk(KERN_INFO PFX "Power cycle is enabled.\n");
#ifdef CONFIG_PROC_FS
- ipmi_table_header = register_sysctl_table(ipmi_root_table);
+ ipmi_table_header = register_sysctl_paths(ipmi_path, ipmi_table);
if (!ipmi_table_header) {
printk(KERN_ERR PFX "Unable to register powercycle sysctl\n");
rv = -ENOMEM;
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 007/115] sysctl: remove .child from abi/vsyscall32 (x86)
From: Lucian Adrian Grijincu @ 2011-05-08 22:38 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
arch/x86/vdso/vdso32-setup.c | 14 +++++---------
1 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c
index 468d591..e6ef3b4 100644
--- a/arch/x86/vdso/vdso32-setup.c
+++ b/arch/x86/vdso/vdso32-setup.c
@@ -380,7 +380,7 @@ subsys_initcall(sysenter_setup);
/* Register vsyscall32 into the ABI table */
#include <linux/sysctl.h>
-static ctl_table abi_table2[] = {
+static ctl_table abi_table[] = {
{
.procname = "vsyscall32",
.data = &sysctl_vsyscall32,
@@ -391,18 +391,14 @@ static ctl_table abi_table2[] = {
{}
};
-static ctl_table abi_root_table2[] = {
- {
- .procname = "abi",
- .mode = 0555,
- .child = abi_table2
- },
- {}
+static const struct ctl_path abi_root_path[] = {
+ { .procname = "abi" },
+ { }
};
static __init int ia32_binfmt_init(void)
{
- register_sysctl_table(abi_root_table2);
+ register_sysctl_paths(abi_root_path, abi_table);
return 0;
}
__initcall(ia32_binfmt_init);
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 001/115] sysctl: remove .child from dev/parport/default
From: Lucian Adrian Grijincu @ 2011-05-08 22:38 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
First patch in a series that will end with a rewrite of sysctl. The
new implementation needs to get rid of the .child field of ctl_table.
Same functionality, but a little more clarity.
MAINTAINERS says parport is "Orphan" and I don't have a parallel
port. I minimally tested this patch, but I don't know who to resort to
for an ACK.
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
drivers/parport/procfs.c | 96 +++++++++++++++++++---------------------------
1 files changed, 40 insertions(+), 56 deletions(-)
diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c
index 3f56bc0..89b8b71 100644
--- a/drivers/parport/procfs.c
+++ b/drivers/parport/procfs.c
@@ -419,56 +419,6 @@ parport_device_sysctl_template = {
}
};
-struct parport_default_sysctl_table
-{
- struct ctl_table_header *sysctl_header;
- ctl_table vars[3];
- ctl_table default_dir[2];
- ctl_table parport_dir[2];
- ctl_table dev_dir[2];
-};
-
-static struct parport_default_sysctl_table
-parport_default_sysctl_table = {
- .sysctl_header = NULL,
- {
- {
- .procname = "timeslice",
- .data = &parport_default_timeslice,
- .maxlen = sizeof(parport_default_timeslice),
- .mode = 0644,
- .proc_handler = proc_doulongvec_ms_jiffies_minmax,
- .extra1 = (void*) &parport_min_timeslice_value,
- .extra2 = (void*) &parport_max_timeslice_value
- },
- {
- .procname = "spintime",
- .data = &parport_default_spintime,
- .maxlen = sizeof(parport_default_spintime),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = (void*) &parport_min_spintime_value,
- .extra2 = (void*) &parport_max_spintime_value
- },
- {}
- },
- {
- {
- .procname = "default",
- .mode = 0555,
- .child = parport_default_sysctl_table.vars
- },
- {}
- },
- {
- PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir),
- {}
- },
- {
- PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir),
- {}
- }
-};
int parport_proc_register(struct parport *port)
@@ -558,19 +508,53 @@ int parport_device_proc_unregister(struct pardevice *device)
return 0;
}
+
+static struct ctl_table_header *parport_default_sysctl_header;
+
+static struct ctl_table parport_default_sysctl_table[] = {
+ {
+ .procname = "timeslice",
+ .data = &parport_default_timeslice,
+ .maxlen = sizeof(parport_default_timeslice),
+ .mode = 0644,
+ .proc_handler = proc_doulongvec_ms_jiffies_minmax,
+ .extra1 = (void*) &parport_min_timeslice_value,
+ .extra2 = (void*) &parport_max_timeslice_value
+ },
+ {
+ .procname = "spintime",
+ .data = &parport_default_spintime,
+ .maxlen = sizeof(parport_default_spintime),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = (void*) &parport_min_spintime_value,
+ .extra2 = (void*) &parport_max_spintime_value
+ },
+ { },
+};
+
+static const __initdata struct ctl_path parport_default_path[] = {
+ { .procname = "dev" },
+ { .procname = "parport" },
+ { .procname = "default" },
+ { },
+};
+
static int __init parport_default_proc_register(void)
{
- parport_default_sysctl_table.sysctl_header =
- register_sysctl_table(parport_default_sysctl_table.dev_dir);
+ parport_default_sysctl_header =
+ register_sysctl_paths(parport_default_path,
+ parport_default_sysctl_table);
+ /* XXX: if this fails then we can't access the sysctl tables for
+ * /proc/sys/dev/parport/default/. Should the module fail to load? */
return 0;
}
static void __exit parport_default_proc_unregister(void)
{
- if (parport_default_sysctl_table.sysctl_header) {
- unregister_sysctl_table(parport_default_sysctl_table.
- sysctl_header);
- parport_default_sysctl_table.sysctl_header = NULL;
+ if (parport_default_sysctl_header) {
+ unregister_sysctl_table(parport_default_sysctl_header);
+ parport_default_sysctl_header = NULL;
}
}
--
1.7.5.134.g1c08b
^ permalink raw reply related
* Re: pull request: batman-adv 2011-05-08
From: David Miller @ 2011-05-08 22:40 UTC (permalink / raw)
To: sven-KaDOiPu9UxWEi8DpZVb4nw
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r
In-Reply-To: <1304868284-9364-1-git-send-email-sven-KaDOiPu9UxWEi8DpZVb4nw@public.gmane.org>
From: Sven Eckelmann <sven-KaDOiPu9UxWEi8DpZVb4nw@public.gmane.org>
Date: Sun, 8 May 2011 17:24:36 +0200
> Hi,
>
> I would like to propose following patches for net-next-2.6/2.6.40. They
> include minor cleanups of comments, a big rename patch s/hna/tt/, but
> also a remove some duplicated code. The spinlock which protected the
> list of possible interfaces for batman-adv was completely replaced by
> rtnl_lock because we want to be in sync with the rest of the network
> stack and the extra spinlock made everything more complex without giving
> any additional feature (and rtnl_lock was already used everywhere).
> Related to this patch is also a fix which should prevent a deadlock
> between the sysfs code and the event listener. Also the reference
> counting in find_router was fixed when an error was detected after the
> refcounter was already increased. The only feature is the support for
> multiple vlans in the bridge loop detection code.
>
> I will submit a patch to remove the atomic_dec_not_zero from main.h
> after Linus accepted the patch you already saw.
Pulled, thanks Sven.
^ permalink raw reply
* [v2 096/115] sysctl: net/ipv6/neigh: create empty dir with register_sysctl_dir
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
net/ipv6/sysctl_net_ipv6.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index 1d2d8c7..bb57ab4 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -15,8 +15,6 @@
#include <net/addrconf.h>
#include <net/inet_frag.h>
-static struct ctl_table empty[1];
-
static ctl_table ipv6_bindv6only_template[] = {
{
.procname = "bindv6only",
@@ -173,7 +171,7 @@ static struct ctl_table_header *ip6_base;
int ipv6_static_sysctl_register(void)
{
- ip6_base = register_sysctl_paths(net_ipv6_neigh_path, empty);
+ ip6_base = register_sysctl_dir(net_ipv6_neigh_path);
if (ip6_base == NULL)
return -ENOMEM;
return 0;
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 092/115] sysctl: sched: create empty dir with register_sysctl_dir
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
kernel/sched.c | 19 ++++---------------
1 files changed, 4 insertions(+), 15 deletions(-)
diff --git a/kernel/sched.c b/kernel/sched.c
index 8320365..5cda526 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -6302,16 +6302,11 @@ static void register_sched_domain_sysctl(void)
i = 0;
for_each_possible_cpu(cpu) {
- struct ctl_table *empty = kzalloc(sizeof(*empty), GFP_KERNEL);
- if (empty == NULL)
- goto unregister_sd_cpudir_headers;
sd_path[SD_PATH_CPU].procname = sd_cpu_names[cpu];
sd_path[SD_PATH_DOM].procname = NULL; /* end of array sentinel */
- sd_cpudir_headers[i] = register_sysctl_paths(sd_path, empty);
- if (sd_cpudir_headers[i] == NULL) {
- kfree(empty);
+ sd_cpudir_headers[i] = register_sysctl_dir(sd_path);
+ if (sd_cpudir_headers[i] == NULL)
goto unregister_sd_cpudir_headers;
- }
i++;
}
@@ -6347,11 +6342,8 @@ unregister_sd_domain_headers:
i = sd_cpudir_headers_num;
unregister_sd_cpudir_headers:
i--;
- for(; i >= 0; i--) {
- struct ctl_table *table = sd_cpudir_headers[i]->ctl_table_arg;
+ for(; i >= 0; i--)
unregister_sysctl_table(sd_cpudir_headers[i]);
- kfree(table);
- }
kfree(sd_domain_headers);
fail_alloc_sd_domain_headers:
@@ -6391,11 +6383,8 @@ static void unregister_sched_domain_sysctl(void)
kfree(table);
}
- for(i = sd_cpudir_headers_num - 1; i >= 0; i--) {
- struct ctl_table *table = sd_cpudir_headers[i]->ctl_table_arg;
+ for(i = sd_cpudir_headers_num - 1; i >= 0; i--)
unregister_sysctl_table(sd_cpudir_headers[i]);
- kfree(table);
- }
kfree(sd_domain_headers);
kfree(sd_cpudir_headers);
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 091/115] sysctl: add register_sysctl_dir: register an empty sysctl directory
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
include/linux/sysctl.h | 5 +++--
kernel/sysctl.c | 37 +++++++++++++++++++++++++++++++++++++
kernel/sysctl_check.c | 15 +++++++++++----
3 files changed, 51 insertions(+), 6 deletions(-)
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 322246d..03842cc 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -1133,11 +1133,12 @@ extern struct ctl_table_header *__register_sysctl_paths(struct ctl_table_group *
struct ctl_table *table);
extern struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
struct ctl_table *table);
+struct ctl_table_header *register_sysctl_dir(const struct ctl_path *path);
extern void unregister_sysctl_table(struct ctl_table_header *table);
#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
-extern int sysctl_check_table(const struct ctl_path *path,
- int nr_dirs,
+extern int sysctl_check_path(const struct ctl_path *path, int nr_dirs);
+extern int sysctl_check_table(const struct ctl_path *path, int nr_dirs,
struct ctl_table *table);
extern int sysctl_check_duplicates(struct ctl_table_header *header);
extern int sysctl_check_netns_correspondents(struct ctl_table_header *header,
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 94fff4e..7cf0242 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -2045,6 +2045,9 @@ struct ctl_table_header *__register_sysctl_paths(struct ctl_table_group *group,
int dirs_created = 0;
#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
+ if (sysctl_check_path(path, nr_dirs))
+ return NULL;
+
if (sysctl_check_table(path, nr_dirs, table))
return NULL;
#endif
@@ -2098,6 +2101,39 @@ struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
return __register_sysctl_paths(&root_table_group, path, table);
}
+/* Register an empty sysctl directory. */
+static struct ctl_table_header *__register_sysctl_dir(
+ struct ctl_table_group *group, const struct ctl_path *path)
+{
+ struct ctl_table_header *dir;
+ int nr_dirs = ctl_path_items(path);
+ int dirs_created = 0;
+
+#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
+ if (sysctl_check_path(path, nr_dirs))
+ return NULL;
+#endif
+
+ dir = sysctl_mkdirs(&root_table_header, group, path,
+ nr_dirs, &dirs_created);
+ if (!dir)
+ return NULL;
+
+ /* -1 because we don't want to count ourselves in the list of
+ * directory headers owned by @dir. NOTE: if all of the dirs
+ * in the path are already registered dirs_created will be 0. */
+ if (dirs_created > 0)
+ dir->ctl_owned_dirs_refs = dirs_created - 1;
+ else
+ dir->ctl_owned_dirs_refs = 0;
+ return dir;
+}
+
+struct ctl_table_header *register_sysctl_dir(const struct ctl_path *path)
+{
+ return __register_sysctl_dir(&root_table_group, path);
+}
+
/**
* unregister_sysctl_table - unregister a sysctl table hierarchy
* @header: the header returned from __register_sysctl_paths
@@ -3193,4 +3229,5 @@ EXPORT_SYMBOL(proc_dostring);
EXPORT_SYMBOL(proc_doulongvec_minmax);
EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
EXPORT_SYMBOL(register_sysctl_paths);
+EXPORT_SYMBOL(register_sysctl_dir);
EXPORT_SYMBOL(unregister_sysctl_table);
diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c
index 205f721..20c1948 100644
--- a/kernel/sysctl_check.c
+++ b/kernel/sysctl_check.c
@@ -24,6 +24,17 @@ static void fail(const struct ctl_path *path,
#define FAIL(str) do { fail(path, t->procname, str); error = -EINVAL;} while (0)
+
+int sysctl_check_path(const struct ctl_path *path,
+ int nr_dirs)
+{
+ if (nr_dirs <= CTL_MAXNAME - 1)
+ return 0;
+ fail(path, NULL, "tree too deep");
+ return -EINVAL;
+}
+
+
int sysctl_check_table(const struct ctl_path *path,
int nr_dirs,
struct ctl_table *table)
@@ -33,10 +44,6 @@ int sysctl_check_table(const struct ctl_path *path,
unsigned int nr_files = 0;
int error = 0;
- if (nr_dirs > CTL_MAXNAME - 1) {
- fail(path, NULL, "tree too deep");
- error = -EINVAL;
- }
for(t = table; t->procname; t++) {
nr_files ++;
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 087/115] sysctl: check netns-specific registration order respected
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
include/linux/sysctl.h | 2 +
kernel/sysctl.c | 15 ++++++++-
kernel/sysctl_check.c | 78 ++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 85 insertions(+), 10 deletions(-)
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index bdc8c97..036d1aa 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -1128,6 +1128,8 @@ extern int sysctl_check_table(const struct ctl_path *path,
int nr_dirs,
struct ctl_table *table);
extern int sysctl_check_duplicates(struct ctl_table_header *header);
+extern int sysctl_check_netns_correspondents(struct ctl_table_header *header,
+ struct ctl_table_group *group);
#endif /* CONFIG_SYSCTL_SYSCALL_CHECK */
#endif /* __KERNEL__ */
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 9b2c05a..9e50334 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1920,6 +1920,12 @@ static struct ctl_table_header *sysctl_mkdirs(struct ctl_table_header *parent,
sysctl_write_unlock_head(parent);
parent = h;
dirs[i] = NULL; /* I'm used, don't free me */
+#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
+ if (sysctl_check_netns_correspondents(parent, group)) {
+ unregister_sysctl_table(h);
+ goto err_check_netns_correspondents;
+ }
+#endif
continue;
}
@@ -1946,11 +1952,18 @@ static struct ctl_table_header *sysctl_mkdirs(struct ctl_table_header *parent,
return parent;
+#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
+err_check_netns_correspondents:
+ if (__netns_corresp)
+ kmem_cache_free(sysctl_header_cachep, __netns_corresp);
+#endif
+
err_alloc_coresp:
i = nr_dirs;
err_alloc_dir:
for (i--; i >= 0; i--)
- kmem_cache_free(sysctl_header_cachep, dirs[i]);
+ if (dirs[i])
+ kmem_cache_free(sysctl_header_cachep, dirs[i]);
return NULL;
}
diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c
index 4e0bce5..55e797a 100644
--- a/kernel/sysctl_check.c
+++ b/kernel/sysctl_check.c
@@ -63,19 +63,14 @@ int sysctl_check_table(const struct ctl_path *path,
return error;
}
-
-/*
- * @dir: the directory imediately above the offender
- * @offender is the name of a file or directory that violated some sysctl rules.
- */
-static void duplicate_error(struct ctl_table_header *dir,
- const char *offender)
+/* Print the path from to a sysctl directory. The header must *not*
+ * point to a ctl_table_header that wraps a ctl_table array, it must
+ * be a directory. */
+static void printk_sysctl_dir(struct ctl_table_header *dir)
{
const char *names[CTL_MAXNAME];
int i = 0;
- printk(KERN_ERR "sysctl duplicate check failed: ");
-
for (; dir->parent; dir = dir->parent)
/* ctl_dirname can be NULL: netns-correspondent
* directories do not have a ctl_dirname. Their only
@@ -90,7 +85,18 @@ static void duplicate_error(struct ctl_table_header *dir,
/* Print the names in the normal path order, not reversed */
for(i--; i >= 0; i--)
printk("/%s", names[i]);
+}
+
+/*
+ * @dir: the directory imediately above the offender
+ * @offender is the name of a file or directory that violated some sysctl rules.
+ */
+static void duplicate_error(struct ctl_table_header *dir,
+ const char *offender)
+{
+ printk(KERN_ERR "sysctl duplicate check failed: ");
+ printk_sysctl_dir(dir);
printk("/%s \n", offender);
}
@@ -150,3 +156,57 @@ int sysctl_check_duplicates(struct ctl_table_header *header)
return has_duplicates;
}
+
+/* Check whether adding this header respects the rule that no
+ * non-netns-specific directory will be registered after one with the
+ * same name, but netns-specific was registered before (and still is registered)
+ *
+ * E.g. This sequence of registrations is not valid:
+ * - non-netns-specific: /net/ipv4/
+ * - netns-specific: /net/ipv4/conf/lo
+ * - non-netns-specific: /net/ipv4/conf/
+
+ * because after first adding 'conf' as a netns specific directory,
+ * we're adding one non-netns specific.
+ *
+ * NOTE: in this example, the directory that has a netns-correspondent is 'ipv4'
+ */
+int sysctl_check_netns_correspondents(struct ctl_table_header *header,
+ struct ctl_table_group *group)
+{
+ struct ctl_table_header *netns_corresp, *h;
+ int found = 0;
+ /* we're only checking registration of non-netns paths added,
+ * because only those paths can violate the above rule. */
+ if (group->has_netns_corresp)
+ return 0;
+
+ netns_corresp = sysctl_use_netns_corresp(header->parent);
+ if (!netns_corresp)
+ return 0;
+
+ /* see if the netns_correspondent has a subdir
+ * with the same as this non-netns specific header */
+ sysctl_read_lock_head(netns_corresp);
+ list_for_each_entry(h, &netns_corresp->ctl_subdirs, ctl_entry) {
+ if (IS_ERR(sysctl_use_header(h)))
+ continue;
+ if (strcmp(header->ctl_dirname, h->ctl_dirname) == 0) {
+ sysctl_unuse_header(h);
+ found = 1;
+ break;
+ }
+ sysctl_unuse_header(h);
+ }
+ sysctl_read_unlock_head(netns_corresp);
+
+ if (!found)
+ return 0;
+
+ printk(KERN_ERR "illegal sysctl registration of non-netns-specific "
+ "directory after a netns-specific with the same name\n");
+ printk_sysctl_dir(header);
+ dump_stack();
+
+ return 1;
+}
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 085/115] sysctl: single subheader path: kernel/sched_domain/CPU/DOMAIN/
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
kernel/sched.c | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/kernel/sched.c b/kernel/sched.c
index 6e39b7c..8320365 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -6250,7 +6250,13 @@ static void register_sched_domain_sysctl(void)
{ .procname = "kernel" },
{ .procname = "sched_domain" },
{ /* 'cpu0' */ },
- { /* 'domain0' */ },
+ {
+ /* 'domain0' */
+ .procname = NULL,
+ /* skip duplicate name check; we're registering
+ * just one subheader for this directory */
+ .has_just_one_subheader = 1,
+ },
{ },
};
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 082/115] sysctl: single subheader path: net/ipv6/conf/DEVICE-NAME/
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
net/ipv6/addrconf.c | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index a7bda07..3a9f958 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -4486,7 +4486,13 @@ static int __addrconf_sysctl_register(struct net *net, char *dev_name,
{ .procname = "net", },
{ .procname = "ipv6", },
{ .procname = "conf", },
- { /* to be set */ },
+ {
+ /* to be set bellow (ADDRCONF_CTL_PATH_DEV) */
+ .procname = NULL,
+ /* skip duplicate name check; we're registering
+ * just one subheader for this directory */
+ .has_just_one_subheader = 1,
+ },
{ },
};
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 081/115] sysctl: single subheader path: net/{ipv4|ipv6}/neigh/DEV/
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
net/core/neighbour.c | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 799f06e..63677be 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -2818,7 +2818,13 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
{ .procname = "net", },
{ .procname = "proto", },
{ .procname = "neigh", },
- { .procname = "default", },
+ {
+ /* will be set to device name (NEIGH_CTL_PATH_DEV) */
+ .procname = "default",
+ /* skip duplicate name check; we're registering
+ * just one subheader for this directory */
+ .has_just_one_subheader = 1,
+ },
{ },
};
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 079/115] sysctl: single subheader path: optimisation for paths used only once
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
This is an optimisation for registering paths that you know will be
used to register a single table. Because such directories will be used
only once, sysctl will always create an entry for it when it sees it.
When sysctl registers a table, for each directory that may be used
while registering other tables we do a linear search to see if it's
already added, and, if not, add it ourselves.
For example: each netdevice will register a single table under
/proc/sys/net/ipv4/conf/DEVNAME/.
The 'DEVNAME' component of the path is not used to register other
headers, and we can optimise adding that directory: we don't have to
check if it's already registered.
This will have a positive performance impact when registering many
such directories because we're doing a O(nr of sibling directories)
search. With @has_just_one_subheader=1 set we skip that search and add
the directory directly because we know no other sibling directory with
the same name was registered.
NOTE: in this example setting @has_just_one_subheader=1 for the 'conf'
ctl_path would be wrong because it's used when registering other
subheaders too (e.g. subheaders for other netdevices).
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
include/linux/sysctl.h | 31 +++++++++++++++++++++++++++++++
kernel/sysctl.c | 12 +++++++-----
2 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 22b6eb8..bdc8c97 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -1083,6 +1083,37 @@ struct ctl_table_header {
/* struct ctl_path describes where in the hierarchy a table is added */
struct ctl_path {
const char *procname;
+
+
+ /* This is an optimisation for registering paths that you know
+ * will be used to register a single table. Because such
+ * directories will be used only once, sysctl will always
+ * create an entry for it when it sees it.
+ *
+ * When sysctl registers a table, for each directory that may
+ * be used while registering other tables we do a linear
+ * search to see if it's already added, and, if not, add it
+ * ourselves.
+ *
+ * For example: each netdevice will register a single table
+ * under /proc/sys/net/ipv4/conf/DEVNAME/.
+ *
+ * The 'DEVNAME' component of the path is not used to register
+ * other headers, and we can optimise adding that directory:
+ * we don't have to check if it's already registered.
+ *
+ * This will have a positive performance impact when
+ * registering many such directories because we're doing a
+ * O(nr of sibling directories) search. With
+ * @has_just_one_subheader=1 set we skip that search and add
+ * the directory directly because we know no other sibling
+ * directory with the same name was registered.
+ *
+ * NOTE: in this example setting @has_just_one_subheader=1 for
+ * the 'conf' ctl_path would be wrong because it's used when
+ * registering other subheaders too (e.g. subheaders for other
+ * netdevices). */
+ int has_just_one_subheader;
};
extern struct ctl_table_header *__register_sysctl_paths(struct ctl_table_group *g,
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c207c19..9b2c05a 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1906,11 +1906,13 @@ static struct ctl_table_header *sysctl_mkdirs(struct ctl_table_header *parent,
retry:
sysctl_write_lock_head(parent);
- h = mkdir_existing_dir(parent, dirs[i]->ctl_dirname);
- if (h != NULL) {
- sysctl_write_unlock_head(parent);
- parent = h;
- continue;
+ if (!path[i].has_just_one_subheader) {
+ h = mkdir_existing_dir(parent, dirs[i]->ctl_dirname);
+ if (h != NULL) {
+ sysctl_write_unlock_head(parent);
+ parent = h;
+ continue;
+ }
}
if (likely(!create_first_netns_corresp)) {
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 078/115] sysctl: alloc ctl_table_header with kmem_cache
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Because now ctl_table_header objects are allocated with a fixed size
buffer (sizeof(struct ctl_table_header)) we can do the allocations
with kmem_cache.
Also, by making sure that the objects that are returned to the cache
are in a sane state we don't waste time reinitializing every field
after kmem_cache_alloc. We only initialize fields that were not left
with a sane value before returning an object to the cache.
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
kernel/sysctl.c | 48 +++++++++++++++++++++++++++++++++++++++---------
1 files changed, 39 insertions(+), 9 deletions(-)
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index d777e89..c207c19 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -198,6 +198,9 @@ static int sysrq_sysctl_handler(ctl_table *table, int write,
#endif
+/* cache for ctl_table_header objects */
+static struct kmem_cache *sysctl_header_cachep;
+
/* uses default ops */
static const struct ctl_table_group_ops root_table_group_ops = { };
@@ -1553,7 +1556,9 @@ void sysctl_proc_inode_get(struct ctl_table_header *head)
static void free_head(struct rcu_head *rcu)
{
- kfree(container_of(rcu, struct ctl_table_header, rcu));
+ struct ctl_table_header *header;
+ header = container_of(rcu, struct ctl_table_header, rcu);
+ kmem_cache_free(sysctl_header_cachep, header);
}
void sysctl_proc_inode_put(struct ctl_table_header *head)
@@ -1664,6 +1669,8 @@ int sysctl_perm(struct ctl_table_group *group, struct ctl_table *table, int op)
return test_perm(mode, op);
}
+static void sysctl_header_ctor(void *data);
+
__init int sysctl_init(void)
{
struct ctl_table_header *kern_header, *vm_header, *fs_header,
@@ -1672,6 +1679,12 @@ __init int sysctl_init(void)
struct ctl_table_header *binfmt_misc_header;
#endif
+ sysctl_header_cachep = kmem_cache_create("sysctl_header_cachep",
+ sizeof(struct ctl_table_header),
+ 0, 0, &sysctl_header_ctor);
+ if (!sysctl_header_cachep)
+ goto fail_alloc_cachep;
+
kern_header = register_sysctl_paths(kern_path, kern_table);
if (kern_header == NULL)
goto fail_register_kern;
@@ -1715,6 +1728,8 @@ fail_register_fs:
fail_register_vm:
unregister_sysctl_table(kern_header);
fail_register_kern:
+ kmem_cache_destroy(sysctl_header_cachep);
+fail_alloc_cachep:
return -ENOMEM;
}
@@ -1735,19 +1750,34 @@ static int ctl_path_items(const struct ctl_path *path)
return n;
}
+static void sysctl_header_ctor(void *data)
+{
+ struct ctl_table_header *h = data;
+
+ h->ctl_use_refs = 0;
+ h->ctl_procfs_refs = 0;
+ h->ctl_header_refs = 0;
+
+ INIT_LIST_HEAD(&h->ctl_entry);
+ INIT_LIST_HEAD(&h->ctl_subdirs);
+ INIT_LIST_HEAD(&h->ctl_tables);
+}
static struct ctl_table_header *alloc_sysctl_header(struct ctl_table_group *group)
{
struct ctl_table_header *h;
- h = kzalloc(sizeof(*h), GFP_KERNEL);
+ h = kmem_cache_alloc(sysctl_header_cachep, GFP_KERNEL);
if (!h)
return NULL;
+ /* - all _refs members are zero before freeing
+ * - all list_head members point to themselves (empty lists) */
+
+ h->ctl_table_arg = NULL;
+ h->unregistering = NULL;
h->ctl_group = group;
- INIT_LIST_HEAD(&h->ctl_entry);
- INIT_LIST_HEAD(&h->ctl_subdirs);
- INIT_LIST_HEAD(&h->ctl_tables);
+
return h;
}
@@ -1905,12 +1935,12 @@ static struct ctl_table_header *sysctl_mkdirs(struct ctl_table_header *parent,
parent = mkdir_netns_corresp(parent, group, &__netns_corresp);
if (__netns_corresp)
- kfree(__netns_corresp);
+ kmem_cache_free(sysctl_header_cachep, __netns_corresp);
/* free unused pre-allocated entries */
for (i = 0; i < nr_dirs; i++)
if (dirs[i])
- kfree(dirs[i]);
+ kmem_cache_free(sysctl_header_cachep, dirs[i]);
return parent;
@@ -1918,7 +1948,7 @@ err_alloc_coresp:
i = nr_dirs;
err_alloc_dir:
for (i--; i >= 0; i--)
- kfree(dirs[i]);
+ kmem_cache_free(sysctl_header_cachep, dirs[i]);
return NULL;
}
@@ -1991,7 +2021,7 @@ struct ctl_table_header *__register_sysctl_paths(struct ctl_table_group *group,
header->parent = sysctl_mkdirs(&root_table_header, group, path, nr_dirs);
if (!header->parent) {
- kfree(header);
+ kmem_cache_free(sysctl_header_cachep, header);
return NULL;
}
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 077/115] sysctl: add duplicate entry and sanity ctl_table checks
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
include/linux/sysctl.h | 7 ++
kernel/sysctl.c | 19 ++++++-
kernel/sysctl_check.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 177 insertions(+), 2 deletions(-)
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index b626271..22b6eb8 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -1092,6 +1092,13 @@ extern struct ctl_table_header *register_sysctl_paths(const struct ctl_path *pat
struct ctl_table *table);
extern void unregister_sysctl_table(struct ctl_table_header *table);
+#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
+extern int sysctl_check_table(const struct ctl_path *path,
+ int nr_dirs,
+ struct ctl_table *table);
+extern int sysctl_check_duplicates(struct ctl_table_header *header);
+#endif /* CONFIG_SYSCTL_SYSCALL_CHECK */
+
#endif /* __KERNEL__ */
#endif /* _LINUX_SYSCTL_H */
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index cbf33b1..d777e89 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1977,8 +1977,14 @@ struct ctl_table_header *__register_sysctl_paths(struct ctl_table_group *group,
const struct ctl_path *path, struct ctl_table *table)
{
struct ctl_table_header *header;
+ int failed_duplicate_check = 0;
int nr_dirs = ctl_path_items(path);
+#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
+ if (sysctl_check_table(path, nr_dirs, table))
+ return NULL;
+#endif
+
header = alloc_sysctl_header(group);
if (!header)
return NULL;
@@ -1993,9 +1999,20 @@ struct ctl_table_header *__register_sysctl_paths(struct ctl_table_group *group,
header->ctl_header_refs = 1;
sysctl_write_lock_head(header->parent);
- list_add_tail(&header->ctl_entry, &header->parent->ctl_tables);
+
+#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
+ failed_duplicate_check = sysctl_check_duplicates(header);
+#endif
+ if (!failed_duplicate_check)
+ list_add_tail(&header->ctl_entry, &header->parent->ctl_tables);
+
sysctl_write_unlock_head(header->parent);
+ if (failed_duplicate_check) {
+ unregister_sysctl_table(header);
+ return NULL;
+ }
+
return header;
}
diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c
index e9a7a58..4e0bce5 100644
--- a/kernel/sysctl_check.c
+++ b/kernel/sysctl_check.c
@@ -1 +1,152 @@
-/* will be rewritten */
+#include <linux/sysctl.h>
+#include <linux/string.h>
+
+/*
+ * @path: the path to the offender
+ * @offender is the name of a file or directory that violated some sysctl rules.
+ * @str: a message accompanying the error
+ */
+static void fail(const struct ctl_path *path,
+ const char *offender,
+ const char *str)
+{
+ printk(KERN_ERR "sysctl sanity check failed: ");
+
+ for (; path->procname; path++)
+ printk("/%s", path->procname);
+
+ if (offender)
+ printk("/%s", offender);
+
+ printk(": %s\n", str);
+}
+
+#define FAIL(str) do { fail(path, t->procname, str); error = -EINVAL;} while (0)
+
+int sysctl_check_table(const struct ctl_path *path,
+ int nr_dirs,
+ struct ctl_table *table)
+{
+ struct ctl_table *t;
+ int error = 0;
+
+ if (nr_dirs > CTL_MAXNAME - 1) {
+ fail(path, NULL, "tree too deep");
+ error = -EINVAL;
+ }
+
+ for(t = table; t->procname; t++) {
+ if ((t->proc_handler == proc_dostring) ||
+ (t->proc_handler == proc_dointvec) ||
+ (t->proc_handler == proc_dointvec_minmax) ||
+ (t->proc_handler == proc_dointvec_jiffies) ||
+ (t->proc_handler == proc_dointvec_userhz_jiffies) ||
+ (t->proc_handler == proc_dointvec_ms_jiffies) ||
+ (t->proc_handler == proc_doulongvec_minmax) ||
+ (t->proc_handler == proc_doulongvec_ms_jiffies_minmax)) {
+ if (!t->data)
+ FAIL("No data");
+ if (!t->maxlen)
+ FAIL("No maxlen");
+ }
+#ifdef CONFIG_PROC_SYSCTL
+ if (!t->proc_handler)
+ FAIL("No proc_handler");
+#endif
+ if (t->mode > 0777)
+ FAIL("bogus .mode");
+ }
+
+ if (error)
+ dump_stack();
+
+ return error;
+}
+
+
+/*
+ * @dir: the directory imediately above the offender
+ * @offender is the name of a file or directory that violated some sysctl rules.
+ */
+static void duplicate_error(struct ctl_table_header *dir,
+ const char *offender)
+{
+ const char *names[CTL_MAXNAME];
+ int i = 0;
+
+ printk(KERN_ERR "sysctl duplicate check failed: ");
+
+ for (; dir->parent; dir = dir->parent)
+ /* ctl_dirname can be NULL: netns-correspondent
+ * directories do not have a ctl_dirname. Their only
+ * pourpose is to hold the list of
+ * subdirs/subtables. They hold netns-specific
+ * information for the parent directory. */
+ if (dir->ctl_dirname) {
+ names[i] = dir->ctl_dirname;
+ i++;
+ }
+
+ /* Print the names in the normal path order, not reversed */
+ for(i--; i >= 0; i--)
+ printk("/%s", names[i]);
+
+ printk("/%s \n", offender);
+}
+
+/* is there an entry in the table with the same procname? */
+static int match(struct ctl_table *table, const char *name)
+{
+ for ( ; table->procname; table++) {
+
+ if (strcmp(table->procname, name) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+
+/* Called under header->parent write lock.
+ *
+ * checks whether this header's table introduces items that have the
+ * same names as other items at the same level (other files or
+ * subdirectories of the current dir). */
+int sysctl_check_duplicates(struct ctl_table_header *header)
+{
+ int has_duplicates = 0;
+ struct ctl_table *table = header->ctl_table_arg;
+ struct ctl_table_header *dir = header->parent;
+ struct ctl_table_header *h;
+
+ list_for_each_entry(h, &dir->ctl_subdirs, ctl_entry) {
+ if (IS_ERR(sysctl_use_header(h)))
+ continue;
+
+ if (match(table, h->ctl_dirname)) {
+ has_duplicates = 1;
+ duplicate_error(dir, h->ctl_dirname);
+ }
+
+ sysctl_unuse_header(h);
+ }
+
+ list_for_each_entry(h, &dir->ctl_tables, ctl_entry) {
+ ctl_table *t;
+
+ if (IS_ERR(sysctl_use_header(h)))
+ continue;
+
+ for (t = h->ctl_table_arg; t->procname; t++) {
+ if (match(table, t->procname)) {
+ has_duplicates = 1;
+ duplicate_error(dir, t->procname);
+ }
+ }
+ sysctl_unuse_header(h);
+ }
+
+ if (has_duplicates)
+ dump_stack();
+
+ return has_duplicates;
+}
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 075/115] sysctl: move removal from list out of start_unregistering
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
Later on we'll switch form a global list protected by the sysctl_lock
spin lock to rwsem protected per-header lists.
At that point we'll need to hold the parent header's rwlock to remove
the header from the list, not the sysctl_lock spin lock.
As start_unregistering is called under the sysctl_lock, we move the
list removal out.
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
kernel/sysctl.c | 12 +++++++-----
1 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 8dde087..a863b56 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1552,11 +1552,6 @@ static void start_unregistering(struct ctl_table_header *p)
/* anything non-NULL; we'll never dereference it */
p->unregistering = ERR_PTR(-EINVAL);
}
- /*
- * do not remove from the list until nobody holds it; walking the
- * list in do_sysctl() relies on that.
- */
- list_del_init(&p->ctl_entry);
}
void sysctl_proc_inode_get(struct ctl_table_header *head)
@@ -1949,6 +1944,13 @@ void unregister_sysctl_table(struct ctl_table_header * header)
spin_lock(&sysctl_lock);
start_unregistering(header);
+
+ /* after start_unregistering has finished no one holds a
+ * ctl_use_refs or is able to acquire one => no one is going
+ * to access internal fields of this object, so we can remove
+ * it from the list and schedule it for deletion. */
+ list_del_init(&p->ctl_entry);
+
if (!--header->parent->ctl_header_refs) {
WARN_ON(1);
if (!header->parent->ctl_procfs_refs)
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 072/115] sysctl: simplify ->permissions hook
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
The @root parameter was not used at all.
The @namespaces parameter was used to transmit current->nsproxy. We
can access current->nsproxy directly in the ->permissions function, no
need to send it.
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
include/linux/sysctl.h | 3 +--
kernel/sysctl.c | 2 +-
net/sysctl_net.c | 9 +++------
3 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index e265880..1af4ed5 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -1034,8 +1034,7 @@ struct ctl_table_root {
struct ctl_table_set default_set;
struct ctl_table_set *(*lookup)(struct ctl_table_root *root,
struct nsproxy *namespaces);
- int (*permissions)(struct ctl_table_root *root,
- struct nsproxy *namespaces, struct ctl_table *table);
+ int (*permissions)(struct ctl_table *table);
};
/* struct ctl_table_header is used to maintain dynamic lists of
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 1281827..6e4e32b 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1664,7 +1664,7 @@ int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
int mode;
if (root->permissions)
- mode = root->permissions(root, current->nsproxy, table);
+ mode = root->permissions(table);
else
mode = table->mode;
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index 1197d9c..1c0cb57 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -41,9 +41,7 @@ static int is_seen(struct ctl_table_set *set)
}
/* Return standard mode bits for table entry. */
-static int net_ctl_permissions(struct ctl_table_root *root,
- struct nsproxy *nsproxy,
- struct ctl_table *table)
+static int net_ctl_permissions(struct ctl_table *table)
{
/* Allow network administrator to have same access as root. */
if (capable(CAP_NET_ADMIN)) {
@@ -58,10 +56,9 @@ static struct ctl_table_root net_sysctl_root = {
.permissions = net_ctl_permissions,
};
-static int net_ctl_ro_header_perms(struct ctl_table_root *root,
- struct nsproxy *namespaces, struct ctl_table *table)
+static int net_ctl_ro_header_perms(ctl_table *table)
{
- if (net_eq(namespaces->net_ns, &init_net))
+ if (net_eq(current->nsproxy->net_ns, &init_net))
return table->mode;
else
return table->mode & ~0222;
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 069/115] sysctl: split ->count into ctl_procfs_refs and ctl_header_refs
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
This is not necessary at this point, but will be later when we replace
the sysctl implementation with one that uses ctl_table_header objects
as directories.
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
include/linux/sysctl.h | 8 +++++++-
kernel/sysctl.c | 21 ++++++++++++---------
2 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 4ed5235..0f41beb 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -1046,7 +1046,13 @@ struct ctl_table_header
/* references to this header from contexts that
* can access fields of this header */
int ctl_use_refs;
- int count;
+ /* references to this header from procfs inodes.
+ * procfs embeds a pointer to the header in proc_inode */
+ int ctl_procfs_refs;
+ /* counts references to this header from other
+ * headers (through ->parent) plus the reference
+ * returned by __register_sysctl_paths */
+ int ctl_header_refs;
};
struct rcu_head rcu;
};
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index e4ec23e..48a1ffd 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -200,7 +200,7 @@ static int sysrq_sysctl_handler(ctl_table *table, int write,
static struct ctl_table root_table[];
static struct ctl_table_root sysctl_table_root;
static struct ctl_table_header root_table_header = {
- {{.count = 1,
+ {{.ctl_header_refs = 1,
.ctl_table = root_table,
.ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),}},
.root = &sysctl_table_root,
@@ -1554,7 +1554,7 @@ static void start_unregistering(struct ctl_table_header *p)
void sysctl_head_get(struct ctl_table_header *head)
{
spin_lock(&sysctl_lock);
- head->count++;
+ head->ctl_procfs_refs++;
spin_unlock(&sysctl_lock);
}
@@ -1566,7 +1566,8 @@ static void free_head(struct rcu_head *rcu)
void sysctl_head_put(struct ctl_table_header *head)
{
spin_lock(&sysctl_lock);
- if (!--head->count)
+ head->ctl_procfs_refs--;
+ if ((head->ctl_procfs_refs == 0) && (head->ctl_header_refs == 0))
call_rcu(&head->rcu, free_head);
spin_unlock(&sysctl_lock);
}
@@ -1877,7 +1878,7 @@ struct ctl_table_header *__register_sysctl_paths(
INIT_LIST_HEAD(&header->ctl_entry);
header->unregistering = NULL;
header->root = root;
- header->count = 1;
+ header->ctl_header_refs = 1;
#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
if (sysctl_check_table(namespaces, header->ctl_table)) {
kfree(header);
@@ -1897,7 +1898,7 @@ struct ctl_table_header *__register_sysctl_paths(
try_attach(p, header);
}
}
- header->parent->count++;
+ header->parent->ctl_header_refs++;
list_add_tail(&header->ctl_entry, &header->set->list);
spin_unlock(&sysctl_lock);
@@ -1937,12 +1938,14 @@ void unregister_sysctl_table(struct ctl_table_header * header)
spin_lock(&sysctl_lock);
start_unregistering(header);
- if (!--header->parent->count) {
+ if (!--header->parent->ctl_header_refs) {
WARN_ON(1);
- call_rcu(&header->parent->rcu, free_head);
+ if (!header->parent->ctl_procfs_refs)
+ call_rcu(&header->parent->rcu, free_head);
}
- if (!--header->count)
- call_rcu(&header->rcu, free_head);
+ if (!--header->ctl_header_refs)
+ if (!header->ctl_procfs_refs)
+ call_rcu(&header->rcu, free_head);
spin_unlock(&sysctl_lock);
}
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 066/115] sysctl: rename ->used to ->ctl_use_refs
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
In a later patch I will split the 'count' counter. We need to have a
clear distinction between the three counters to be able to understand
the code.
This counts the number of references to this object from places that
can tinker with it's internals (e.g. ctl_table, ctl_entry,
attached_to, attached_by, etc.).
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
include/linux/sysctl.h | 4 +++-
kernel/sysctl.c | 9 ++++-----
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 1c41dbd..fe13067 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -1043,7 +1043,9 @@ struct ctl_table_header
struct {
struct ctl_table *ctl_table;
struct list_head ctl_entry;
- int used;
+ /* references to this header from contexts that
+ * can access fields of this header */
+ int ctl_use_refs;
int count;
};
struct rcu_head rcu;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 8b56695..ab242b4 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1494,14 +1494,14 @@ static int use_table(struct ctl_table_header *p)
{
if (unlikely(p->unregistering))
return 0;
- p->used++;
+ p->ctl_use_refs++;
return 1;
}
/* called under sysctl_lock */
static void unuse_table(struct ctl_table_header *p)
{
- if (!--p->used)
+ if (!--p->ctl_use_refs)
if (unlikely(p->unregistering))
complete(p->unregistering);
}
@@ -1510,10 +1510,10 @@ static void unuse_table(struct ctl_table_header *p)
static void start_unregistering(struct ctl_table_header *p)
{
/*
- * if p->used is 0, nobody will ever touch that entry again;
+ * if p->ctl_use_refs is 0, nobody will ever touch that entry again;
* we'll eliminate all paths to it before dropping sysctl_lock
*/
- if (unlikely(p->used)) {
+ if (unlikely(p->ctl_use_refs)) {
struct completion wait;
init_completion(&wait);
p->unregistering = &wait;
@@ -1875,7 +1875,6 @@ struct ctl_table_header *__register_sysctl_paths(
header->ctl_table_arg = table;
INIT_LIST_HEAD(&header->ctl_entry);
- header->used = 0;
header->unregistering = NULL;
header->root = root;
header->count = 1;
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 064/115] sysctl: sysctl_head_grab defaults to root header on NULL
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
The code that could send NULL to sysctl_head_grab is grab_header
because for the root sysctl directory ('/proc/sys/')
PROC_I(inode)->sysctl is NULL.
For it we used to return root_table_header indirectly through a call
to sysctl_head_next(NULL). Now we default to the root header here.
The BUG() has not been triggered until now so we can assume no one
else is sending NULL here.
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
fs/proc/proc_sysctl.c | 5 +----
kernel/sysctl.c | 2 +-
2 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index d1640bc..93962b0 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -64,10 +64,7 @@ static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name)
static struct ctl_table_header *grab_header(struct inode *inode)
{
- if (PROC_I(inode)->sysctl)
- return sysctl_head_grab(PROC_I(inode)->sysctl);
- else
- return sysctl_head_next(NULL);
+ return sysctl_head_grab(PROC_I(inode)->sysctl);
}
static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 0450d3d..8b56695 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1554,7 +1554,7 @@ void sysctl_head_put(struct ctl_table_header *head)
struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head)
{
if (!head)
- BUG();
+ head = &root_table_header;
spin_lock(&sysctl_lock);
if (!use_table(head))
head = ERR_PTR(-ENOENT);
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 063/115] sysctl: simplify find_in_table
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
The if (!p->procname) check is useless because the loop condition
prevents it from happening.
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
fs/proc/proc_sysctl.c | 10 ++--------
1 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index f50133c..d1640bc 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -52,18 +52,12 @@ static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name)
int len;
for ( ; p->procname; p++) {
- if (!p->procname)
- continue;
-
len = strlen(p->procname);
if (len != name->len)
continue;
- if (memcmp(p->procname, name->name, len) != 0)
- continue;
-
- /* I have a match */
- return p;
+ if (memcmp(p->procname, name->name, len) == 0)
+ return p;
}
return NULL;
}
--
1.7.5.134.g1c08b
^ permalink raw reply related
* [v2 062/115] sysctl: remove useless ctl_table->parent field
From: Lucian Adrian Grijincu @ 2011-05-08 22:39 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Lucian Adrian Grijincu
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>
The 'parent' field was added for selinux in:
commit d912b0cc1a617d7c590d57b7ea971d50c7f02503
[PATCH] sysctl: add a parent entry to ctl_table and set the parent entry
and then was used for sysctl_check_table.
Both of the users have found other implementations.
Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
include/linux/sysctl.h | 1 -
kernel/sysctl.c | 12 ------------
kernel/sysctl_check.c | 5 +++--
3 files changed, 3 insertions(+), 15 deletions(-)
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 095df3a..1c41dbd 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -1021,7 +1021,6 @@ struct ctl_table
int maxlen;
mode_t mode;
struct ctl_table *child;
- struct ctl_table *parent; /* Automatically set */
proc_handler *proc_handler; /* Callback for text formatting */
void *extra1;
void *extra2;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index edacbdc..0450d3d 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1671,15 +1671,6 @@ int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
return test_perm(mode, op);
}
-static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table)
-{
- for (; table->procname; table++) {
- table->parent = parent;
- if (table->child)
- sysctl_set_parent(table, table->child);
- }
-}
-
__init int sysctl_init(void)
{
struct ctl_table_header *kern_header, *vm_header, *fs_header,
@@ -1688,8 +1679,6 @@ __init int sysctl_init(void)
struct ctl_table_header *binfmt_misc_header;
#endif
- sysctl_set_parent(NULL, root_table);
-
kern_header = register_sysctl_paths(kern_path, kern_table);
if (kern_header == NULL)
goto fail_register_kern;
@@ -1889,7 +1878,6 @@ struct ctl_table_header *__register_sysctl_paths(
header->used = 0;
header->unregistering = NULL;
header->root = root;
- sysctl_set_parent(NULL, header->ctl_table);
header->count = 1;
#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
if (sysctl_check_table(namespaces, header->ctl_table)) {
diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c
index cc26490..52f4810 100644
--- a/kernel/sysctl_check.c
+++ b/kernel/sysctl_check.c
@@ -100,8 +100,9 @@ static int __sysctl_check_table(struct nsproxy *namespaces,
for (; table->procname; table++) {
fail = NULL;
- if (table->parent) {
- if (!table->parent->procname)
+
+ if (depth != 0) { /* has parent */
+ if (!parents[depth - 1]->procname)
SET_FAIL("Parent without procname");
}
if (table->child) {
--
1.7.5.134.g1c08b
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox