On Fri, 13 Jan 2012, Alex Elder wrote:

> Lockdep was reporting a possible circular lock dependency in
> dentry_lease_is_valid().  That function needs to sample the
> session's s_cap_gen and and s_cap_ttl fields coherently, but needs
> to do so while holding a dentry lock.  The s_cap_lock field was
> being used to protect the two fields, but that can't be taken while
> holding a lock on a dentry within the session.
> 
> In most cases, the s_cap_gen and s_cap_ttl fields only get operated
> on separately.  But in three cases they need to be updated together.
> Implement a new lock to protect the spots updating both fields
> atomically is required.
> 
> Signed-off-by: Alex Elder <[email protected]>
> ---
>  fs/ceph/caps.c       |    4 ++--
>  fs/ceph/dir.c        |   14 +++-----------
>  fs/ceph/mds_client.c |    8 +++++---
>  fs/ceph/mds_client.h |    7 +++++--
>  4 files changed, 15 insertions(+), 18 deletions(-)
> 
> diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
> index 8b53193..90d789d 100644
> --- a/fs/ceph/caps.c
> +++ b/fs/ceph/caps.c
> @@ -641,10 +641,10 @@ static int __cap_is_valid(struct ceph_cap *cap)
>       unsigned long ttl;
>       u32 gen;
>  
> -     spin_lock(&cap->session->s_cap_lock);
> +     spin_lock(&cap->session->s_gen_ttl_lock);
>       gen = cap->session->s_cap_gen;
>       ttl = cap->session->s_cap_ttl;
> -     spin_unlock(&cap->session->s_cap_lock);
> +     spin_unlock(&cap->session->s_gen_ttl_lock);
>  
>       if (cap->cap_gen < gen || time_after_eq(jiffies, ttl)) {
>               dout("__cap_is_valid %p cap %p issued %s "
> diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
> index ab2b035..a1a0693 100644
> --- a/fs/ceph/dir.c
> +++ b/fs/ceph/dir.c
> @@ -971,24 +971,16 @@ static int dentry_lease_is_valid(struct dentry
> *dentry)
>       struct inode *dir = NULL;
>       u32 seq = 0;
>  
> -retry:
>       spin_lock(&dentry->d_lock);
>       di = ceph_dentry(dentry);
>       if (di->lease_session) {
>               s = di->lease_session;
>               ceph_get_mds_session(s);
> -             spin_unlock(&dentry->d_lock);
> -             spin_lock(&s->s_cap_lock);
> -             spin_lock(&dentry->d_lock);
> -             if (di->lease_session != s) {
> -                     spin_unlock(&s->s_cap_lock);
> -                     spin_unlock(&dentry->d_lock);
> -                     ceph_put_mds_session(s);
> -                     goto retry;
> -             }

We should drop/squash my patch that added this ugliness in the first 
place.

Otherwise, looks good!

> +
> +             spin_lock(&s->s_gen_ttl_lock);
>               gen = s->s_cap_gen;
>               ttl = s->s_cap_ttl;
> -             spin_unlock(&s->s_cap_lock);
> +             spin_unlock(&s->s_gen_ttl_lock);
>  
>               if (di->lease_gen == gen &&
>                   time_before(jiffies, dentry->d_time) &&
> diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
> index 23ab6a3..2b0e274 100644
> --- a/fs/ceph/mds_client.c
> +++ b/fs/ceph/mds_client.c
> @@ -398,9 +398,11 @@ static struct ceph_mds_session
> *register_session(struct ceph_mds_client *mdsc,
>       s->s_con.peer_name.type = CEPH_ENTITY_TYPE_MDS;
>       s->s_con.peer_name.num = cpu_to_le64(mds);
>  
> -     spin_lock_init(&s->s_cap_lock);
> +     spin_lock_init(&s->s_gen_ttl_lock);
>       s->s_cap_gen = 0;
>       s->s_cap_ttl = 0;
> +
> +     spin_lock_init(&s->s_cap_lock);
>       s->s_renew_requested = 0;
>       s->s_renew_seq = 0;
>       INIT_LIST_HEAD(&s->s_caps);
> @@ -2326,10 +2328,10 @@ static void handle_session(struct
> ceph_mds_session *session,
>       case CEPH_SESSION_STALE:
>               pr_info("mds%d caps went stale, renewing\n",
>                       session->s_mds);
> -             spin_lock(&session->s_cap_lock);
> +             spin_lock(&session->s_gen_ttl_lock);
>               session->s_cap_gen++;
>               session->s_cap_ttl = 0;
> -             spin_unlock(&session->s_cap_lock);
> +             spin_unlock(&session->s_gen_ttl_lock);
>               send_renew_caps(mdsc, session);
>               break;
>  
> diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
> index a50ca0e..8c7c04e 100644
> --- a/fs/ceph/mds_client.h
> +++ b/fs/ceph/mds_client.h
> @@ -117,10 +117,13 @@ struct ceph_mds_session {
>       void             *s_authorizer_buf, *s_authorizer_reply_buf;
>       size_t            s_authorizer_buf_len, s_authorizer_reply_buf_len;
>  
> -     /* protected by s_cap_lock */
> -     spinlock_t        s_cap_lock;
> +     /* protected by s_gen_ttl_lock */
> +     spinlock_t        s_gen_ttl_lock;
>       u32               s_cap_gen;  /* inc each time we get mds stale msg */
>       unsigned long     s_cap_ttl;  /* when session caps expire */
> +
> +     /* protected by s_cap_lock */
> +     spinlock_t        s_cap_lock;
>       struct list_head  s_caps;     /* all caps issued by this session */
>       int               s_nr_caps, s_trim_caps;
>       int               s_num_cap_releases;
> -- 
> 1.7.5.4
> 
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
> the body of a message to [email protected]
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 
--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to