aboutsummaryrefslogtreecommitdiffstats
path: root/fs
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 18:52:48 -0500
commitd35258ef702cca0c4e66d799f8e38b78c02ce8a5 (patch)
treef3d98795cf620ad32edd4df982d015cfeedd1a97 /fs
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 'fs')
-rw-r--r--fs/kernfs/dir.c71
-rw-r--r--fs/sysfs/mount.c2
2 files changed, 65 insertions, 8 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 89f8462f337e..3cff0a233cd1 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -435,7 +435,7 @@ int kernfs_add_one(struct kernfs_node *kn)
435 goto out_unlock; 435 goto out_unlock;
436 436
437 ret = -ENOENT; 437 ret = -ENOENT;
438 if (!kernfs_active(parent)) 438 if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent))
439 goto out_unlock; 439 goto out_unlock;
440 440
441 kn->hash = kernfs_name_hash(kn->name, kn->ns); 441 kn->hash = kernfs_name_hash(kn->name, kn->ns);
@@ -451,9 +451,19 @@ int kernfs_add_one(struct kernfs_node *kn)
451 ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; 451 ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME;
452 } 452 }
453 453
454 /* Mark the entry added into directory tree */ 454 mutex_unlock(&kernfs_mutex);
455 atomic_sub(KN_DEACTIVATED_BIAS, &kn->active); 455
456 ret = 0; 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
457out_unlock: 467out_unlock:
458 mutex_unlock(&kernfs_mutex); 468 mutex_unlock(&kernfs_mutex);
459 return ret; 469 return ret;
@@ -528,13 +538,14 @@ EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns);
528/** 538/**
529 * kernfs_create_root - create a new kernfs hierarchy 539 * kernfs_create_root - create a new kernfs hierarchy
530 * @scops: optional syscall operations for the hierarchy 540 * @scops: optional syscall operations for the hierarchy
541 * @flags: KERNFS_ROOT_* flags
531 * @priv: opaque data associated with the new directory 542 * @priv: opaque data associated with the new directory
532 * 543 *
533 * Returns the root of the new hierarchy on success, ERR_PTR() value on 544 * Returns the root of the new hierarchy on success, ERR_PTR() value on
534 * failure. 545 * failure.
535 */ 546 */
536struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops, 547struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
537 void *priv) 548 unsigned int flags, void *priv)
538{ 549{
539 struct kernfs_root *root; 550 struct kernfs_root *root;
540 struct kernfs_node *kn; 551 struct kernfs_node *kn;
@@ -553,14 +564,17 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
553 return ERR_PTR(-ENOMEM); 564 return ERR_PTR(-ENOMEM);
554 } 565 }
555 566
556 atomic_sub(KN_DEACTIVATED_BIAS, &kn->active);
557 kn->priv = priv; 567 kn->priv = priv;
558 kn->dir.root = root; 568 kn->dir.root = root;
559 569
560 root->syscall_ops = scops; 570 root->syscall_ops = scops;
571 root->flags = flags;
561 root->kn = kn; 572 root->kn = kn;
562 init_waitqueue_head(&root->deactivate_waitq); 573 init_waitqueue_head(&root->deactivate_waitq);
563 574
575 if (!(root->flags & KERNFS_ROOT_CREATE_DEACTIVATED))
576 kernfs_activate(kn);
577
564 return root; 578 return root;
565} 579}
566 580
@@ -783,6 +797,40 @@ static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos,
783 return pos->parent; 797 return pos->parent;
784} 798}
785 799
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 */
813void 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
786static void __kernfs_remove(struct kernfs_node *kn) 834static void __kernfs_remove(struct kernfs_node *kn)
787{ 835{
788 struct kernfs_node *pos; 836 struct kernfs_node *pos;
@@ -817,7 +865,16 @@ static void __kernfs_remove(struct kernfs_node *kn)
817 */ 865 */
818 kernfs_get(pos); 866 kernfs_get(pos);
819 867
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);
821 878
822 /* 879 /*
823 * kernfs_unlink_sibling() succeeds once per node. Use it 880 * kernfs_unlink_sibling() succeeds once per node. Use it
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 6211230814fd..5c7fdd9c6811 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -62,7 +62,7 @@ int __init sysfs_init(void)
62{ 62{
63 int err; 63 int err;
64 64
65 sysfs_root = kernfs_create_root(NULL, NULL); 65 sysfs_root = kernfs_create_root(NULL, 0, NULL);
66 if (IS_ERR(sysfs_root)) 66 if (IS_ERR(sysfs_root))
67 return PTR_ERR(sysfs_root); 67 return PTR_ERR(sysfs_root);
68 68