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

split do_revalidate() into RCU and non-RCU cases



fixing oopsen in lookup_one_len()

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 24643087
Loading
Loading
Loading
Loading
+30 −17
Original line number Diff line number Diff line
@@ -592,12 +592,10 @@ static int d_revalidate(struct dentry *dentry, struct nameidata *nd)
	return status;
}

static inline struct dentry *
static struct dentry *
do_revalidate(struct dentry *dentry, struct nameidata *nd)
{
	int status;

	status = d_revalidate(dentry, nd);
	int status = d_revalidate(dentry, nd);
	if (unlikely(status <= 0)) {
		/*
		 * The dentry failed validation.
@@ -606,21 +604,36 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd)
		 * to return a fail status.
		 */
		if (status < 0) {
			/* If we're in rcu-walk, we don't have a ref */
			if (!(nd->flags & LOOKUP_RCU))
			dput(dentry);
			dentry = ERR_PTR(status);
		} else if (!d_invalidate(dentry)) {
			dput(dentry);
			dentry = NULL;
		}
	}
	return dentry;
}

		} else {
static inline struct dentry *
do_revalidate_rcu(struct dentry *dentry, struct nameidata *nd)
{
	int status = dentry->d_op->d_revalidate(dentry, nd);
	if (likely(status > 0))
		return dentry;
	if (status == -ECHILD) {
		if (nameidata_dentry_drop_rcu(nd, dentry))
			return ERR_PTR(-ECHILD);
		return do_revalidate(dentry, nd);
	}
	if (status < 0)
		return ERR_PTR(status);
	/* Don't d_invalidate in rcu-walk mode */
			if (nameidata_dentry_drop_rcu_maybe(nd, dentry))
	if (nameidata_dentry_drop_rcu(nd, dentry))
		return ERR_PTR(-ECHILD);
	if (!d_invalidate(dentry)) {
		dput(dentry);
		dentry = NULL;
	}
		}
	}
	return dentry;
}

@@ -1260,7 +1273,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,

		nd->seq = seq;
		if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
			dentry = do_revalidate(dentry, nd);
			dentry = do_revalidate_rcu(dentry, nd);
			if (!dentry)
				goto need_lookup;
			if (IS_ERR(dentry))