Message ID | 20190201142253.5478-4-zyan@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | ceph: proactively release used caps | expand |
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@redhat.com> > --- > 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; > }
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 (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; }
introduce ceph_d_delete(), which checks if dentry has valid lease. Signed-off-by: "Yan, Zheng" <zyan@redhat.com> --- 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(-)