aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2008-07-15 01:44:23 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2008-07-26 20:53:09 -0400
commitf7e6ced4061da509f737541ca4dbd44d83a6e82f (patch)
tree065a6907a085854da1eb176da1314c472e69a364 /include
parent734550921e9b7ab924a43aa3d0bd4239dac4fbf1 (diff)
[PATCH] allow delayed freeing of ctl_table_header
Refcount the sucker; instead of freeing it by the end of unregistration just drop the refcount and free only when it hits zero. Make sure that we _always_ make ->unregistering non-NULL in start_unregistering(). That allows anybody to get a reference to such puppy, preventing its freeing and reuse. It does *not* block unregistration. Anybody who holds such a reference can * try to grab a "use" reference (ctl_head_grab()); that will succeeds if and only if it hadn't entered unregistration yet. If it succeeds, we can use it in all normal ways until we release the "use" reference (with ctl_head_finish()). Note that this relies on having ->unregistering become non-NULL in all cases when one starts to unregister the sucker. * keep pointers to ctl_table entries; they *can* be freed if the entire thing is unregistered. However, if ctl_head_grab() succeeds, we know that unregistration had not happened (and will not happen until ctl_head_finish()) and such pointers can be used safely. IOW, now we can have inodes under /proc/sys keep references to ctl_table entries, protecting them with references to ctl_table_header and grabbing the latter for the duration of operations that require access to ctl_table. That won't cause deadlocks, since unregistration will not be stopped by mere keeping a reference to ctl_table_header. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'include')
-rw-r--r--include/linux/sysctl.h6
1 files changed, 6 insertions, 0 deletions
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index c1e0cf408af9..956264d09ba0 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -957,6 +957,11 @@ extern void setup_sysctl_set(struct ctl_table_set *p,
957 struct ctl_table_set *parent, 957 struct ctl_table_set *parent,
958 int (*is_seen)(struct ctl_table_set *)); 958 int (*is_seen)(struct ctl_table_set *));
959 959
960struct ctl_table_header;
961
962extern void sysctl_head_get(struct ctl_table_header *);
963extern void sysctl_head_put(struct ctl_table_header *);
964extern struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *);
960extern struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev); 965extern struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev);
961extern struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces, 966extern struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
962 struct ctl_table_header *prev); 967 struct ctl_table_header *prev);
@@ -1073,6 +1078,7 @@ struct ctl_table_header
1073 struct ctl_table *ctl_table; 1078 struct ctl_table *ctl_table;
1074 struct list_head ctl_entry; 1079 struct list_head ctl_entry;
1075 int used; 1080 int used;
1081 int count;
1076 struct completion *unregistering; 1082 struct completion *unregistering;
1077 struct ctl_table *ctl_table_arg; 1083 struct ctl_table *ctl_table_arg;
1078 struct ctl_table_root *root; 1084 struct ctl_table_root *root;