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: Jeff Layton <jlayton@kernel.org> Reviewed-by: "Yan, Zheng" <zyan@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
parent
76a495d666
commit
4b82228700
|
@ -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) ||
|
||||
|
|
Loading…
Reference in New Issue