diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 16 |
1 files changed, 10 insertions, 6 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 85c9e2bff8e6..40469044088d 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -683,6 +683,8 @@ EXPORT_SYMBOL(dget_parent); | |||
683 | /** | 683 | /** |
684 | * d_find_alias - grab a hashed alias of inode | 684 | * d_find_alias - grab a hashed alias of inode |
685 | * @inode: inode in question | 685 | * @inode: inode in question |
686 | * @want_discon: flag, used by d_splice_alias, to request | ||
687 | * that only a DISCONNECTED alias be returned. | ||
686 | * | 688 | * |
687 | * If inode has a hashed alias, or is a directory and has any alias, | 689 | * If inode has a hashed alias, or is a directory and has any alias, |
688 | * acquire the reference to alias and return it. Otherwise return NULL. | 690 | * acquire the reference to alias and return it. Otherwise return NULL. |
@@ -691,9 +693,10 @@ EXPORT_SYMBOL(dget_parent); | |||
691 | * of a filesystem. | 693 | * of a filesystem. |
692 | * | 694 | * |
693 | * If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer | 695 | * If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer |
694 | * any other hashed alias over that. | 696 | * any other hashed alias over that one unless @want_discon is set, |
697 | * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias. | ||
695 | */ | 698 | */ |
696 | static struct dentry *__d_find_alias(struct inode *inode) | 699 | static struct dentry *__d_find_alias(struct inode *inode, int want_discon) |
697 | { | 700 | { |
698 | struct dentry *alias, *discon_alias; | 701 | struct dentry *alias, *discon_alias; |
699 | 702 | ||
@@ -705,7 +708,7 @@ again: | |||
705 | if (IS_ROOT(alias) && | 708 | if (IS_ROOT(alias) && |
706 | (alias->d_flags & DCACHE_DISCONNECTED)) { | 709 | (alias->d_flags & DCACHE_DISCONNECTED)) { |
707 | discon_alias = alias; | 710 | discon_alias = alias; |
708 | } else { | 711 | } else if (!want_discon) { |
709 | __dget_dlock(alias); | 712 | __dget_dlock(alias); |
710 | spin_unlock(&alias->d_lock); | 713 | spin_unlock(&alias->d_lock); |
711 | return alias; | 714 | return alias; |
@@ -736,7 +739,7 @@ struct dentry *d_find_alias(struct inode *inode) | |||
736 | 739 | ||
737 | if (!list_empty(&inode->i_dentry)) { | 740 | if (!list_empty(&inode->i_dentry)) { |
738 | spin_lock(&inode->i_lock); | 741 | spin_lock(&inode->i_lock); |
739 | de = __d_find_alias(inode); | 742 | de = __d_find_alias(inode, 0); |
740 | spin_unlock(&inode->i_lock); | 743 | spin_unlock(&inode->i_lock); |
741 | } | 744 | } |
742 | return de; | 745 | return de; |
@@ -1647,8 +1650,9 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) | |||
1647 | 1650 | ||
1648 | if (inode && S_ISDIR(inode->i_mode)) { | 1651 | if (inode && S_ISDIR(inode->i_mode)) { |
1649 | spin_lock(&inode->i_lock); | 1652 | spin_lock(&inode->i_lock); |
1650 | new = __d_find_any_alias(inode); | 1653 | new = __d_find_alias(inode, 1); |
1651 | if (new) { | 1654 | if (new) { |
1655 | BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED)); | ||
1652 | spin_unlock(&inode->i_lock); | 1656 | spin_unlock(&inode->i_lock); |
1653 | security_d_instantiate(new, inode); | 1657 | security_d_instantiate(new, inode); |
1654 | d_move(new, dentry); | 1658 | d_move(new, dentry); |
@@ -2478,7 +2482,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | |||
2478 | struct dentry *alias; | 2482 | struct dentry *alias; |
2479 | 2483 | ||
2480 | /* Does an aliased dentry already exist? */ | 2484 | /* Does an aliased dentry already exist? */ |
2481 | alias = __d_find_alias(inode); | 2485 | alias = __d_find_alias(inode, 0); |
2482 | if (alias) { | 2486 | if (alias) { |
2483 | actual = alias; | 2487 | actual = alias; |
2484 | write_seqlock(&rename_lock); | 2488 | write_seqlock(&rename_lock); |