Merge tag 'ceph-for-4.9-rc1' of git://github.com/ceph/ceph-client
[cascardo/linux.git] / drivers / block / rbd.c
index 5e55d1c..abb7162 100644 (file)
@@ -986,7 +986,6 @@ static int rbd_header_from_disk(struct rbd_device *rbd_dev,
        char *snap_names = NULL;
        u64 *snap_sizes = NULL;
        u32 snap_count;
-       size_t size;
        int ret = -ENOMEM;
        u32 i;
 
@@ -1024,9 +1023,9 @@ static int rbd_header_from_disk(struct rbd_device *rbd_dev,
                        goto out_err;
 
                /* ...as well as the array of their sizes. */
-
-               size = snap_count * sizeof (*header->snap_sizes);
-               snap_sizes = kmalloc(size, GFP_KERNEL);
+               snap_sizes = kmalloc_array(snap_count,
+                                          sizeof(*header->snap_sizes),
+                                          GFP_KERNEL);
                if (!snap_sizes)
                        goto out_err;
 
@@ -1618,11 +1617,17 @@ static bool obj_request_type_valid(enum obj_request_type type)
        }
 }
 
+static void rbd_img_obj_callback(struct rbd_obj_request *obj_request);
+
 static void rbd_obj_request_submit(struct rbd_obj_request *obj_request)
 {
        struct ceph_osd_request *osd_req = obj_request->osd_req;
 
        dout("%s %p osd_req %p\n", __func__, obj_request, osd_req);
+       if (obj_request_img_data_test(obj_request)) {
+               WARN_ON(obj_request->callback != rbd_img_obj_callback);
+               rbd_img_request_get(obj_request->img_request);
+       }
        ceph_osdc_start_request(osd_req->r_osdc, osd_req, false);
 }
 
@@ -1813,6 +1818,22 @@ static void rbd_obj_request_complete(struct rbd_obj_request *obj_request)
                complete_all(&obj_request->completion);
 }
 
+static void rbd_obj_request_error(struct rbd_obj_request *obj_request, int err)
+{
+       obj_request->result = err;
+       obj_request->xferred = 0;
+       /*
+        * kludge - mirror rbd_obj_request_submit() to match a put in
+        * rbd_img_obj_callback()
+        */
+       if (obj_request_img_data_test(obj_request)) {
+               WARN_ON(obj_request->callback != rbd_img_obj_callback);
+               rbd_img_request_get(obj_request->img_request);
+       }
+       obj_request_done_set(obj_request);
+       rbd_obj_request_complete(obj_request);
+}
+
 static void rbd_osd_read_callback(struct rbd_obj_request *obj_request)
 {
        struct rbd_img_request *img_request = NULL;
@@ -1945,11 +1966,10 @@ static void rbd_osd_req_callback(struct ceph_osd_request *osd_req)
 
 static void rbd_osd_req_format_read(struct rbd_obj_request *obj_request)
 {
-       struct rbd_img_request *img_request = obj_request->img_request;
        struct ceph_osd_request *osd_req = obj_request->osd_req;
 
-       if (img_request)
-               osd_req->r_snapid = img_request->snap_id;
+       rbd_assert(obj_request_img_data_test(obj_request));
+       osd_req->r_snapid = obj_request->img_request->snap_id;
 }
 
 static void rbd_osd_req_format_write(struct rbd_obj_request *obj_request)
@@ -2142,7 +2162,9 @@ static void rbd_obj_request_destroy(struct kref *kref)
                        bio_chain_put(obj_request->bio_list);
                break;
        case OBJ_REQUEST_PAGES:
-               if (obj_request->pages)
+               /* img_data requests don't own their page array */
+               if (obj_request->pages &&
+                   !obj_request_img_data_test(obj_request))
                        ceph_release_page_vector(obj_request->pages,
                                                obj_request->page_count);
                break;
@@ -2363,13 +2385,6 @@ static bool rbd_img_obj_end_request(struct rbd_obj_request *obj_request)
                xferred = obj_request->length;
        }
 
-       /* Image object requests don't own their page array */
-
-       if (obj_request->type == OBJ_REQUEST_PAGES) {
-               obj_request->pages = NULL;
-               obj_request->page_count = 0;
-       }
-
        if (img_request_child_test(img_request)) {
                rbd_assert(img_request->obj_request != NULL);
                more = obj_request->which < img_request->obj_request_count - 1;
@@ -2588,8 +2603,6 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
 
                rbd_img_obj_request_fill(obj_request, osd_req, op_type, 0);
 
-               rbd_img_request_get(img_request);
-
                img_offset += length;
                resid -= length;
        }
@@ -2670,7 +2683,7 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
        rbd_assert(obj_request_type_valid(orig_request->type));
        img_result = img_request->result;
        parent_length = img_request->length;
-       rbd_assert(parent_length == img_request->xferred);
+       rbd_assert(img_result || parent_length == img_request->xferred);
        rbd_img_request_put(img_request);
 
        rbd_assert(orig_request->img_request);
