Commit 14fb9c9e authored by Jeff Layton's avatar Jeff Layton Committed by Ilya Dryomov

ceph: allow dentry_lease_is_valid to work under RCU walk

Under rcuwalk, we need to take extra care when dereferencing d_parent.
We want to do that once and pass a pointer to dentry_lease_is_valid.

Also, we must ensure that that function can handle the case where we're
racing with d_release. Check whether "di" is NULL under the d_lock, and
just return 0 if so.

Finally, we still need to kick off a renewal job if the lease is getting
close to expiration. If that's the case, then just drop out of rcuwalk
mode since that could block.
Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Reviewed-by: default avatarYan, Zheng <zyan@redhat.com>
parent 5b484a51
...@@ -1133,7 +1133,8 @@ void ceph_invalidate_dentry_lease(struct dentry *dentry) ...@@ -1133,7 +1133,8 @@ void ceph_invalidate_dentry_lease(struct dentry *dentry)
* Check if dentry lease is valid. If not, delete the lease. Try to * Check if dentry lease is valid. If not, delete the lease. Try to
* renew if the least is more than half up. * renew if the least is more than half up.
*/ */
static int dentry_lease_is_valid(struct dentry *dentry) static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags,
struct inode *dir)
{ {
struct ceph_dentry_info *di; struct ceph_dentry_info *di;
struct ceph_mds_session *s; struct ceph_mds_session *s;
...@@ -1141,12 +1142,11 @@ static int dentry_lease_is_valid(struct dentry *dentry) ...@@ -1141,12 +1142,11 @@ static int dentry_lease_is_valid(struct dentry *dentry)
u32 gen; u32 gen;
unsigned long ttl; unsigned long ttl;
struct ceph_mds_session *session = NULL; struct ceph_mds_session *session = NULL;
struct inode *dir = NULL;
u32 seq = 0; u32 seq = 0;
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
di = ceph_dentry(dentry); di = ceph_dentry(dentry);
if (di->lease_session) { if (di && di->lease_session) {
s = di->lease_session; s = di->lease_session;
spin_lock(&s->s_gen_ttl_lock); spin_lock(&s->s_gen_ttl_lock);
gen = s->s_cap_gen; gen = s->s_cap_gen;
...@@ -1159,8 +1159,14 @@ static int dentry_lease_is_valid(struct dentry *dentry) ...@@ -1159,8 +1159,14 @@ static int dentry_lease_is_valid(struct dentry *dentry)
valid = 1; valid = 1;
if (di->lease_renew_after && if (di->lease_renew_after &&
time_after(jiffies, di->lease_renew_after)) { time_after(jiffies, di->lease_renew_after)) {
/* we should renew */ /*
dir = d_inode(dentry->d_parent); * We should renew. If we're in RCU walk mode
* though, we can't do that so just return
* -ECHILD.
*/
if (flags & LOOKUP_RCU) {
valid = -ECHILD;
} else {
session = ceph_get_mds_session(s); session = ceph_get_mds_session(s);
seq = di->lease_seq; seq = di->lease_seq;
di->lease_renew_after = 0; di->lease_renew_after = 0;
...@@ -1168,6 +1174,7 @@ static int dentry_lease_is_valid(struct dentry *dentry) ...@@ -1168,6 +1174,7 @@ static int dentry_lease_is_valid(struct dentry *dentry)
} }
} }
} }
}
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
if (session) { if (session) {
...@@ -1224,13 +1231,17 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags) ...@@ -1224,13 +1231,17 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
} else if (d_really_is_positive(dentry) && } else if (d_really_is_positive(dentry) &&
ceph_snap(d_inode(dentry)) == CEPH_SNAPDIR) { ceph_snap(d_inode(dentry)) == CEPH_SNAPDIR) {
valid = 1; valid = 1;
} else if (dentry_lease_is_valid(dentry) || } else {
dir_lease_is_valid(dir, dentry)) { valid = dentry_lease_is_valid(dentry, flags, dir);
if (valid == -ECHILD)
return valid;
if (valid || dir_lease_is_valid(dir, dentry)) {
if (d_really_is_positive(dentry)) if (d_really_is_positive(dentry))
valid = ceph_is_any_caps(d_inode(dentry)); valid = ceph_is_any_caps(d_inode(dentry));
else else
valid = 1; valid = 1;
} }
}
if (!valid) { if (!valid) {
struct ceph_mds_client *mdsc = struct ceph_mds_client *mdsc =
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment