ceph: delete stale dentry when last reference is dropped
introduce ceph_d_delete(), which checks if dentry has valid lease. Signed-off-by: "Yan, Zheng" <zyan@redhat.com> Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
Родитель
8d9c0906ac
Коммит
1e9c2eb681
104
fs/ceph/dir.c
104
fs/ceph/dir.c
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче