diff options
author | Tejun Heo <tj@kernel.org> | 2014-01-10 08:57:24 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-01-10 16:48:08 -0500 |
commit | 99177a34110889a8f2c36420c34e3bcc9bfd8a70 (patch) | |
tree | 53aa8ccc23e3bd92192a8d0518aa4f5f84a634d9 /fs/kernfs | |
parent | f601f9a2bf7dc1f7ee18feece4c4e2fc6845d6c4 (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.c | 114 | ||||
-rw-r--r-- | fs/kernfs/file.c | 10 | ||||
-rw-r--r-- | fs/kernfs/kernfs-internal.h | 12 | ||||
-rw-r--r-- | fs/kernfs/symlink.c | 10 |
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 | */ | ||
413 | void 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 | */ |
442 | int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn, | 414 | int 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 | } | 452 | out_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 | */ | ||
491 | void 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 | ||
844 | static void __kernfs_remove(struct kernfs_addrm_cxt *acxt, | 787 | static 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 | */ |
907 | void kernfs_remove(struct kernfs_node *kn) | 848 | void 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) | |||
925 | int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, | 864 | int 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 | */ | ||
51 | struct kernfs_addrm_cxt { | ||
52 | struct kernfs_node *removed; | ||
53 | }; | ||
54 | |||
55 | /* | ||
56 | * mount.c | 49 | * mount.c |
57 | */ | 50 | */ |
58 | struct kernfs_super_info { | 51 | struct kernfs_super_info { |
@@ -101,10 +94,7 @@ extern const struct inode_operations kernfs_dir_iops; | |||
101 | 94 | ||
102 | struct kernfs_node *kernfs_get_active(struct kernfs_node *kn); | 95 | struct kernfs_node *kernfs_get_active(struct kernfs_node *kn); |
103 | void kernfs_put_active(struct kernfs_node *kn); | 96 | void kernfs_put_active(struct kernfs_node *kn); |
104 | void kernfs_addrm_start(struct kernfs_addrm_cxt *acxt); | 97 | int kernfs_add_one(struct kernfs_node *kn, struct kernfs_node *parent); |
105 | int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn, | ||
106 | struct kernfs_node *parent); | ||
107 | void kernfs_addrm_finish(struct kernfs_addrm_cxt *acxt); | ||
108 | struct kernfs_node *kernfs_new_node(struct kernfs_root *root, const char *name, | 98 | struct 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 | ||