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

Commit 5d0f49c1 authored by Al Viro's avatar Al Viro
Browse files

namei: untanlge lookup_fast()



Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 6c51e513
Loading
Loading
Loading
Loading
+37 −46
Original line number Diff line number Diff line
@@ -1512,32 +1512,29 @@ static struct dentry *__lookup_hash(struct qstr *name,
	return lookup_real(base->d_inode, dentry, flags);
}

/*
 *  It's more convoluted than I'd like it to be, but... it's still fairly
 *  small and for now I'd prefer to have fast path as straight as possible.
 *  It _is_ time-critical.
 */
static int lookup_fast(struct nameidata *nd,
		       struct path *path, struct inode **inode,
		       unsigned *seqp)
{
	struct vfsmount *mnt = nd->path.mnt;
	struct dentry *dentry, *parent = nd->path.dentry;
	int need_reval = 1;
	int status = 1;
	int err;

	/*
	 * Rename seqlock is not required here because in the off chance
	 * of a false negative due to a concurrent rename, we're going to
	 * do the non-racy lookup, below.
	 * of a false negative due to a concurrent rename, the caller is
	 * going to fall back to non-racy lookup.
	 */
	if (nd->flags & LOOKUP_RCU) {
		unsigned seq;
		bool negative;
		dentry = __d_lookup_rcu(parent, &nd->last, &seq);
		if (!dentry)
			goto unlazy;
		if (unlikely(!dentry)) {
			if (unlazy_walk(nd, NULL, 0))
				return -ECHILD;
			return 1;
		}

		/*
		 * This sequence count validates that the inode matches
@@ -1545,7 +1542,7 @@ static int lookup_fast(struct nameidata *nd,
		 */
		*inode = d_backing_inode(dentry);
		negative = d_is_negative(dentry);
		if (read_seqcount_retry(&dentry->d_seq, seq))
		if (unlikely(read_seqcount_retry(&dentry->d_seq, seq)))
			return -ECHILD;

		/*
@@ -1555,63 +1552,57 @@ static int lookup_fast(struct nameidata *nd,
		 * The memory barrier in read_seqcount_begin of child is
		 *  enough, we can use __read_seqcount_retry here.
		 */
		if (__read_seqcount_retry(&parent->d_seq, nd->seq))
		if (unlikely(__read_seqcount_retry(&parent->d_seq, nd->seq)))
			return -ECHILD;

		*seqp = seq;
		if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
		if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE))
			status = d_revalidate(dentry, nd->flags);
		if (unlikely(status <= 0)) {
				if (status != -ECHILD)
					need_reval = 0;
				goto unlazy;
			}
		}
			if (unlazy_walk(nd, dentry, seq))
				return -ECHILD;
			if (status == -ECHILD)
				status = d_revalidate(dentry, nd->flags);
		} else {
			/*
			 * Note: do negative dentry check after revalidation in
			 * case that drops it.
			 */
		if (negative)
			if (unlikely(negative))
				return -ENOENT;
			path->mnt = mnt;
			path->dentry = dentry;
			if (likely(__follow_mount_rcu(nd, path, inode, seqp)))
				return 0;
unlazy:
			if (unlazy_walk(nd, dentry, seq))
				return -ECHILD;
		}
	} else {
		dentry = __d_lookup(parent, &nd->last);
	}

		if (unlikely(!dentry))
		goto need_lookup;

	if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE) && need_reval)
			return 1;
		if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE))
			status = d_revalidate(dentry, nd->flags);
	if (unlikely(status <= 0)) {
		if (status < 0) {
			dput(dentry);
			return status;
	}
	if (unlikely(status <= 0)) {
		if (!status) {
			d_invalidate(dentry);
			status = 1;
		}
		dput(dentry);
		goto need_lookup;
		return status;
	}

	if (unlikely(d_is_negative(dentry))) {
		dput(dentry);
		return -ENOENT;
	}

	path->mnt = mnt;
	path->dentry = dentry;
	err = follow_managed(path, nd);
	if (likely(!err))
		*inode = d_backing_inode(path->dentry);
	return err;

need_lookup:
	return 1;
}

/* Fast lookup failed, do it the slow way */