On Fri, 2019-02-01 at 22:22 +0800, Yan, Zheng wrote: > introduce ceph_d_delete(), which checks if dentry has valid lease. > > Signed-off-by: "Yan, Zheng" <zyan@xxxxxxxxxx> > --- > fs/ceph/dir.c | 132 +++++++++++++++++++++++++++++++++---------- > fs/ceph/inode.c | 2 +- > fs/ceph/mds_client.c | 2 +- > fs/ceph/super.h | 2 +- > 4 files changed, 106 insertions(+), 32 deletions(-) > > diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c > index 82928cea0209..bb5d765fcaae 100644 > --- a/fs/ceph/dir.c > +++ b/fs/ceph/dir.c > @@ -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 > * 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 && __dentry_lease_is_valid(di)) { > + valid = 1; > > - if (di->lease_gen == gen && > - time_before(jiffies, di->time) && > - time_before(jiffies, ttl)) { > - valid = 1; > - if (di->lease_renew_after && > - time_after(jiffies, di->lease_renew_after)) { > - /* > - * 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; > - di->lease_renew_from = jiffies; > - } > + if (di->lease_renew_after && > + time_after(jiffies, di->lease_renew_after)) { > + /* > + * 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(di->lease_session); > + seq = di->lease_seq; > + di->lease_renew_after = 0; > + di->lease_renew_from = jiffies; > } > } > } > @@ -1192,6 +1206,40 @@ 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; > + > + rcu_read_lock(); > + dir = d_inode_rcu(dentry->d_parent); > + ci = ceph_inode(dir); If you hold dentry->d_lock (and you do here), then d_parent is stable and you shouldn't need to use RCU. > + > + 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; > + } > + rcu_read_unlock(); > + > + if (!valid) > + di->lease_shared_gen = 0; > + return valid; > +} > + > /* > * Check if directory-wide content lease/cap is valid. > */ > @@ -1308,6 +1356,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 +1604,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, > diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c > index f588b2d7b598..f75476e94d75 100644 > --- a/fs/ceph/inode.c > +++ b/fs/ceph/inode.c > @@ -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; > > diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c > index 8f2d97e806b2..e5aea1db8d84 100644 > --- a/fs/ceph/mds_client.c > +++ b/fs/ceph/mds_client.c > @@ -619,7 +619,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); > diff --git a/fs/ceph/super.h b/fs/ceph/super.h > index c4a79eadc55a..c0654e613fc0 100644 > --- a/fs/ceph/super.h > +++ b/fs/ceph/super.h > @@ -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; > } -- Jeff Layton <jlayton@xxxxxxxxxx>