mirror of
https://github.com/torvalds/linux.git
synced 2025-08-16 06:31:34 +02:00
merge d_materialise_unique() into d_splice_alias()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
154e80e4c3
commit
b5ae6b15bd
2 changed files with 37 additions and 110 deletions
145
fs/dcache.c
145
fs/dcache.c
|
@ -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,
|
||||||
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 @@ out_err:
|
||||||
*/
|
*/
|
||||||
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)) {
|
|
||||||
/* Check for loops */
|
|
||||||
actual = ERR_PTR(-ELOOP);
|
|
||||||
spin_unlock(&inode->i_lock);
|
|
||||||
} else if (IS_ROOT(alias)) {
|
|
||||||
/* Is this an anonymous mountpoint that we
|
|
||||||
* could splice into our tree? */
|
|
||||||
__d_move(alias, dentry, false);
|
|
||||||
write_sequnlock(&rename_lock);
|
write_sequnlock(&rename_lock);
|
||||||
goto found;
|
spin_unlock(&inode->i_lock);
|
||||||
|
dput(new);
|
||||||
|
new = ERR_PTR(-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);
|
||||||
|
} else if (!IS_ROOT(new)) {
|
||||||
|
int err = __d_unalias(inode, dentry, new);
|
||||||
|
write_sequnlock(&rename_lock);
|
||||||
|
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);
|
iput(inode);
|
||||||
if (IS_ERR(actual)) {
|
return new;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* 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;
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue