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

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

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
Loading
Loading
Loading
Loading
+26 −15
Original line number Diff line number Diff line
@@ -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
 * 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_mds_session *s;
@@ -1141,12 +1142,11 @@ static int dentry_lease_is_valid(struct dentry *dentry)
	u32 gen;
	unsigned long ttl;
	struct ceph_mds_session *session = NULL;
	struct inode *dir = NULL;
	u32 seq = 0;

	spin_lock(&dentry->d_lock);
	di = ceph_dentry(dentry);
	if (di->lease_session) {
	if (di && di->lease_session) {
		s = di->lease_session;
		spin_lock(&s->s_gen_ttl_lock);
		gen = s->s_cap_gen;
@@ -1159,8 +1159,14 @@ static int dentry_lease_is_valid(struct dentry *dentry)
			valid = 1;
			if (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);
					seq = di->lease_seq;
					di->lease_renew_after = 0;
@@ -1168,6 +1174,7 @@ static int dentry_lease_is_valid(struct dentry *dentry)
				}
			}
		}
	}
	spin_unlock(&dentry->d_lock);

	if (session) {
@@ -1224,13 +1231,17 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
	} else if (d_really_is_positive(dentry) &&
		   ceph_snap(d_inode(dentry)) == CEPH_SNAPDIR) {
		valid = 1;
	} else if (dentry_lease_is_valid(dentry) ||
		   dir_lease_is_valid(dir, dentry)) {
	} else {
		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))
				valid = ceph_is_any_caps(d_inode(dentry));
			else
				valid = 1;
		}
	}

	if (!valid) {
		struct ceph_mds_client *mdsc =