Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d35258e

Browse files
htejungregkh
authored andcommitted
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 <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent b9c9dad commit d35258e

File tree

3 files changed

+78
-10
lines changed

3 files changed

+78
-10
lines changed

fs/kernfs/dir.c

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ int kernfs_add_one(struct kernfs_node *kn)
435435
goto out_unlock;
436436

437437
ret = -ENOENT;
438-
if (!kernfs_active(parent))
438+
if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent))
439439
goto out_unlock;
440440

441441
kn->hash = kernfs_name_hash(kn->name, kn->ns);
@@ -451,9 +451,19 @@ int kernfs_add_one(struct kernfs_node *kn)
451451
ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME;
452452
}
453453

454-
/* Mark the entry added into directory tree */
455-
atomic_sub(KN_DEACTIVATED_BIAS, &kn->active);
456-
ret = 0;
454+
mutex_unlock(&kernfs_mutex);
455+
456+
/*
457+
* Activate the new node unless CREATE_DEACTIVATED is requested.
458+
* If not activated here, the kernfs user is responsible for
459+
* activating the node with kernfs_activate(). A node which hasn't
460+
* been activated is not visible to userland and its removal won't
461+
* trigger deactivation.
462+
*/
463+
if (!(kernfs_root(kn)->flags & KERNFS_ROOT_CREATE_DEACTIVATED))
464+
kernfs_activate(kn);
465+
return 0;
466+
457467
out_unlock:
458468
mutex_unlock(&kernfs_mutex);
459469
return ret;
@@ -528,13 +538,14 @@ EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns);
528538
/**
529539
* kernfs_create_root - create a new kernfs hierarchy
530540
* @scops: optional syscall operations for the hierarchy
541+
* @flags: KERNFS_ROOT_* flags
531542
* @priv: opaque data associated with the new directory
532543
*
533544
* Returns the root of the new hierarchy on success, ERR_PTR() value on
534545
* failure.
535546
*/
536547
struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
537-
void *priv)
548+
unsigned int flags, void *priv)
538549
{
539550
struct kernfs_root *root;
540551
struct kernfs_node *kn;
@@ -553,14 +564,17 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
553564
return ERR_PTR(-ENOMEM);
554565
}
555566

556-
atomic_sub(KN_DEACTIVATED_BIAS, &kn->active);
557567
kn->priv = priv;
558568
kn->dir.root = root;
559569

560570
root->syscall_ops = scops;
571+
root->flags = flags;
561572
root->kn = kn;
562573
init_waitqueue_head(&root->deactivate_waitq);
563574

575+
if (!(root->flags & KERNFS_ROOT_CREATE_DEACTIVATED))
576+
kernfs_activate(kn);
577+
564578
return root;
565579
}
566580

@@ -783,6 +797,40 @@ static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos,
783797
return pos->parent;
784798
}
785799

800+
/**
801+
* kernfs_activate - activate a node which started deactivated
802+
* @kn: kernfs_node whose subtree is to be activated
803+
*
804+
* If the root has KERNFS_ROOT_CREATE_DEACTIVATED set, a newly created node
805+
* needs to be explicitly activated. A node which hasn't been activated
806+
* isn't visible to userland and deactivation is skipped during its
807+
* removal. This is useful to construct atomic init sequences where
808+
* creation of multiple nodes should either succeed or fail atomically.
809+
*
810+
* The caller is responsible for ensuring that this function is not called
811+
* after kernfs_remove*() is invoked on @kn.
812+
*/
813+
void kernfs_activate(struct kernfs_node *kn)
814+
{
815+
struct kernfs_node *pos;
816+
817+
mutex_lock(&kernfs_mutex);
818+
819+
pos = NULL;
820+
while ((pos = kernfs_next_descendant_post(pos, kn))) {
821+
if (!pos || (pos->flags & KERNFS_ACTIVATED))
822+
continue;
823+
824+
WARN_ON_ONCE(pos->parent && RB_EMPTY_NODE(&pos->rb));
825+
WARN_ON_ONCE(atomic_read(&pos->active) != KN_DEACTIVATED_BIAS);
826+
827+
atomic_sub(KN_DEACTIVATED_BIAS, &pos->active);
828+
pos->flags |= KERNFS_ACTIVATED;
829+
}
830+
831+
mutex_unlock(&kernfs_mutex);
832+
}
833+
786834
static void __kernfs_remove(struct kernfs_node *kn)
787835
{
788836
struct kernfs_node *pos;
@@ -817,7 +865,16 @@ static void __kernfs_remove(struct kernfs_node *kn)
817865
*/
818866
kernfs_get(pos);
819867

820-
kernfs_drain(pos);
868+
/*
869+
* Drain iff @kn was activated. This avoids draining and
870+
* its lockdep annotations for nodes which have never been
871+
* activated and allows embedding kernfs_remove() in create
872+
* error paths without worrying about draining.
873+
*/
874+
if (kn->flags & KERNFS_ACTIVATED)
875+
kernfs_drain(pos);
876+
else
877+
WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS);
821878

