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

Commit 1e9c2eb6 authored by Yan, Zheng's avatar Yan, Zheng Committed by Ilya Dryomov
Browse files

ceph: delete stale dentry when last reference is dropped



introduce ceph_d_delete(), which checks if dentry has valid lease.

Signed-off-by: default avatar"Yan, Zheng" <zyan@redhat.com>
Reviewed-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent 8d9c0906
Loading
Loading
Loading
Loading
+101 −29
Original line number Diff line number Diff line
@@ -1139,30 +1139,45 @@ 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 bool __dentry_lease_is_valid(struct ceph_dentry_info *di)
{
	struct ceph_mds_session *session;

	if (!di->lease_gen)
		return false;

	session = di->lease_session;
	if (session) {
		u32 gen;
		unsigned long ttl;

		spin_lock(&session->s_gen_ttl_lock);
		gen = session->s_cap_gen;
		ttl = session->s_cap_ttl;
		spin_unlock(&session->s_gen_ttl_lock);

		if (di->lease_gen == gen &&
		    time_before(jiffies, ttl) &&
		    time_before(jiffies, di->time))
			return true;
	}
	di->lease_gen = 0;
	return false;
}

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;
	int valid = 0;
	u32 gen;
	unsigned long ttl;
	struct ceph_mds_session *session = NULL;
	u32 seq = 0;
	int valid = 0;

	spin_lock(&dentry->d_lock);
	di = ceph_dentry(dentry);
	if (di && di->lease_session) {
		s = di->lease_session;
		spin_lock(&s->s_gen_ttl_lock);
		gen = s->s_cap_gen;
		ttl = s->s_cap_ttl;
		spin_unlock(&s->s_gen_ttl_lock);

		if (di->lease_gen == gen &&
		    time_before(jiffies, di->time) &&
		    time_before(jiffies, ttl)) {
	if (di && __dentry_lease_is_valid(di)) {
		valid = 1;

		if (di->lease_renew_after &&
		    time_after(jiffies, di->lease_renew_after)) {
			/*
@@ -1173,14 +1188,13 @@ static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags,
			if (flags & LOOKUP_RCU) {
				valid = -ECHILD;
			} else {
					session = ceph_get_mds_session(s);
				session = ceph_get_mds_session(di->lease_session);
				seq = di->lease_seq;
				di->lease_renew_after = 0;
				di->lease_renew_from = jiffies;
			}
		}
	}
	}
	spin_unlock(&dentry->d_lock);

	if (session) {
@@ -1192,6 +1206,38 @@ static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags,
	return valid;
}

/*
 * Called under dentry->d_lock.
 */
static int __dir_lease_try_check(const struct dentry *dentry)
{
	struct ceph_dentry_info *di = ceph_dentry(dentry);
	struct inode *dir;
	struct ceph_inode_info *ci;
	int valid = 0;

	if (!di->lease_shared_gen)
		return 0;
	if (IS_ROOT(dentry))
		return 0;

	dir = d_inode(dentry->d_parent);
	ci = ceph_inode(dir);

	if (spin_trylock(&ci->i_ceph_lock)) {
		if (atomic_read(&ci->i_shared_gen) == di->lease_shared_gen &&
		    __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 0))
			valid = 1;
		spin_unlock(&ci->i_ceph_lock);
	} else {
		valid = -EBUSY;
	}

	if (!valid)
		di->lease_shared_gen = 0;
	return valid;
}

/*
 * Check if directory-wide content lease/cap is valid.
 */
@@ -1308,6 +1354,31 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
	return valid;
}

/*
 * Delete unused dentry that doesn't have valid lease
 *
 * Called under dentry->d_lock.
 */
static int ceph_d_delete(const struct dentry *dentry)
{
	struct ceph_dentry_info *di;

	/* won't release caps */
	if (d_really_is_negative(dentry))
		return 0;
	if (ceph_snap(d_inode(dentry)) != CEPH_NOSNAP)
		return 0;
	/* vaild lease? */
	di = ceph_dentry(dentry);
	if (di) {
		if (__dentry_lease_is_valid(di))
			return 0;
		if (__dir_lease_try_check(dentry))
			return 0;
	}
	return 1;
}

/*
 * Release our ceph_dentry_info.
 */
@@ -1531,6 +1602,7 @@ const struct inode_operations ceph_snapdir_iops = {

const struct dentry_operations ceph_dentry_ops = {
	.d_revalidate = ceph_d_revalidate,
	.d_delete = ceph_d_delete,
	.d_release = ceph_d_release,
	.d_prune = ceph_d_prune,
	.d_init = ceph_d_init,
+1 −1
Original line number Diff line number Diff line
@@ -497,7 +497,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
	ci->i_wrbuffer_ref = 0;
	ci->i_wrbuffer_ref_head = 0;
	atomic_set(&ci->i_filelock_ref, 0);
	atomic_set(&ci->i_shared_gen, 0);
	atomic_set(&ci->i_shared_gen, 1);
	ci->i_rdcache_gen = 0;
	ci->i_rdcache_revoking = 0;

+1 −1
Original line number Diff line number Diff line
@@ -621,7 +621,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
	ceph_con_init(&s->s_con, s, &mds_con_ops, &mdsc->fsc->client->msgr);

	spin_lock_init(&s->s_gen_ttl_lock);
	s->s_cap_gen = 0;
	s->s_cap_gen = 1;
	s->s_cap_ttl = jiffies - 1;

	spin_lock_init(&s->s_cap_lock);
+1 −1
Original line number Diff line number Diff line
@@ -594,7 +594,7 @@ extern u32 ceph_choose_frag(struct ceph_inode_info *ci, u32 v,
			    struct ceph_inode_frag *pfrag,
			    int *found);

static inline struct ceph_dentry_info *ceph_dentry(struct dentry *dentry)
static inline struct ceph_dentry_info *ceph_dentry(const struct dentry *dentry)
{
	return (struct ceph_dentry_info *)dentry->d_fsdata;
}