netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
To: linux-kernel@vger.kernel.org
Cc: netdev@vger.kernel.org,
	Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
Subject: [v2 090/115] sysctl: warn if registration/unregistration order is not respected
Date: Mon,  9 May 2011 00:39:42 +0200	[thread overview]
Message-ID: <1304894407-32201-91-git-send-email-lucian.grijincu@gmail.com> (raw)
In-Reply-To: <1304894407-32201-1-git-send-email-lucian.grijincu@gmail.com>

This patch sends a warning for each sysctl unregistration that cannot
delete all the directories that it created.

For example:
- register   /existingdir/newdir/file-a
- register   /existingdir/newdir/dir3/file-b
- unregister /existingdir/newdir/file-a
- unregister /existingdir/newdir/dir3/file-b

Here the order is violated because the first unregister operation
cannot delete all the directories it has created (namely 'newdir')
because they are used by another registered path.

This rule violation can be fixed in (at least) two ways:

- enforce order of unregistration:
  - register   /existingdir/newdir/file-a
  - register   /existingdir/newdir/dir3/file-b
  - unregister /existingdir/newdir/dir3/file-b
  - unregister /existingdir/newdir/file-a

- have a third party register the common part:
  - register   /existingdir/newdir/
  - register   /existingdir/newdir/file-a
  - register   /existingdir/newdir/dir3/file-b
  - unregister /existingdir/newdir/file-a
  - unregister /existingdir/newdir/dir3/file-b
  - unregister /existingdir/newdir/

The current implementation works well regardless of this order being
respected. In the future, other sysctl implementations may only work
if this rule is respected.

Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>
---
 include/linux/sysctl.h |   15 ++++++++++++---
 kernel/sysctl.c        |   39 +++++++++++++++++++++++++++++++++++----
 2 files changed, 47 insertions(+), 7 deletions(-)

diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index d5d9b66f..322246d 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -1036,12 +1036,14 @@ struct ctl_table_group_ops {
 };
 
 struct ctl_table_group {
+	/* has initialization for this group finished? */
+	int is_initialized:1;
+	/* does this group use the @corresp_list? */
+	int has_netns_corresp:1;
+	struct list_head corresp_list;
 	const struct ctl_table_group_ops *ctl_ops;
 	/* A list of ctl_table_header elements that represent the
 	 * netns-specific correspondents of some sysctl directories */
-	struct list_head corresp_list;
-	/* binary: whether this group uses the @corresp_list */
-	char has_netns_corresp;
 };
 
 /* struct ctl_table_header is used to maintain dynamic lists of
@@ -1069,6 +1071,13 @@ struct ctl_table_header {
 			 * the max value of this is the number of files in the
 			 * ctl_table array, or 1 for directories. */
 			u8 ctl_procfs_refs;
