Commit b5ae6b15 authored by Al Viro's avatar Al Viro

merge d_materialise_unique() into d_splice_alias()

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 154e80e4
...@@ -2575,11 +2575,11 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2) ...@@ -2575,11 +2575,11 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2)
* Note: If ever the locking in lock_rename() changes, then please * Note: If ever the locking in lock_rename() changes, then please
* remember to update this too... * remember to update this too...
*/ */
static struct dentry *__d_unalias(struct inode *inode, static int __d_unalias(struct inode *inode,
struct dentry *dentry, struct dentry *alias) struct dentry *dentry, struct dentry *alias)
{ {
struct mutex *m1 = NULL, *m2 = NULL; struct mutex *m1 = NULL, *m2 = NULL;
struct dentry *ret = ERR_PTR(-EBUSY); int ret = -EBUSY;
/* If alias and dentry share a parent, then no extra locks required */ /* If alias and dentry share a parent, then no extra locks required */
if (alias->d_parent == dentry->d_parent) if (alias->d_parent == dentry->d_parent)
...@@ -2594,7 +2594,7 @@ static struct dentry *__d_unalias(struct inode *inode, ...@@ -2594,7 +2594,7 @@ static struct dentry *__d_unalias(struct inode *inode,
m2 = &alias->d_parent->d_inode->i_mutex; m2 = &alias->d_parent->d_inode->i_mutex;
out_unalias: out_unalias:
__d_move(alias, dentry, false); __d_move(alias, dentry, false);
ret = alias; ret = 0;
out_err: out_err:
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
if (m2) if (m2)
...@@ -2629,130 +2629,57 @@ static struct dentry *__d_unalias(struct inode *inode, ...@@ -2629,130 +2629,57 @@ static struct dentry *__d_unalias(struct inode *inode,
*/ */
struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
{ {
struct dentry *new = NULL;
if (IS_ERR(inode)) if (IS_ERR(inode))
return ERR_CAST(inode); return ERR_CAST(inode);
if (inode && S_ISDIR(inode->i_mode)) {
spin_lock(&inode->i_lock);
new = __d_find_any_alias(inode);
if (new) {
if (!IS_ROOT(new)) {
spin_unlock(&inode->i_lock);
dput(new);
iput(inode);
return ERR_PTR(-EIO);
}
if (d_ancestor(new, dentry)) {
spin_unlock(&inode->i_lock);
dput(new);
iput(inode);
return ERR_PTR(-EIO);
}
write_seqlock(&rename_lock);
__d_move(new, dentry, false);
write_sequnlock(&rename_lock);
spin_unlock(&inode->i_lock);
security_d_instantiate(new, inode);
iput(inode);
} else {
/* already taking inode->i_lock, so d_add() by hand */
__d_instantiate(dentry, inode);
spin_unlock(&inode->i_lock);
security_d_instantiate(dentry, inode);
d_rehash(dentry);
}
} else {
d_instantiate(dentry, inode);
if (d_unhashed(dentry))
d_rehash(dentry);
}
return new;
}
EXPORT_SYMBOL(d_splice_alias);
/**
* d_materialise_unique - introduce an inode into the tree
* @dentry: candidate dentry
* @inode: inode to bind to the dentry, to which aliases may be attached
*
* Introduces an dentry into the tree, substituting an extant disconnected
* root directory alias in its place if there is one. Caller must hold the
* i_mutex of the parent directory.
*/
struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
{
struct dentry *actual;
BUG_ON(!d_unhashed(dentry)); BUG_ON(!d_unhashed(dentry));
if (!inode) { if (!inode) {
actual = dentry;
__d_instantiate(dentry, NULL); __d_instantiate(dentry, NULL);
d_rehash(actual); goto out;
goto out_nolock;
} }
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (S_ISDIR(inode->i_mode)) { if (S_ISDIR(inode->i_mode)) {
struct dentry *alias; struct dentry *new = __d_find_any_alias(inode);
if (unlikely(new)) {
/* Does an aliased dentry already exist? */
alias = __d_find_alias(inode);
if (alias) {
actual = alias;
write_seqlock(&rename_lock); write_seqlock(&rename_lock);
if (unlikely(d_ancestor(new, dentry))) {
if (d_ancestor(alias, dentry)) { write_sequnlock(&rename_lock);
/* Check for loops */
actual = ERR_PTR(-ELOOP);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} else if (IS_ROOT(alias)) { dput(new);
/* Is this an anonymous mountpoint that we new = ERR_PTR(-ELOOP);
* could splice into our tree? */ pr_warn_ratelimited(
__d_move(alias, dentry, false); "VFS: Lookup of '%s' in %s %s"
" would have caused loop\n",
dentry->d_name.name,
inode->i_sb->s_type->name,
inode->i_sb->s_id);
} else if (!IS_ROOT(new)) {
int err = __d_unalias(inode, dentry, new);
write_sequnlock(&rename_lock); write_sequnlock(&rename_lock);
goto found; if (err) {
dput(new);
new = ERR_PTR(err);
}
} else { } else {
/* Nope, but we must(!) avoid directory __d_move(new, dentry, false);
* aliasing. This drops inode->i_lock */ write_sequnlock(&rename_lock);
actual = __d_unalias(inode, dentry, alias); spin_unlock(&inode->i_lock);
} security_d_instantiate(new, inode);
write_sequnlock(&rename_lock);
if (IS_ERR(actual)) {
if (PTR_ERR(actual) == -ELOOP)
pr_warn_ratelimited(
"VFS: Lookup of '%s' in %s %s"
" would have caused loop\n",
dentry->d_name.name,
inode->i_sb->s_type->name,
inode->i_sb->s_id);
dput(alias);
} }
goto out_nolock; iput(inode);
return new;
} }
} }
/* already taking inode->i_lock, so d_add() by hand */
/* Add a unique reference */ __d_instantiate(dentry, inode);
actual = __d_instantiate_unique(dentry, inode);
if (!actual)
actual = dentry;
d_rehash(actual);
found:
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
out_nolock: out:
if (actual == dentry) { security_d_instantiate(dentry, inode);
security_d_instantiate(dentry, inode); d_rehash(dentry);
return NULL; return NULL;
}
iput(inode);
return actual;
} }
EXPORT_SYMBOL_GPL(d_materialise_unique); EXPORT_SYMBOL(d_splice_alias);
static int prepend(char **buffer, int *buflen, const char *str, int namelen) static int prepend(char **buffer, int *buflen, const char *str, int namelen)
{ {
......
...@@ -230,7 +230,7 @@ extern seqlock_t rename_lock; ...@@ -230,7 +230,7 @@ extern seqlock_t rename_lock;
*/ */
extern void d_instantiate(struct dentry *, struct inode *); extern void d_instantiate(struct dentry *, struct inode *);
extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *); extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *);
extern struct dentry * d_materialise_unique(struct dentry *, struct inode *); #define d_materialise_unique(d, i) d_splice_alias(i, d)
extern int d_instantiate_no_diralias(struct dentry *, struct inode *); extern int d_instantiate_no_diralias(struct dentry *, struct inode *);
extern void __d_drop(struct dentry *dentry); extern void __d_drop(struct dentry *dentry);
extern void d_drop(struct dentry *dentry); extern void d_drop(struct dentry *dentry);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment