diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-10-12 22:16:02 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-11-19 13:01:19 -0500 |
commit | b5ae6b15bd73e35b129408755a0804287a87e041 (patch) | |
tree | bc674dfb16177844acf90fed70320dd641fe77cd /fs/dcache.c | |
parent | 154e80e4c3ad3b1713ad0b9670ac2e91c677c101 (diff) |
merge d_materialise_unique() into d_splice_alias()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 143 |
1 files changed, 35 insertions, 108 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index e605e90d0f0a..435991eada1e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -2575,11 +2575,11 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2) | |||
2575 | * Note: If ever the locking in lock_rename() changes, then please | 2575 | * Note: If ever the locking in lock_rename() changes, then please |
2576 | * remember to update this too... | 2576 | * remember to update this too... |
2577 | */ | 2577 | */ |
2578 | static struct dentry *__d_unalias(struct inode *inode, | 2578 | static int __d_unalias(struct inode *inode, |
2579 | struct dentry *dentry, struct dentry *alias) | 2579 | struct dentry *dentry, struct dentry *alias) |
2580 | { | 2580 | { |
2581 | struct mutex *m1 = NULL, *m2 = NULL; | 2581 | struct mutex *m1 = NULL, *m2 = NULL; |
2582 | struct dentry *ret = ERR_PTR(-EBUSY); | 2582 | int ret = -EBUSY; |
2583 | 2583 | ||
2584 | /* If alias and dentry share a parent, then no extra locks required */ | 2584 | /* If alias and dentry share a parent, then no extra locks required */ |
2585 | if (alias->d_parent == dentry->d_parent) | 2585 | if (alias->d_parent == dentry->d_parent) |
@@ -2594,7 +2594,7 @@ static struct dentry *__d_unalias(struct inode *inode, | |||
2594 | m2 = &alias->d_parent->d_inode->i_mutex; | 2594 | m2 = &alias->d_parent->d_inode->i_mutex; |
2595 | out_unalias: | 2595 | out_unalias: |
2596 | __d_move(alias, dentry, false); | 2596 | __d_move(alias, dentry, false); |
2597 | ret = alias; | 2597 | ret = 0; |
2598 | out_err: | 2598 | out_err: |
2599 | spin_unlock(&inode->i_lock); | 2599 | spin_unlock(&inode->i_lock); |
2600 | if (m2) | 2600 | if (m2) |
@@ -2629,130 +2629,57 @@ out_err: | |||
2629 | */ | 2629 | */ |
2630 | struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) | 2630 | struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) |
2631 | { | 2631 | { |
2632 | struct dentry *new = NULL; | ||
2633 | |||
2634 | if (IS_ERR(inode)) | 2632 | if (IS_ERR(inode)) |
2635 | return ERR_CAST(inode); | 2633 | return ERR_CAST(inode); |
2636 | 2634 | ||
2637 | if (inode && S_ISDIR(inode->i_mode)) { | ||
2638 | spin_lock(&inode->i_lock); | ||
2639 | new = __d_find_any_alias(inode); | ||
2640 | if (new) { | ||
2641 | if (!IS_ROOT(new)) { | ||
2642 | spin_unlock(&inode->i_lock); | ||
2643 | dput(new); | ||
2644 | iput(inode); | ||
2645 | return ERR_PTR(-EIO); | ||
2646 | } | ||
2647 | if (d_ancestor(new, dentry)) { | ||
2648 | spin_unlock(&inode->i_lock); | ||
2649 | dput(new); | ||
2650 | iput(inode); | ||
2651 | return ERR_PTR(-EIO); | ||
2652 | } | ||
2653 | write_seqlock(&rename_lock); | ||
2654 | __d_move(new, dentry, false); | ||
2655 | write_sequnlock(&rename_lock); | ||
2656 | spin_unlock(&inode->i_lock); | ||
2657 | security_d_instantiate(new, inode); | ||
2658 | iput(inode); | ||
2659 | } else { | ||
2660 | /* already taking inode->i_lock, so d_add() by hand */ | ||
2661 | __d_instantiate(dentry, inode); | ||
2662 | spin_unlock(&inode->i_lock); | ||
2663 | security_d_instantiate(dentry, inode); | ||
2664 | d_rehash(dentry); | ||
2665 | } | ||
2666 | } else { | ||
2667 | d_instantiate(dentry, inode); | ||
2668 | if (d_unhashed(dentry)) | ||
2669 | d_rehash(dentry); | ||
2670 | } | ||
2671 | return new; | ||
2672 | } | ||
2673 | EXPORT_SYMBOL(d_splice_alias); | ||
2674 | |||
2675 | /** | ||
2676 | * d_materialise_unique - introduce an inode into the tree | ||
2677 | * @dentry: candidate dentry | ||
2678 | * @inode: inode to bind to the dentry, to which aliases may be attached | ||
2679 | * | ||
2680 | * Introduces an dentry into the tree, substituting an extant disconnected | ||
2681 | * root directory alias in its place if there is one. Caller must hold the | ||
2682 | * i_mutex of the parent directory. | ||
2683 | */ | ||
2684 | struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | ||
2685 | { | ||
2686 | struct dentry *actual; | ||
2687 | |||
2688 | BUG_ON(!d_unhashed(dentry)); | 2635 | BUG_ON(!d_unhashed(dentry)); |
2689 | 2636 | ||
2690 | if (!inode) { | 2637 | if (!inode) { |
2691 | actual = dentry; | ||
2692 | __d_instantiate(dentry, NULL); | 2638 | __d_instantiate(dentry, NULL); |
2693 | d_rehash(actual); | 2639 | goto out; |
2694 | goto out_nolock; | ||
2695 | } | 2640 | } |
2696 | |||
2697 | spin_lock(&inode->i_lock); | 2641 | spin_lock(&inode->i_lock); |
2698 | |||
2699 | if (S_ISDIR(inode->i_mode)) { | 2642 | if (S_ISDIR(inode->i_mode)) { |
2700 | struct dentry *alias; | 2643 | struct dentry *new = __d_find_any_alias(inode); |
2701 | 2644 | if (unlikely(new)) { | |
2702 | /* Does an aliased dentry already exist? */ | ||
2703 | alias = __d_find_alias(inode); | ||
2704 | if (alias) { | ||
2705 | actual = alias; | ||
2706 | write_seqlock(&rename_lock); | 2645 | write_seqlock(&rename_lock); |
2707 | 2646 | if (unlikely(d_ancestor(new, dentry))) { | |
2708 | if (d_ancestor(alias, dentry)) { | 2647 | write_sequnlock(&rename_lock); |
2709 | /* Check for loops */ | ||
2710 | actual = ERR_PTR(-ELOOP); | ||
2711 | spin_unlock(&inode->i_lock); | 2648 | spin_unlock(&inode->i_lock); |
2712 | } else if (IS_ROOT(alias)) { | 2649 | dput(new); |
2713 | /* Is this an anonymous mountpoint that we | 2650 | new = ERR_PTR(-ELOOP); |
2714 | * could splice into our tree? */ | 2651 | pr_warn_ratelimited( |
2715 | __d_move(alias, dentry, false); | 2652 | "VFS: Lookup of '%s' in %s %s" |
2653 | " would have caused loop\n", | ||
2654 | dentry->d_name.name, | ||
2655 | inode->i_sb->s_type->name, | ||
2656 | inode->i_sb->s_id); | ||
2657 | } else if (!IS_ROOT(new)) { | ||
2658 | int err = __d_unalias(inode, dentry, new); | ||
2716 | write_sequnlock(&rename_lock); | 2659 | write_sequnlock(&rename_lock); |
2717 | goto found; | 2660 | if (err) { |
2661 | dput(new); | ||
2662 | new = ERR_PTR(err); | ||
2663 | } | ||
2718 | } else { | 2664 | } else { |
2719 | /* Nope, but we must(!) avoid directory | 2665 | __d_move(new, dentry, false); |
2720 | * aliasing. This drops inode->i_lock */ | 2666 | write_sequnlock(&rename_lock); |
2721 | actual = __d_unalias(inode, dentry, alias); | 2667 | spin_unlock(&inode->i_lock); |
2722 | } | 2668 | security_d_instantiate(new, inode); |
2723 | write_sequnlock(&rename_lock); | ||
2724 | if (IS_ERR(actual)) { | ||
2725 | if (PTR_ERR(actual) == -ELOOP) | ||
2726 | pr_warn_ratelimited( | ||
2727 | "VFS: Lookup of '%s' in %s %s" | ||
2728 | " would have caused loop\n", | ||
2729 | dentry->d_name.name, | ||
2730 | inode->i_sb->s_type->name, | ||
2731 | inode->i_sb->s_id); | ||
2732 | dput(alias); | ||
2733 | } | 2669 | } |
2734 | goto out_nolock; | 2670 | iput(inode); |
2671 | return new; | ||
2735 | } | 2672 | } |
2736 | } | 2673 | } |
2737 | 2674 | /* already taking inode->i_lock, so d_add() by hand */ | |
2738 | /* Add a unique reference */ | 2675 | __d_instantiate(dentry, inode); |
2739 | actual = __d_instantiate_unique(dentry, inode); | ||
2740 | if (!actual) | ||
2741 | actual = dentry; | ||
2742 | |||
2743 | d_rehash(actual); | ||
2744 | found: | ||
2745 | spin_unlock(&inode->i_lock); | 2676 | spin_unlock(&inode->i_lock); |
2746 | out_nolock: | 2677 | out: |
2747 | if (actual == dentry) { | 2678 | security_d_instantiate(dentry, inode); |
2748 | security_d_instantiate(dentry, inode); | 2679 | d_rehash(dentry); |
2749 | return NULL; | 2680 | return NULL; |
2750 | } | ||
2751 | |||
2752 | iput(inode); | ||
2753 | return actual; | ||
2754 | } | 2681 | } |
2755 | EXPORT_SYMBOL_GPL(d_materialise_unique); | 2682 | EXPORT_SYMBOL(d_splice_alias); |
2756 | 2683 | ||
2757 | static int prepend(char **buffer, int *buflen, const char *str, int namelen) | 2684 | static int prepend(char **buffer, int *buflen, const char *str, int namelen) |
2758 | { | 2685 | { |