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/dir.c | |
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/dir.c')
-rw-r--r-- | fs/kernfs/dir.c | 114 |
1 files changed, 26 insertions, 88 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; |