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); |