822879
/*
823880
* kernfs_unlink_sibling() succeeds once per node. Use it

fs/sysfs/mount.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ int __init sysfs_init(void)
6262
{
6363
int err;
6464

65-
sysfs_root = kernfs_create_root(NULL, NULL);
65+
sysfs_root = kernfs_create_root(NULL, 0, NULL);
6666
if (IS_ERR(sysfs_root))
6767
return PTR_ERR(sysfs_root);
6868

include/linux/kernfs.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ enum kernfs_node_type {
3838
#define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK
3939

4040
enum kernfs_node_flag {
41+
KERNFS_ACTIVATED = 0x0010,
4142
KERNFS_NS = 0x0020,
4243
KERNFS_HAS_SEQ_SHOW = 0x0040,
4344
KERNFS_HAS_MMAP = 0x0080,
@@ -47,6 +48,11 @@ enum kernfs_node_flag {
4748
KERNFS_SUICIDED = 0x0800,
4849
};
4950

51+
/* @flags for kernfs_create_root() */
52+
enum kernfs_root_flag {
53+
KERNFS_ROOT_CREATE_DEACTIVATED = 0x0001,
54+
};
55+
5056
/* type-specific structures for kernfs_node union members */
5157
struct kernfs_elem_dir {
5258
unsigned long subdirs;
@@ -128,6 +134,7 @@ struct kernfs_syscall_ops {
128134
struct kernfs_root {
129135
/* published fields */
130136
struct kernfs_node *kn;
137+
unsigned int flags; /* KERNFS_ROOT_* flags */
131138

132139
/* private fields, do not use outside kernfs proper */
133140
struct ida ino_ida;
@@ -223,7 +230,7 @@ void kernfs_get(struct kernfs_node *kn);
223230
void kernfs_put(struct kernfs_node *kn);
224231

225232
struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
226-
void *priv);
233+
unsigned int flags, void *priv);
227234
void kernfs_destroy_root(struct kernfs_root *root);
228235

229236
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,
239246
struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
240247
const char *name,
241248
struct kernfs_node *target);
249+
void kernfs_activate(struct kernfs_node *kn);
242250
void kernfs_remove(struct kernfs_node *kn);
243251
void kernfs_break_active_protection(struct kernfs_node *kn);
244252
void kernfs_unbreak_active_protection(struct kernfs_node *kn);
@@ -276,7 +284,8 @@ static inline void kernfs_get(struct kernfs_node *kn) { }
276284
static inline void kernfs_put(struct kernfs_node *kn) { }
277285

278286
static inline struct kernfs_root *
279-
kernfs_create_root(struct kernfs_syscall_ops *scops, void *priv)
287+
kernfs_create_root(struct kernfs_syscall_ops *scops, unsigned int flags,
288+
void *priv)
280289
{ return ERR_PTR(-ENOSYS); }
281290

282291
static inline void kernfs_destroy_root(struct kernfs_root *root) { }
@@ -298,6 +307,8 @@ kernfs_create_link(struct kernfs_node *parent, const char *name,
298307
struct kernfs_node *target)
299308
{ return ERR_PTR(-ENOSYS); }
300309

310+
static inline void kernfs_activate(struct kernfs_node *kn) { }
311+
301312
static inline void kernfs_remove(struct kernfs_node *kn) { }
302313

303314
static inline bool kernfs_remove_self(struct kernfs_node *kn)

0 commit comments

Comments
 (0)