summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2014-02-03 14:09:12 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-02-07 15:52:48 -0800
commitd35258ef702cca0c4e66d799f8e38b78c02ce8a5 (patch)
treef3d98795cf620ad32edd4df982d015cfeedd1a97 /include
parentb9c9dad0c457d32cf8c7d2e413463c8414c7a7a7 (diff)
kernfs: allow nodes to be created in the deactivated state
Currently, kernfs_nodes are made visible to userland on creation, which makes it difficult for kernfs users to atomically succeed or fail creation of multiple nodes. In addition, if something fails after creating some nodes, the created nodes might already be in use and their active refs need to be drained for removal, which has the potential to introduce tricky reverse locking dependency on active_ref depending on how the error path is synchronized. This patch introduces per-root flag KERNFS_ROOT_CREATE_DEACTIVATED. If set, all nodes under the root are created in the deactivated state and stay invisible to userland until explicitly enabled by the new kernfs_activate() API. Also, nodes which have never been activated are guaranteed to bypass draining on removal thus allowing error paths to not worry about lockding dependency on active_ref draining. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'include')
-rw-r--r--include/linux/kernfs.h15
1 files changed, 13 insertions, 2 deletions
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index 5d5b7e947294..4520c86f5cb4 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -38,6 +38,7 @@ enum kernfs_node_type {
#define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK
enum kernfs_node_flag {
+ KERNFS_ACTIVATED = 0x0010,
KERNFS_NS = 0x0020,
KERNFS_HAS_SEQ_SHOW = 0x0040,
KERNFS_HAS_MMAP = 0x0080,
@@ -47,6 +48,11 @@ enum kernfs_node_flag {
KERNFS_SUICIDED = 0x0800,
};
+/* @flags for kernfs_create_root() */
+enum kernfs_root_flag {
+ KERNFS_ROOT_CREATE_DEACTIVATED = 0x0001,
+};
+
/* type-specific structures for kernfs_node union members */
struct kernfs_elem_dir {
unsigned long subdirs;
@@ -128,6 +134,7 @@ struct kernfs_syscall_ops {
struct kernfs_root {
/* published fields */
struct kernfs_node *kn;
+ unsigned int flags; /* KERNFS_ROOT_* flags */
/* private fields, do not use outside kernfs proper */
struct ida ino_ida;
@@ -223,7 +230,7 @@ void kernfs_get(struct kernfs_node *kn);
void kernfs_put(struct kernfs_node *kn);
struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
- void *priv);
+ unsigned int flags, void *priv);
void kernfs_destroy_root(struct kernfs_root *root);
struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
@@ -239,6 +246,7 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
const char *name,
struct kernfs_node *target);
+void kernfs_activate(struct kernfs_node *kn);
void kernfs_remove(struct kernfs_node *kn);
void kernfs_break_active_protection(struct kernfs_node *kn);
void kernfs_unbreak_active_protection(struct kernfs_node *kn);
@@ -276,7 +284,8 @@ static inline void kernfs_get(struct kernfs_node *kn) { }
static inline void kernfs_put(struct kernfs_node *kn) { }
static inline struct kernfs_root *
-kernfs_create_root(struct kernfs_syscall_ops *scops, void *priv)
+kernfs_create_root(struct kernfs_syscall_ops *scops, unsigned int flags,
+ void *priv)
{ return ERR_PTR(-ENOSYS); }
static inline void kernfs_destroy_root(struct kernfs_root *root) { }
@@ -298,6 +307,8 @@ kernfs_create_link(struct kernfs_node *parent, const char *name,
struct kernfs_node *target)
{ return ERR_PTR(-ENOSYS); }
+static inline void kernfs_activate(struct kernfs_node *kn) { }
+
static inline void kernfs_remove(struct kernfs_node *kn) { }
static inline bool kernfs_remove_self(struct kernfs_node *kn)