aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-10-12 22:16:02 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2014-11-19 13:01:19 -0500
commitb5ae6b15bd73e35b129408755a0804287a87e041 (patch)
treebc674dfb16177844acf90fed70320dd641fe77cd /fs/dcache.c
parent154e80e4c3ad3b1713ad0b9670ac2e91c677c101 (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.c143
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 */
2578static struct dentry *__d_unalias(struct inode *inode, 2578static 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;
2595out_unalias: 2595out_unalias:
2596 __d_move(alias, dentry, false); 2596 __d_move(alias, dentry, false);
2597 ret = alias; 2597 ret = 0;
2598out_err: 2598out_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 */
2630struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) 2630struct 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}
2673EXPORT_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 */
2684struct 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);
2744found:
2745 spin_unlock(&inode->i_lock); 2676 spin_unlock(&inode->i_lock);
2746out_nolock: 2677out:
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}
2755EXPORT_SYMBOL_GPL(d_materialise_unique); 2682EXPORT_SYMBOL(d_splice_alias);
2756 2683
2757static int prepend(char **buffer, int *buflen, const char *str, int namelen) 2684static int prepend(char **buffer, int *buflen, const char *str, int namelen)
2758{ 2685{