|
@@ -683,6 +683,8 @@ EXPORT_SYMBOL(dget_parent);
|
|
|
/**
|
|
|
* d_find_alias - grab a hashed alias of inode
|
|
|
* @inode: inode in question
|
|
|
+ * @want_discon: flag, used by d_splice_alias, to request
|
|
|
+ * that only a DISCONNECTED alias be returned.
|
|
|
*
|
|
|
* If inode has a hashed alias, or is a directory and has any alias,
|
|
|
* acquire the reference to alias and return it. Otherwise return NULL.
|
|
@@ -691,9 +693,10 @@ EXPORT_SYMBOL(dget_parent);
|
|
|
* of a filesystem.
|
|
|
*
|
|
|
* If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer
|
|
|
- * any other hashed alias over that.
|
|
|
+ * any other hashed alias over that one unless @want_discon is set,
|
|
|
+ * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias.
|
|
|
*/
|
|
|
-static struct dentry *__d_find_alias(struct inode *inode)
|
|
|
+static struct dentry *__d_find_alias(struct inode *inode, int want_discon)
|
|
|
{
|
|
|
struct dentry *alias, *discon_alias;
|
|
|
|
|
@@ -705,7 +708,7 @@ again:
|
|
|
if (IS_ROOT(alias) &&
|
|
|
(alias->d_flags & DCACHE_DISCONNECTED)) {
|
|
|
discon_alias = alias;
|
|
|
- } else {
|
|
|
+ } else if (!want_discon) {
|
|
|
__dget_dlock(alias);
|
|
|
spin_unlock(&alias->d_lock);
|
|
|
return alias;
|
|
@@ -736,7 +739,7 @@ struct dentry *d_find_alias(struct inode *inode)
|
|
|
|
|
|
if (!list_empty(&inode->i_dentry)) {
|
|
|
spin_lock(&inode->i_lock);
|
|
|
- de = __d_find_alias(inode);
|
|
|
+ de = __d_find_alias(inode, 0);
|
|
|
spin_unlock(&inode->i_lock);
|
|
|
}
|
|
|
return de;
|
|
@@ -1647,8 +1650,9 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
|
|
|
|
|
|
if (inode && S_ISDIR(inode->i_mode)) {
|
|
|
spin_lock(&inode->i_lock);
|
|
|
- new = __d_find_any_alias(inode);
|
|
|
+ new = __d_find_alias(inode, 1);
|
|
|
if (new) {
|
|
|
+ BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));
|
|
|
spin_unlock(&inode->i_lock);
|
|
|
security_d_instantiate(new, inode);
|
|
|
d_move(new, dentry);
|
|
@@ -2478,7 +2482,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
|
|
|
struct dentry *alias;
|
|
|
|
|
|
/* Does an aliased dentry already exist? */
|
|
|
- alias = __d_find_alias(inode);
|
|
|
+ alias = __d_find_alias(inode, 0);
|
|
|
if (alias) {
|
|
|
actual = alias;
|
|
|
write_seqlock(&rename_lock);
|