Commit 4b822287 authored by Jeff Layton's avatar Jeff Layton Committed by Ilya Dryomov
Browse files

ceph: handle the case where a dentry has been renamed on outstanding req



It's possible for us to issue a lookup to revalidate a dentry
concurrently with a rename. If done in the right order, then we could
end up processing dentry info in the reply that no longer reflects the
state of the dentry.

If req->r_dentry->d_name differs from the one in the trace, then just
ignore the trace in the reply. We only need to do this however if the
parent's i_rwsem is not held.

Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
Reviewed-by: default avatar"Yan, Zheng" <zyan@redhat.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent 76a495d6
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -1163,6 +1163,19 @@ static int splice_dentry(struct dentry **pdn, struct inode *in)
	return 0;
}

static int d_name_cmp(struct dentry *dentry, const char *name, size_t len)
{
	int ret;

	/* take d_lock to ensure dentry->d_name stability */
	spin_lock(&dentry->d_lock);
	ret = dentry->d_name.len - len;
	if (!ret)
		ret = memcmp(dentry->d_name.name, name, len);
	spin_unlock(&dentry->d_lock);
	return ret;
}

/*
 * Incorporate results into the local cache.  This is either just
 * one inode, or a directory, dentry, and possibly linked-to inode (e.g.,
@@ -1412,7 +1425,8 @@ retry_lookup:
		err = splice_dentry(&req->r_dentry, in);
		if (err < 0)
			goto done;
	} else if (rinfo->head->is_dentry) {
	} else if (rinfo->head->is_dentry &&
		   !d_name_cmp(req->r_dentry, rinfo->dname, rinfo->dname_len)) {
		struct ceph_vino *ptvino = NULL;

		if ((le32_to_cpu(rinfo->diri.in->cap.caps) & CEPH_CAP_FILE_SHARED) ||