ceph: make sure mdsc->mutex is nested in s->s_mutex to fix dead lock
[platform/kernel/linux-rpi.git] / fs / ceph / mds_client.c
index 486f91f..0e0ab01 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/seq_file.h>
 #include <linux/ratelimit.h>
 #include <linux/bits.h>
+#include <linux/ktime.h>
 
 #include "super.h"
 #include "mds_client.h"
@@ -658,6 +659,7 @@ void ceph_put_mds_session(struct ceph_mds_session *s)
        if (refcount_dec_and_test(&s->s_ref)) {
                if (s->s_auth.authorizer)
                        ceph_auth_destroy_authorizer(s->s_auth.authorizer);
+               WARN_ON(mutex_is_locked(&s->s_mutex));
                xa_destroy(&s->s_delegated_inos);
                kfree(s);
        }
@@ -753,6 +755,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
        INIT_LIST_HEAD(&s->s_cap_releases);
        INIT_WORK(&s->s_cap_release_work, ceph_cap_release_work);
 
+       INIT_LIST_HEAD(&s->s_cap_dirty);
        INIT_LIST_HEAD(&s->s_cap_flushing);
 
        mdsc->sessions[mds] = s;
@@ -2201,6 +2204,7 @@ ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode)
        mutex_init(&req->r_fill_mutex);
        req->r_mdsc = mdsc;
        req->r_started = jiffies;
+       req->r_start_latency = ktime_get();
        req->r_resend_mds = -1;
        INIT_LIST_HEAD(&req->r_unsafe_dir_item);
        INIT_LIST_HEAD(&req->r_unsafe_target_item);
@@ -2547,6 +2551,8 @@ out:
 static void complete_request(struct ceph_mds_client *mdsc,
                             struct ceph_mds_request *req)
 {
+       req->r_end_latency = ktime_get();
+
        if (req->r_callback)
                req->r_callback(mdsc, req);
        complete_all(&req->r_completion);
@@ -3155,6 +3161,9 @@ out_err:
 
        /* kick calling process */
        complete_request(mdsc, req);
+
+       ceph_update_metadata_latency(&mdsc->metric, req->r_start_latency,
+                                    req->r_end_latency, err);
 out:
        ceph_mdsc_put_request(req);
        return;
@@ -3251,8 +3260,7 @@ static void handle_session(struct ceph_mds_session *session,
        void *end = p + msg->front.iov_len;
        struct ceph_mds_session_head *h;
        u32 op;
-       u64 seq;
-       unsigned long features = 0;
+       u64 seq, features = 0;
        int wake = 0;
        bool blacklisted = false;
 
@@ -3271,9 +3279,8 @@ static void handle_session(struct ceph_mds_session *session,
                        goto bad;
                /* version >= 3, feature bits */
                ceph_decode_32_safe(&p, end, len, bad);
-               ceph_decode_need(&p, end, len, bad);
-               memcpy(&features, p, min_t(size_t, len, sizeof(features)));
-               p += len;
+               ceph_decode_64_safe(&p, end, features, bad);
+               p += len - sizeof(features);
        }
 
        mutex_lock(&mdsc->mutex);
@@ -3762,8 +3769,6 @@ fail:
  * recovering MDS might have.
  *
  * This is a relatively heavyweight operation, but it's rare.
- *
- * called with mdsc->mutex held.
  */
 static void send_mds_reconnect(struct ceph_mds_client *mdsc,
                               struct ceph_mds_session *session)
@@ -4017,7 +4022,11 @@ static void check_new_map(struct ceph_mds_client *mdsc,
                            oldstate != CEPH_MDS_STATE_STARTING)
                                pr_info("mds%d recovery completed\n", s->s_mds);
                        kick_requests(mdsc, i);
+                       mutex_unlock(&mdsc->mutex);
+                       mutex_lock(&s->s_mutex);
+                       mutex_lock(&mdsc->mutex);
                        ceph_kick_flushing_caps(mdsc, s);
+                       mutex_unlock(&s->s_mutex);
                        wake_up_session_caps(s, RECONNECT);
                }
        }
@@ -4325,6 +4334,7 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
 
 {
        struct ceph_mds_client *mdsc;
+       int err;
 
        mdsc = kzalloc(sizeof(struct ceph_mds_client), GFP_NOFS);
        if (!mdsc)
@@ -4333,8 +4343,8 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
        mutex_init(&mdsc->mutex);
        mdsc->mdsmap = kzalloc(sizeof(*mdsc->mdsmap), GFP_NOFS);
        if (!mdsc->mdsmap) {
-               kfree(mdsc);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto err_mdsc;
        }
 
        fsc->mdsc = mdsc;
@@ -4366,13 +4376,15 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
        spin_lock_init(&mdsc->snap_flush_lock);
        mdsc->last_cap_flush_tid = 1;
        INIT_LIST_HEAD(&mdsc->cap_flush_list);
-       INIT_LIST_HEAD(&mdsc->cap_dirty);
        INIT_LIST_HEAD(&mdsc->cap_dirty_migrating);
        mdsc->num_cap_flushing = 0;
        spin_lock_init(&mdsc->cap_dirty_lock);
        init_waitqueue_head(&mdsc->cap_flushing_wq);
        INIT_WORK(&mdsc->cap_reclaim_work, ceph_cap_reclaim_work);
        atomic_set(&mdsc->cap_reclaim_pending, 0);
+       err = ceph_metric_init(&mdsc->metric);
+       if (err)
+               goto err_mdsmap;
 
        spin_lock_init(&mdsc->dentry_list_lock);
        INIT_LIST_HEAD(&mdsc->dentry_leases);
@@ -4391,6 +4403,12 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
        strscpy(mdsc->nodename, utsname()->nodename,
                sizeof(mdsc->nodename));
        return 0;
+
+err_mdsmap:
+       kfree(mdsc->mdsmap);
+err_mdsc:
+       kfree(mdsc);
+       return err;
 }
 
 /*
@@ -4648,6 +4666,8 @@ void ceph_mdsc_destroy(struct ceph_fs_client *fsc)
 
        ceph_mdsc_stop(mdsc);
 
+       ceph_metric_destroy(&mdsc->metric);
+
        fsc->mdsc = NULL;
        kfree(mdsc);
        dout("mdsc_destroy %p done\n", mdsc);