@@ -2723,12 +2736,8 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
        return;
 
 out_err:
-       /* Record the error code and complete the request */
-
-       orig_request->result = img_result;
-       orig_request->xferred = 0;
-       obj_request_done_set(orig_request);
-       rbd_obj_request_complete(orig_request);
+       ceph_release_page_vector(pages, page_count);
+       rbd_obj_request_error(orig_request, img_result);
 }
 
 /*
@@ -2879,21 +2888,30 @@ static void rbd_img_obj_exists_callback(struct rbd_obj_request *obj_request)
        return;
 
 fail_orig_request:
-       orig_request->result = result;
-       orig_request->xferred = 0;
-       obj_request_done_set(orig_request);
-       rbd_obj_request_complete(orig_request);
+       rbd_obj_request_error(orig_request, result);
 }
 
 static int rbd_img_obj_exists_submit(struct rbd_obj_request *obj_request)
 {
        struct rbd_device *rbd_dev = obj_request->img_request->rbd_dev;
        struct rbd_obj_request *stat_request;
-       struct page **pages = NULL;
+       struct page **pages;
        u32 page_count;
        size_t size;
        int ret;
 
+       stat_request = rbd_obj_request_create(obj_request->object_name, 0, 0,
+                                             OBJ_REQUEST_PAGES);
+       if (!stat_request)
+               return -ENOMEM;
+
+       stat_request->osd_req = rbd_osd_req_create(rbd_dev, OBJ_OP_READ, 1,
+                                                  stat_request);
+       if (!stat_request->osd_req) {
+               ret = -ENOMEM;
+               goto fail_stat_request;
+       }
+
        /*
         * The response data for a STAT call consists of:
         *     le64 length;
@@ -2905,38 +2923,26 @@ static int rbd_img_obj_exists_submit(struct rbd_obj_request *obj_request)
        size = sizeof (__le64) + sizeof (__le32) + sizeof (__le32);
        page_count = (u32)calc_pages_for(0, size);
        pages = ceph_alloc_page_vector(page_count, GFP_KERNEL);
-       if (IS_ERR(pages))
-               return PTR_ERR(pages);
+       if (IS_ERR(pages)) {
+               ret = PTR_ERR(pages);
+               goto fail_stat_request;
+       }
 
-       ret = -ENOMEM;
-       stat_request = rbd_obj_request_create(obj_request->object_name, 0, 0,
-                                                       OBJ_REQUEST_PAGES);
-       if (!stat_request)
-               goto out;
+       osd_req_op_init(stat_request->osd_req, 0, CEPH_OSD_OP_STAT, 0);
+       osd_req_op_raw_data_in_pages(stat_request->osd_req, 0, pages, size, 0,
+                                    false, false);
 
        rbd_obj_request_get(obj_request);
        stat_request->obj_request = obj_request;
        stat_request->pages = pages;
        stat_request->page_count = page_count;
-
-       stat_request->osd_req = rbd_osd_req_create(rbd_dev, OBJ_OP_READ, 1,
-                                                  stat_request);
-       if (!stat_request->osd_req)
-               goto out;
        stat_request->callback = rbd_img_obj_exists_callback;
 
-       osd_req_op_init(stat_request->osd_req, 0, CEPH_OSD_OP_STAT, 0);
-       osd_req_op_raw_data_in_pages(stat_request->osd_req, 0, pages, size, 0,
-                                       false, false);
-       rbd_osd_req_format_read(stat_request);
-
        rbd_obj_request_submit(stat_request);
        return 0;
 
-out:
-       if (ret)
-               rbd_obj_request_put(obj_request);
-
+fail_stat_request:
+       rbd_obj_request_put(stat_request);
        return ret;
 }
 
@@ -4027,7 +4033,6 @@ static int rbd_obj_method_sync(struct rbd_device *rbd_dev,
        osd_req_op_cls_response_data_pages(obj_request->osd_req, 0,
                                        obj_request->pages, inbound_size,
                                        0, false, false);
-       rbd_osd_req_format_read(obj_request);
 
        rbd_obj_request_submit(obj_request);
        ret = rbd_obj_request_wait(obj_request);
@@ -4269,7 +4274,6 @@ static int rbd_obj_read_sync(struct rbd_device *rbd_dev,
                                        obj_request->length,
                                        obj_request->offset & ~PAGE_MASK,
                                        false, false);
-       rbd_osd_req_format_read(obj_request);
 
        rbd_obj_request_submit(obj_request);
        ret = rbd_obj_request_wait(obj_request);
@@ -4440,7 +4444,6 @@ static int rbd_init_request(void *data, struct request *rq,
 
 static struct blk_mq_ops rbd_mq_ops = {
        .queue_rq       = rbd_queue_rq,
-       .map_queue      = blk_mq_map_queue,
        .init_request   = rbd_init_request,
 };