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

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
...@@ -1139,45 +1139,59 @@ void ceph_invalidate_dentry_lease(struct dentry *dentry) ...@@ -1139,45 +1139,59 @@ 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 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, static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags,
struct inode *dir) struct inode *dir)
{ {
struct ceph_dentry_info *di; struct ceph_dentry_info *di;
struct ceph_mds_session *s;
int valid = 0;
u32 gen;
unsigned long ttl;
struct ceph_mds_session *session = NULL; struct ceph_mds_session *session = NULL;
u32 seq = 0; u32 seq = 0;
int valid = 0;
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
di = ceph_dentry(dentry); di = ceph_dentry(dentry);
if (di && di->lease_session) { if (di && __dentry_lease_is_valid(di)) {
s = di->lease_session; valid = 1;
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 && if (di->lease_renew_after &&
time_before(jiffies, di->time) && time_after(jiffies, di->lease_renew_after)) {
time_before(jiffies, ttl)) { /*
valid = 1; * We should renew. If we're in RCU walk mode
if (di->lease_renew_after && * though, we can't do that so just return
time_after(jiffies, di->lease_renew_after)) { * -ECHILD.
/* */
* We should renew. If we're in RCU walk mode if (flags & LOOKUP_RCU) {
* though, we can't do that so just return valid = -ECHILD;
* -ECHILD. } else {
*/ session = ceph_get_mds_session(di->lease_session);
if (flags & LOOKUP_RCU) { seq = di->lease_seq;
valid = -ECHILD; di->lease_renew_after = 0;
} else { di->lease_renew_from = jiffies;
session = ceph_get_mds_session(s);
seq = di->lease_seq;
di->lease_renew_after = 0;
di->lease_renew_from = jiffies;
}
} }
} }
} }
...@@ -1192,6 +1206,38 @@ static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags, ...@@ -1192,6 +1206,38 @@ static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags,
return valid; 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. * Check if directory-wide content lease/cap is valid.
*/ */
...@@ -1308,6 +1354,31 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags) ...@@ -1308,6 +1354,31 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
return valid; 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. * Release our ceph_dentry_info.
*/ */
...@@ -1531,6 +1602,7 @@ const struct inode_operations ceph_snapdir_iops = { ...@@ -1531,6 +1602,7 @@ const struct inode_operations ceph_snapdir_iops = {
const struct dentry_operations ceph_dentry_ops = { const struct dentry_operations ceph_dentry_ops = {
.d_revalidate = ceph_d_revalidate, .d_revalidate = ceph_d_revalidate,
.d_delete = ceph_d_delete,
.d_release = ceph_d_release, .d_release = ceph_d_release,
.d_prune = ceph_d_prune, .d_prune = ceph_d_prune,
.d_init = ceph_d_init, .d_init = ceph_d_init,
......
...@@ -497,7 +497,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb) ...@@ -497,7 +497,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
ci->i_wrbuffer_ref = 0; ci->i_wrbuffer_ref = 0;
ci->i_wrbuffer_ref_head = 0; ci->i_wrbuffer_ref_head = 0;
atomic_set(&ci->i_filelock_ref, 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_gen = 0;
ci->i_rdcache_revoking = 0; ci->i_rdcache_revoking = 0;
......
...@@ -621,7 +621,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, ...@@ -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); ceph_con_init(&s->s_con, s, &mds_con_ops, &mdsc->fsc->client->msgr);
spin_lock_init(&s->s_gen_ttl_lock); spin_lock_init(&s->s_gen_ttl_lock);
s->s_cap_gen = 0; s->s_cap_gen = 1;
s->s_cap_ttl = jiffies - 1; s->s_cap_ttl = jiffies - 1;
spin_lock_init(&s->s_cap_lock); spin_lock_init(&s->s_cap_lock);
......
...@@ -594,7 +594,7 @@ extern u32 ceph_choose_frag(struct ceph_inode_info *ci, u32 v, ...@@ -594,7 +594,7 @@ extern u32 ceph_choose_frag(struct ceph_inode_info *ci, u32 v,
struct ceph_inode_frag *pfrag, struct ceph_inode_frag *pfrag,
int *found); 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; return (struct ceph_dentry_info *)dentry->d_fsdata;
} }
......
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