Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b5ae6b15 authored by Al Viro's avatar Al Viro
Browse files

merge d_materialise_unique() into d_splice_alias()



Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 154e80e4
Loading
Loading
Loading
Loading
+35 −108
Original line number Diff line number Diff line
@@ -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
 * 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 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->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;
out_unalias:
	__d_move(alias, dentry, false);
	ret = alias;
	ret = 0;
out_err:
	spin_unlock(&inode->i_lock);
	if (m2)
@@ -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 *new = NULL;

	if (IS_ERR(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));

	if (!inode) {
		actual = dentry;
		__d_instantiate(dentry, NULL);
		d_rehash(actual);
		goto out_nolock;
		goto out;
	}

	spin_lock(&inode->i_lock);

	if (S_ISDIR(inode->i_mode)) {
		struct dentry *alias;

		/* Does an aliased dentry already exist? */
		alias = __d_find_alias(inode);
		if (alias) {
			actual = alias;
		struct dentry *new = __d_find_any_alias(inode);
		if (unlikely(new)) {
			write_seqlock(&rename_lock);

			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);
			if (unlikely(d_ancestor(new, dentry))) {
				write_sequnlock(&rename_lock);
				goto found;
			} else {
				/* Nope, but we must(!) avoid directory
				 * aliasing. This drops inode->i_lock */
				actual = __d_unalias(inode, dentry, alias);
			}
			write_sequnlock(&rename_lock);
			if (IS_ERR(actual)) {
				if (PTR_ERR(actual) == -ELOOP)
				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);
				dput(alias);
			} else if (!IS_ROOT(new)) {
				int err = __d_unalias(inode, dentry, new);
				write_sequnlock(&rename_lock);
				if (err) {
					dput(new);
					new = ERR_PTR(err);
				}
			goto out_nolock;
			} else {
				__d_move(new, dentry, false);
				write_sequnlock(&rename_lock);
				spin_unlock(&inode->i_lock);
				security_d_instantiate(new, inode);
			}
			iput(inode);
			return new;
		}

	/* Add a unique reference */
	actual = __d_instantiate_unique(dentry, inode);
	if (!actual)
		actual = dentry;

	d_rehash(actual);
found:
	}
	/* already taking inode->i_lock, so d_add() by hand */
	__d_instantiate(dentry, inode);
	spin_unlock(&inode->i_lock);
out_nolock:
	if (actual == dentry) {
out:
	security_d_instantiate(dentry, inode);
	d_rehash(dentry);
	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)
{
+1 −1
Original line number Diff line number Diff line
@@ -230,7 +230,7 @@ extern seqlock_t rename_lock;
 */
extern void d_instantiate(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 void __d_drop(struct dentry *dentry);
extern void d_drop(struct dentry *dentry);