aboutsummaryrefslogtreecommitdiffstats
path: root/fs/kernfs
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2014-01-10 08:57:24 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-10 16:48:08 -0500
commit99177a34110889a8f2c36420c34e3bcc9bfd8a70 (patch)
tree53aa8ccc23e3bd92192a8d0518aa4f5f84a634d9 /fs/kernfs
parentf601f9a2bf7dc1f7ee18feece4c4e2fc6845d6c4 (diff)
kernfs: remove kernfs_addrm_cxt
kernfs_addrm_cxt and the accompanying kernfs_addrm_start/finish() were added because there were operations which should be performed outside kernfs_mutex after adding and removing kernfs_nodes. The necessary operations were recorded in kernfs_addrm_cxt and performed by kernfs_addrm_finish(); however, after the recent changes which relocated deactivation and unmapping so that they're performed directly during removal, the only operation kernfs_addrm_finish() performs is kernfs_put(), which can be moved inside the removal path too. This patch moves the kernfs_put() of the base ref to __kernfs_remove() and remove kernfs_addrm_cxt and kernfs_addrm_start/finish(). * kernfs_add_one() is updated to grab and release the parent's active ref and kernfs_mutex itself. kernfs_get/put_active() and kernfs_addrm_start/finish() invocations around it are removed from all users. * __kernfs_remove() puts an unlinked node directly instead of chaining it to kernfs_addrm_cxt. Its callers are updated to grab and release kernfs_mutex instead of calling kernfs_addrm_start/finish() around it. v2: Updated to fit the v2 restructuring of removal path. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/kernfs')
-rw-r--r--fs/kernfs/dir.c114
-rw-r--r--fs/kernfs/file.c10
-rw-r--r--fs/kernfs/kernfs-internal.h12
-rw-r--r--fs/kernfs/symlink.c10
4 files changed, 29 insertions, 117 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index f878e4f2efe7..770d687ee9f3 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -399,28 +399,7 @@ struct kernfs_node *kernfs_new_node(struct kernfs_root *root, const char *name,
399} 399}
400 400
401/** 401/**
402 * kernfs_addrm_start - prepare for kernfs_node add/remove
403 * @acxt: pointer to kernfs_addrm_cxt to be used
404 *
405 * This function is called when the caller is about to add or remove
406 * kernfs_node. This function acquires kernfs_mutex. @acxt is used
407 * to keep and pass context to other addrm functions.
408 *
409 * LOCKING:
410 * Kernel thread context (may sleep). kernfs_mutex is locked on
411 * return.
412 */
413void kernfs_addrm_start(struct kernfs_addrm_cxt *acxt)
414 __acquires(kernfs_mutex)
415{
416 memset(acxt, 0, sizeof(*acxt));
417
418 mutex_lock(&kernfs_mutex);
419}
420
421/**
422 * kernfs_add_one - add kernfs_node to parent without warning 402 * kernfs_add_one - add kernfs_node to parent without warning
423 * @acxt: addrm context to use
424 * @kn: kernfs_node to be added 403 * @kn: kernfs_node to be added
425 * @parent: the parent kernfs_node to add @kn to 404 * @parent: the parent kernfs_node to add @kn to
426 * 405 *
@@ -428,34 +407,29 @@ void kernfs_addrm_start(struct kernfs_addrm_cxt *acxt)
428 * parent inode if @kn is a directory and link into the children list 407 * parent inode if @kn is a directory and link into the children list
429 * of the parent. 408 * of the parent.
430 * 409 *
431 * This function should be called between calls to
432 * kernfs_addrm_start() and kernfs_addrm_finish() and should be passed
433 * the same @acxt as passed to kernfs_addrm_start().
434 *
435 * LOCKING:
436 * Determined by kernfs_addrm_start().
437 *
438 * RETURNS: 410 * RETURNS:
439 * 0 on success, -EEXIST if entry with the given name already 411 * 0 on success, -EEXIST if entry with the given name already
440 * exists. 412 * exists.
441 */ 413 */
442int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn, 414int kernfs_add_one(struct kernfs_node *kn, struct kernfs_node *parent)
443 struct kernfs_node *parent)
444{ 415{
445 bool has_ns = kernfs_ns_enabled(parent);
446 struct kernfs_iattrs *ps_iattr; 416 struct kernfs_iattrs *ps_iattr;
417 bool has_ns;
447 int ret; 418 int ret;
448 419
449 WARN_ON_ONCE(atomic_read(&parent->active) < 0); 420 if (!kernfs_get_active(parent))
421 return -ENOENT;
450 422
451 if (has_ns != (bool)kn->ns) { 423 mutex_lock(&kernfs_mutex);
452 WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", 424
453 has_ns ? "required" : "invalid", parent->name, kn->name); 425 ret = -EINVAL;
454 return -EINVAL; 426 has_ns = kernfs_ns_enabled(parent);
455 } 427 if (WARN(has_ns != (bool)kn->ns, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n",
428 has_ns ? "required" : "invalid", parent->name, kn->name))
429 goto out_unlock;
456 430
457 if (kernfs_type(parent) != KERNFS_DIR) 431 if (kernfs_type(parent) != KERNFS_DIR)
458 return -EINVAL; 432 goto out_unlock;
459 433
460 kn->hash = kernfs_name_hash(kn->name, kn->ns); 434 kn->hash = kernfs_name_hash(kn->name, kn->ns);
461 kn->parent = parent; 435 kn->parent = parent;
@@ -463,7 +437,7 @@ int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn,
463 437
464 ret = kernfs_link_sibling(kn); 438 ret = kernfs_link_sibling(kn);
465 if (ret) 439 if (ret)
466 return ret; 440 goto out_unlock;
467 441
468 /* Update timestamps on the parent */ 442 /* Update timestamps on the parent */
469 ps_iattr = parent->iattr; 443 ps_iattr = parent->iattr;
@@ -474,34 +448,11 @@ int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn,
474 448
475 /* Mark the entry added into directory tree */ 449 /* Mark the entry added into directory tree */
476 atomic_sub(KN_DEACTIVATED_BIAS, &kn->active); 450 atomic_sub(KN_DEACTIVATED_BIAS, &kn->active);
477 return 0; 451 ret = 0;
478} 452out_unlock:
479
480/**
481 * kernfs_addrm_finish - finish up kernfs_node add/remove
482 * @acxt: addrm context to finish up
483 *
484 * Finish up kernfs_node add/remove. Resources acquired by
485 * kernfs_addrm_start() are released and removed kernfs_nodes are
486 * cleaned up.
487 *
488 * LOCKING:
489 * kernfs_mutex is released.
490 */
491void kernfs_addrm_finish(struct kernfs_addrm_cxt *acxt)
492 __releases(kernfs_mutex)
493{
494 /* release resources acquired by kernfs_addrm_start() */
495 mutex_unlock(&kernfs_mutex); 453 mutex_unlock(&kernfs_mutex);
496 454 kernfs_put_active(parent);
497 /* kill removed kernfs_nodes */ 455 return ret;
498 while (acxt->removed) {
499 struct kernfs_node *kn = acxt->removed;
500
501 acxt->removed = kn->u.removed_list;
502
503 kernfs_put(kn);
504 }
505} 456}
506 457
507/** 458/**
@@ -633,7 +584,6 @@ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
633 const char *name, umode_t mode, 584 const char *name, umode_t mode,
634 void *priv, const void *ns) 585 void *priv, const void *ns)
635{ 586{
636 struct kernfs_addrm_cxt acxt;
637 struct kernfs_node *kn; 587 struct kernfs_node *kn;
638 int rc; 588 int rc;
639 589
@@ -648,14 +598,7 @@ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
648 kn->priv = priv; 598 kn->priv = priv;
649 599
650 /* link in */ 600 /* link in */
651 rc = -ENOENT; 601 rc = kernfs_add_one(kn, parent);
652 if (kernfs_get_active(parent)) {
653 kernfs_addrm_start(&acxt);
654 rc = kernfs_add_one(&acxt, kn, parent);
655 kernfs_addrm_finish(&acxt);
656 kernfs_put_active(parent);
657 }
658
659 if (!rc) 602 if (!rc)
660 return kn; 603 return kn;
661 604
@@ -841,8 +784,7 @@ static void __kernfs_deactivate(struct kernfs_node *kn)
841 } 784 }
842} 785}
843 786
844static void __kernfs_remove(struct kernfs_addrm_cxt *acxt, 787static void __kernfs_remove(struct kernfs_node *kn)
845 struct kernfs_node *kn)
846{ 788{
847 struct kernfs_node *pos; 789 struct kernfs_node *pos;
848 790
@@ -890,8 +832,7 @@ static void __kernfs_remove(struct kernfs_addrm_cxt *acxt,
890 ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME; 832 ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME;
891 } 833 }
892 834
893 pos->u.removed_list = acxt->removed; 835 kernfs_put(pos);
894 acxt->removed = pos;
895 } 836 }
896 837
897 kernfs_put(pos); 838 kernfs_put(pos);
@@ -906,11 +847,9 @@ static void __kernfs_remove(struct kernfs_addrm_cxt *acxt,
906 */ 847 */
907void kernfs_remove(struct kernfs_node *kn) 848void kernfs_remove(struct kernfs_node *kn)
908{ 849{
909 struct kernfs_addrm_cxt acxt; 850 mutex_lock(&kernfs_mutex);
910 851 __kernfs_remove(kn);
911 kernfs_addrm_start(&acxt); 852 mutex_unlock(&kernfs_mutex);
912 __kernfs_remove(&acxt, kn);
913 kernfs_addrm_finish(&acxt);
914} 853}
915 854
916/** 855/**
@@ -925,7 +864,6 @@ void kernfs_remove(struct kernfs_node *kn)
925int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, 864int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name,
926 const void *ns) 865 const void *ns)
927{ 866{
928 struct kernfs_addrm_cxt acxt;
929 struct kernfs_node *kn; 867 struct kernfs_node *kn;
930 868
931 if (!parent) { 869 if (!parent) {
@@ -934,13 +872,13 @@ int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name,
934 return -ENOENT; 872 return -ENOENT;
935 } 873 }
936 874
937 kernfs_addrm_start(&acxt); 875 mutex_lock(&kernfs_mutex);
938 876
939 kn = kernfs_find_ns(parent, name, ns); 877 kn = kernfs_find_ns(parent, name, ns);
940 if (kn) 878 if (kn)
941 __kernfs_remove(&acxt, kn); 879 __kernfs_remove(kn);
942 880
943 kernfs_addrm_finish(&acxt); 881 mutex_unlock(&kernfs_mutex);
944 882
945 if (kn) 883 if (kn)
946 return 0; 884 return 0;
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index 404ffd2f27bc..ffe1bebf9197 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -817,7 +817,6 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
817 bool name_is_static, 817 bool name_is_static,
818 struct lock_class_key *key) 818 struct lock_class_key *key)
819{ 819{
820 struct kernfs_addrm_cxt acxt;
821 struct kernfs_node *kn; 820 struct kernfs_node *kn;
822 unsigned flags; 821 unsigned flags;
823 int rc; 822 int rc;
@@ -853,14 +852,7 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
853 if (ops->mmap) 852 if (ops->mmap)
854 kn->flags |= KERNFS_HAS_MMAP; 853 kn->flags |= KERNFS_HAS_MMAP;
855 854
856 rc = -ENOENT; 855 rc = kernfs_add_one(kn, parent);
857 if (kernfs_get_active(parent)) {
858 kernfs_addrm_start(&acxt);
859 rc = kernfs_add_one(&acxt, kn, parent);
860 kernfs_addrm_finish(&acxt);
861 kernfs_put_active(parent);
862 }
863
864 if (rc) { 856 if (rc) {
865 kernfs_put(kn); 857 kernfs_put(kn);
866 return ERR_PTR(rc); 858 return ERR_PTR(rc);
diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
index e9ec38c86074..4bc57848076c 100644
--- a/fs/kernfs/kernfs-internal.h
+++ b/fs/kernfs/kernfs-internal.h
@@ -46,13 +46,6 @@ static inline struct kernfs_root *kernfs_root(struct kernfs_node *kn)
46} 46}
47 47
48/* 48/*
49 * Context structure to be used while adding/removing nodes.
50 */
51struct kernfs_addrm_cxt {
52 struct kernfs_node *removed;
53};
54
55/*
56 * mount.c 49 * mount.c
57 */ 50 */
58struct kernfs_super_info { 51struct kernfs_super_info {
@@ -101,10 +94,7 @@ extern const struct inode_operations kernfs_dir_iops;
101 94
102struct kernfs_node *kernfs_get_active(struct kernfs_node *kn); 95struct kernfs_node *kernfs_get_active(struct kernfs_node *kn);
103void kernfs_put_active(struct kernfs_node *kn); 96void kernfs_put_active(struct kernfs_node *kn);
104void kernfs_addrm_start(struct kernfs_addrm_cxt *acxt); 97int kernfs_add_one(struct kernfs_node *kn, struct kernfs_node *parent);
105int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn,
106 struct kernfs_node *parent);
107void kernfs_addrm_finish(struct kernfs_addrm_cxt *acxt);
108struct kernfs_node *kernfs_new_node(struct kernfs_root *root, const char *name, 98struct kernfs_node *kernfs_new_node(struct kernfs_root *root, const char *name,
109 umode_t mode, unsigned flags); 99 umode_t mode, unsigned flags);
110 100
diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
index b2c106ca3434..3a939c263ede 100644
--- a/fs/kernfs/symlink.c
+++ b/fs/kernfs/symlink.c
@@ -27,7 +27,6 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
27 struct kernfs_node *target) 27 struct kernfs_node *target)
28{ 28{
29 struct kernfs_node *kn; 29 struct kernfs_node *kn;
30 struct kernfs_addrm_cxt acxt;
31 int error; 30 int error;
32 31
33 kn = kernfs_new_node(kernfs_root(parent), name, S_IFLNK|S_IRWXUGO, 32 kn = kernfs_new_node(kernfs_root(parent), name, S_IFLNK|S_IRWXUGO,
@@ -40,14 +39,7 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
40 kn->symlink.target_kn = target; 39 kn->symlink.target_kn = target;
41 kernfs_get(target); /* ref owned by symlink */ 40 kernfs_get(target); /* ref owned by symlink */
42 41
43 error = -ENOENT; 42 error = kernfs_add_one(kn, parent);
44 if (kernfs_get_active(parent)) {
45 kernfs_addrm_start(&acxt);
46 error = kernfs_add_one(&acxt, kn, parent);
47 kernfs_addrm_finish(&acxt);
48 kernfs_put_active(parent);
49 }
50
51 if (!error) 43 if (!error)
52 return kn; 44 return kn;
53 45