+			/* how many dirs were created when this header was
+			 * registered. Rule: the header which created a directory
+			 * should be the one that deletes it. This counter is
+			 * used to signal violations of this rule. The counter's
+			 * max value is CTL_MAXNAME (currently=10) so we use
+			 * only 4 bits of the 8 available. */
+			u8 ctl_owned_dirs_refs;
 		};
 		struct rcu_head rcu;
 	};
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 3e30e78..94fff4e 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -204,8 +204,9 @@ static struct kmem_cache *sysctl_header_cachep;
 static const struct ctl_table_group_ops root_table_group_ops = { };
 
 static struct ctl_table_group root_table_group = {
-	.has_netns_corresp = 0,
-	.ctl_ops = &root_table_group_ops,
+	.is_initialized		= 1,
+	.has_netns_corresp	= 0,
+	.ctl_ops		= &root_table_group_ops,
 };
 
 static struct ctl_table_header root_table_header = {
@@ -1617,6 +1618,14 @@ out:
 struct ctl_table_header *sysctl_use_netns_corresp(struct ctl_table_header *h)
 {
 	struct ctl_table_group *g = &current->nsproxy->net_ns->netns_ctl_group;
+
+	/* this function may be called to check whether the
+	 * netns-specific vs. non-netns-specific registration order is
+	 * respected. Those checks may be done early during init when
+	 * nor init_net is not initialized, nor it's netns-specific group. */
+	if (!g->is_initialized)
+		return NULL;
+
 	/* dflt == NULL means: if there's a netns corresp return it,
 	 *                     if there isn't, just return NULL */
 	return sysctl_use_netns_corresp_dflt(g, h, NULL);
@@ -1869,13 +1878,14 @@ static struct ctl_table_header *mkdir_new_dir(struct ctl_table_header *parent,
 static struct ctl_table_header *sysctl_mkdirs(struct ctl_table_header *parent,
 					      struct ctl_table_group *group,
 					      const struct ctl_path *path,
-					      int nr_dirs)
+					      int nr_dirs, int *p_dirs_created)
 {
 	struct ctl_table_header *dirs[CTL_MAXNAME];
 	struct ctl_table_header *__netns_corresp = NULL;
 	int create_first_netns_corresp = group->has_netns_corresp;
 	int i;
 
+	*p_dirs_created = 0;
 	/* We create excess ctl_table_header for directory entries.
 	 * We do so because we may need new headers while under a lock
 	 * where we will not be able to allocate entries (sleeping).
@@ -1929,6 +1939,7 @@ static struct ctl_table_header *sysctl_mkdirs(struct ctl_table_header *parent,
 				goto err_check_netns_correspondents;
 			}
 #endif
+			(*p_dirs_created)++;
 			continue;
 		}
 
@@ -1945,8 +1956,12 @@ static struct ctl_table_header *sysctl_mkdirs(struct ctl_table_header *parent,
 	if (create_first_netns_corresp)
 		parent = mkdir_netns_corresp(parent, group, &__netns_corresp);
 
+	/* if mkdir_netns_corresp used it, it's NULL */
 	if (__netns_corresp)
 		kmem_cache_free(sysctl_header_cachep, __netns_corresp);
+	else
+		(*p_dirs_created)++;
+
 
 	/* free unused pre-allocated entries */
 	for (i = 0; i < nr_dirs; i++)
@@ -2027,6 +2042,7 @@ struct ctl_table_header *__register_sysctl_paths(struct ctl_table_group *group,
 	struct ctl_table_header *header;
 	int failed_duplicate_check = 0;
 	int nr_dirs = ctl_path_items(path);
+	int dirs_created = 0;
 
 #ifdef CONFIG_SYSCTL_SYSCALL_CHECK
 	if (sysctl_check_table(path, nr_dirs, table))
@@ -2037,7 +2053,8 @@ struct ctl_table_header *__register_sysctl_paths(struct ctl_table_group *group,
 	if (!header)
 		return NULL;
 
-	header->parent = sysctl_mkdirs(&root_table_header, group, path, nr_dirs);
+	header->parent = sysctl_mkdirs(&root_table_header, group, path,
+				       nr_dirs, &dirs_created);
 	if (!header->parent) {
 		kmem_cache_free(sysctl_header_cachep, header);
 		return NULL;
@@ -2045,6 +2062,7 @@ struct ctl_table_header *__register_sysctl_paths(struct ctl_table_group *group,
 
 	header->ctl_table_arg = table;
 	header->ctl_header_refs = 1;
+	header->ctl_owned_dirs_refs = dirs_created;
 
 	sysctl_write_lock_head(header->parent);
 
@@ -2089,6 +2107,7 @@ struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
  */
 void unregister_sysctl_table(struct ctl_table_header *header)
 {
+	int dirs_to_delete = header->ctl_owned_dirs_refs;
 	might_sleep();
 
 	while(header->parent) {
@@ -2098,6 +2117,13 @@ void unregister_sysctl_table(struct ctl_table_header *header)
 		 * and ctl_use_refs) are protected by the spin lock. */
 		spin_lock(&sysctl_lock);
 		if (header->ctl_header_refs > 1) {
+			if (WARN(dirs_to_delete != 0, "directory that we "
+				 "created is still used by another header.")) {
+				/* if one element of the path is still used it's
+				 * parents will be too. Stop sending warnings */
+				dirs_to_delete = 0;
+			}
+
 			/* other headers need a reference to this one. Just
 			 * mark that we don't need it and leave it as it is. */
 			header->ctl_header_refs --;
@@ -2116,6 +2142,10 @@ void unregister_sysctl_table(struct ctl_table_header *header)
 		start_unregistering(header);
 		spin_unlock(&sysctl_lock);
 
+		/* don't go negative */
+		if (dirs_to_delete)
+			dirs_to_delete --;
+
 		if (!header->ctl_dirname) {
 			/* the header is a netns correspondent of it's
 			 * parent. It is a member of it's netns
@@ -2173,6 +2203,7 @@ void sysctl_init_group(struct ctl_table_group *group,
 	group->has_netns_corresp = has_netns_corresp;
 	if (has_netns_corresp)
 		INIT_LIST_HEAD(&group->corresp_list);
+	group->is_initialized = 1;
 }
 
 #else /* !CONFIG_SYSCTL */
-- 
1.7.5.134.g1c08b


  parent reply	other threads:[~2011-05-08 22:42 UTC|newest]

Thread overview: 100+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-05-08 22:38 [v2 000/115] faster tree-based sysctl implementation Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 001/115] sysctl: remove .child from dev/parport/default Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 002/115] sysctl: parport: reorder .child assignments to simplify review Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 003/115] sysctl: remove .child from dev/parport/PORT/devices/DEVICE Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 004/115] sysctl: remove .child from dev/parport/PORT/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 005/115] sysctl: remove .child from dev/parport/PORT/devices/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 006/115] sysctl: remove .child from kernel/vsyscall64 (x86) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 007/115] sysctl: remove .child from abi/vsyscall32 (x86) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 008/115] sysctl: remove .child from crypto/fips_enabled Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 009/115] sysctl: remove .child from dev/cdrom/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 010/115] sysctl: remove .child from dev/hpet/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 011/115] sysctl: remove .child from dev/ipmi/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 012/115] sysctl: remove .child from dev/rtc/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 013/115] sysctl: remove .child from dev/mac_hid/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 014/115] sysctl: remove .child from dev/raid/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 015/115] sysctl: remove .child from xpc/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 016/115] sysctl: remove .child from xpc/hb Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 017/115] sysctl: remove .child from kernel/sclp (s390) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 018/115] sysctl: remove .child from dev/scsi Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 019/115] sysctl: remove .child from kernel/pty Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 020/115] sysctl: remove .child from coda/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 021/115] sysctl: remove .child from fscache/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 022/115] sysctl: remove .child from fs/nfs/ nlm_table table Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 023/115] sysctl: remove .child from fs/nfs/ nfs_cb_table Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 024/115] sysctl: remove .child from fs/ntfs-debug Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 025/115] sysctl: remove .child from fs/ocfs2/nm/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 026/115] sysctl: remove .child from fs/quota/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 027/115] sysctl: remove .child from fs/xfs/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 028/115] sysctl: remove .child from kernel/ (ipc) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 029/115] sysctl: remove .child from fs/mqueue Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 030/115] sysctl: sched: add sd_table_template Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 031/115] sysctl: remove .child from kernel/sched_domain/cpuX/domainY/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 032/115] sysctl: remove .child from kernel/ (utsname) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 033/115] sysctl: remove .child from sunrpc/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 034/115] sysctl: remove .child from sunrpc/svc_rdma Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 035/115] sysctl: remove .child from sunrpc/ (xprtrdma) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 036/115] sysctl: remove .child from sunrpc/ (xprtsock) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 037/115] sysctl: remove .child from bus/isa/ (arm) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 038/115] sysctl: remove .child from reboot/warm (arm) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 039/115] sysctl: remove .child from lasat/ (mips) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 040/115] sysctl: remove .child from appldata/ (s390) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 041/115] sysctl: remove .child from s390dbf/ Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 042/115] sysctl: remove .child from vm/ (s390) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 043/115] sysctl: remove .child from kernel/perfmon/ (ia64) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 044/115] sysctl: remove .child from kernel/ (ia64/kdump) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 045/115] sysctl: remove .child from kernel/powersave-nap (powerpc) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 046/115] sysctl: remove .child from pm/ (frv) Lucian Adrian Grijincu
2011-05-08 22:38 ` [v2 047/115] sysctl: remove .child from frv/ Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 048/115] sysctl: remove .child from sh64/unaligned_fixup/ Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 049/115] sysctl: delete unused register_sysctl_table function Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 050/115] sysctl: remove .child from ax25 table Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 051/115] sysctl: remove .child from net/ipv4/route and net/ipv4/neigh tables Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 052/115] sysctl: remove .child from net/ipv4/neigh table Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 053/115] sysctl: remove .child from net/ipv6/route, net/ipv6/icmp, net/ipv6 tables Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 054/115] sysctl: remove .child from net/llc tables Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 055/115] sysctl: call sysctl_init before the first sysctl registration Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 056/115] sysctl: no-child: manually register kernel/random Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 057/115] sysctl: no-child: manually register kernel/keys Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 058/115] sysctl: no-child: manually register fs/inotify Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 059/115] sysctl: no-child: manually register fs/epoll Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 060/115] sysctl: no-child: manually register root tables Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 061/115] sysctl: faster reimplementation of sysctl_check_table Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 062/115] sysctl: remove useless ctl_table->parent field Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 063/115] sysctl: simplify find_in_table Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 064/115] sysctl: sysctl_head_grab defaults to root header on NULL Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 065/115] sysctl: delete useless grab_header function Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 066/115] sysctl: rename ->used to ->ctl_use_refs Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 067/115] sysctl: rename sysctl_head_grab/finish to sysctl_use_header/unuse Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 068/115] sysctl: rename sysctl_head_next to sysctl_use_next_header Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 069/115] sysctl: split ->count into ctl_procfs_refs and ctl_header_refs Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 070/115] sysctl: rename sysctl_head_get/put to sysctl_proc_inode_get/put Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 071/115] sysctl: rename (un)use_table to __sysctl_(un)use_header Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 072/115] sysctl: simplify ->permissions hook Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 073/115] sysctl: group root-specific operations Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 074/115] sysctl: introduce ctl_table_group Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 075/115] sysctl: move removal from list out of start_unregistering Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 076/115] sysctl: faster tree-based sysctl implementation Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 077/115] sysctl: add duplicate entry and sanity ctl_table checks Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 078/115] sysctl: alloc ctl_table_header with kmem_cache Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 079/115] sysctl: single subheader path: optimisation for paths used only once Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 080/115] sysctl: single subheader path: net/ipv4/conf/DEVICE-NAME/ Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 081/115] sysctl: single subheader path: net/{ipv4|ipv6}/neigh/DEV/ Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 082/115] sysctl: single subheader path: net/ipv6/conf/DEVICE-NAME/ Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 083/115] sysctl: single subheader path: dev/parport/PORT/devices/DEVICE/ Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 084/115] sysctl: single subheader path: net/ax25/DEVICE Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 085/115] sysctl: single subheader path: kernel/sched_domain/CPU/DOMAIN/ Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 086/115] sysctl: single subheader path: net/decnet/conf/DEVNAME Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 087/115] sysctl: check netns-specific registration order respected Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 088/115] RFC: sysctl: convert read-write lock to RCU Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 089/115] RFC: sysctl: change type of ctl_procfs_refs to u8 Lucian Adrian Grijincu
2011-05-08 22:39 ` Lucian Adrian Grijincu [this message]
2011-05-08 22:39 ` [v2 091/115] sysctl: add register_sysctl_dir: register an empty sysctl directory Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 092/115] sysctl: sched: create empty dir with register_sysctl_dir Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 093/115] sysctl: ax25: " Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 094/115] sysctl: net/core: " Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 095/115] sysctl: net/ipv4/neigh: " Lucian Adrian Grijincu
2011-05-08 22:39 ` [v2 096/115] sysctl: net/ipv6/neigh: " Lucian Adrian Grijincu
2011-05-08 22:40 ` [v2 000/115] faster tree-based sysctl implementation David Miller
2011-05-09  3:11 ` Eric W. Biederman
2011-05-10  1:06   ` Lucian Adrian Grijincu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1304894407-32201-91-git-send-email-lucian.grijincu@gmail.com \
    --to=lucian.grijincu@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).