From patchwork Fri Apr 24 13:22:18 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Douglas Fuller X-Patchwork-Id: 6270411 Return-Path: X-Original-To: patchwork-ceph-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 0D6B19F1C4 for ; Fri, 24 Apr 2015 13:23:05 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 64B5A20220 for ; Fri, 24 Apr 2015 13:23:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D0F80202F2 for ; Fri, 24 Apr 2015 13:22:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753741AbbDXNW4 (ORCPT ); Fri, 24 Apr 2015 09:22:56 -0400 Received: from mx1.redhat.com ([209.132.183.28]:58620 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751217AbbDXNWz (ORCPT ); Fri, 24 Apr 2015 09:22:55 -0400 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t3ODMspw020174 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Fri, 24 Apr 2015 09:22:55 -0400 Received: from rex001.front.sepia.ceph.com (vpn-55-141.rdu2.redhat.com [10.10.55.141]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t3ODMlWF020121 for ; Fri, 24 Apr 2015 09:22:53 -0400 From: Douglas Fuller To: ceph-devel@vger.kernel.org Subject: [PATCHv2 2/3] rbd: combine object method calls in header refresh using fewer ceph_msgs Date: Fri, 24 Apr 2015 06:22:18 -0700 Message-Id: <2589bb4ce9f65aa5202ea10582f988e1833a92aa.1429881439.git.dfuller@redhat.com> In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 Sender: ceph-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Douglas Fuller --- drivers/block/rbd.c | 331 ++++++++++++++++++++++++++++++++++++---- include/linux/ceph/osd_client.h | 2 +- 2 files changed, 306 insertions(+), 27 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 8125233..9184b43 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -4667,20 +4667,23 @@ static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev) bool first_time = rbd_dev->header.object_prefix == NULL; int ret; - ret = rbd_dev_v2_image_size(rbd_dev); - if (ret) - return ret; + if (!first_time) + { + ret = rbd_dev_v2_image_size(rbd_dev); + if (ret) + return ret; - if (first_time) { + ret = rbd_dev_v2_snap_context(rbd_dev); + dout("rbd_dev_v2_snap_context returned %d\n", ret); + return ret; + } + else + { ret = rbd_dev_v2_header_onetime(rbd_dev); if (ret) return ret; } - - ret = rbd_dev_v2_snap_context(rbd_dev); - dout("rbd_dev_v2_snap_context returned %d\n", ret); - - return ret; + return ret; /* XXX change logic? */ } static int rbd_dev_header_info(struct rbd_device *rbd_dev) @@ -5091,36 +5094,312 @@ static void rbd_dev_unprobe(struct rbd_device *rbd_dev) memset(header, 0, sizeof (*header)); } +static struct ceph_osd_request * rbd_obj_header_req_alloc( + struct rbd_device *rbd_dev, + int num_ops) +{ + struct ceph_osd_request *osd_req; + struct page ***replies; + + replies = kmalloc(CEPH_OSD_MAX_OP * sizeof(*replies), GFP_KERNEL); + if (!replies) + return NULL; + + osd_req = ceph_osdc_alloc_request(&rbd_dev->rbd_client->client->osdc, + NULL, num_ops, false, GFP_KERNEL); + if (!osd_req) { + kfree(replies); + return NULL; + } + + osd_req->r_flags = CEPH_OSD_FLAG_READ; + osd_req->r_base_oloc.pool = ceph_file_layout_pg_pool(rbd_dev->layout); + osd_req->r_priv = replies; + ceph_oid_set_name(&osd_req->r_base_oid, rbd_dev->header_name); + + return osd_req; +} + +static int rbd_obj_header_method_add(struct ceph_osd_request *osd_req, + int which, + const char *class_name, + const char *method_name, + const void *outbound, + size_t outbound_size, + size_t inbound_size) +{ + u32 page_count; + struct page ***replies = osd_req->r_priv; + + BUG_ON(which >= osd_req->r_num_ops); + + osd_req_op_cls_init(osd_req, which, CEPH_OSD_OP_CALL, + class_name, method_name); + + if (outbound_size) { + struct ceph_pagelist *pagelist; + pagelist = kmalloc(sizeof(*pagelist), GFP_NOFS); + /* XXX is this ever freed? */ + if (!pagelist) + return -ENOMEM; + + ceph_pagelist_init(pagelist); + ceph_pagelist_append(pagelist, outbound, outbound_size); + osd_req_op_cls_request_data_pagelist(osd_req, which, pagelist); + } + + page_count = (u32)calc_pages_for(0, inbound_size); + replies[which] = ceph_alloc_page_vector(page_count, GFP_KERNEL); + if (IS_ERR(replies[which])) + return PTR_ERR(replies[which]); + osd_req_op_cls_response_data_pages(osd_req, which, replies[which], + inbound_size, 0, false, false); + + return 0; +} + +static int rbd_obj_header_req_exec(struct rbd_device * rbd_dev, + struct ceph_osd_request *osd_req) +{ + int ret; + + ceph_osdc_build_request(osd_req, 0, NULL, cpu_to_le64(CEPH_NOSNAP), NULL); + ret = ceph_osdc_start_request(&rbd_dev->rbd_client->client->osdc, + osd_req, false); + if (ret) { + ceph_osdc_put_request(osd_req); + return ret; + } + + ret = ceph_osdc_wait_request(&rbd_dev->rbd_client->client->osdc, osd_req); + if (ret < 0) { + ceph_osdc_cancel_request(osd_req); + return ret; + } + + return 0; +} + +static int rbd_obj_header_method_retrieve(struct ceph_osd_request *osd_req, + int which, void *buf, size_t length) +{ + struct page ***replies = (struct page ***)osd_req->r_priv; + size_t reply_length = osd_req->r_reply_op_len[which]; + + BUG_ON(reply_length > length); + + ceph_copy_from_page_vector(replies[which], buf, 0, reply_length); + ceph_release_page_vector(replies[which], calc_pages_for(0, reply_length)); + + return reply_length; +} + +static void rbd_obj_header_req_destroy(struct ceph_osd_request *osd_req) +{ + if (osd_req) { + kfree(osd_req->r_priv); + ceph_osdc_put_request(osd_req); + } +} + +static int __extract_prefix(struct rbd_device *rbd_dev, + struct ceph_osd_request *osd_req, + int which) +{ + void *prefix_buf; + void * p; + size_t prefix_buflen; + int ret; + + prefix_buf = kzalloc(RBD_OBJ_PREFIX_LEN_MAX, GFP_KERNEL); + if (!prefix_buf) + return -ENOMEM; + + prefix_buflen = rbd_obj_header_method_retrieve(osd_req, which, + prefix_buf, RBD_OBJ_PREFIX_LEN_MAX); + p = prefix_buf; + rbd_dev->header.object_prefix = ceph_extract_encoded_string(&p, + p + prefix_buflen, NULL, GFP_KERNEL); + + if (IS_ERR(rbd_dev->header.object_prefix)) { + ret = PTR_ERR(rbd_dev->header.object_prefix); + rbd_dev->header.object_prefix = NULL; + goto out_err; + } + + ret = 0; + +out_err: + kfree(prefix_buf); + return ret; +} + +static int __extract_features(struct rbd_device *rbd_dev, + struct ceph_osd_request *osd_req, + int which) +{ + int ret; + struct { + __le64 features; + __le64 incompat; + } __attribute__((packed)) features_buf = { 0 }; + u64 incompat; + + rbd_obj_header_method_retrieve(osd_req, which, + &features_buf, sizeof(features_buf)); + incompat = le64_to_cpu(features_buf.incompat); + if (incompat & ~RBD_FEATURES_SUPPORTED) { + ret = -ENXIO; + goto out_err; + } + rbd_dev->header.features = le64_to_cpu(features_buf.features); + + ret = 0; + +out_err: + return ret; +} + +static int __extract_snapcontext(struct rbd_device *rbd_dev, + struct ceph_osd_request *osd_req, + int which) +{ + void *snapc_buf; + size_t snapc_max; + size_t snapc_buflen; + + void *p; + void *q; + + struct ceph_snap_context * snapc; + + u32 seq; + u32 snap_count; + + int i; + int ret; + + snapc_max = sizeof(__le64) + sizeof(__le32) + + RBD_MAX_SNAP_COUNT * sizeof(__le64); + + snapc_buf = kzalloc(snapc_max, GFP_KERNEL); + if (!snapc_buf) { + ret = -ENOMEM; + goto out_err; + } + + snapc_buflen = rbd_obj_header_method_retrieve(osd_req, which, + snapc_buf, snapc_max); + + p = snapc_buf; + q = snapc_buf + snapc_buflen; + ret = -ERANGE; + ceph_decode_64_safe(&p, q, seq, out_err); + ceph_decode_32_safe(&p, q, snap_count, out_err); + + if (snap_count > (SIZE_MAX - sizeof(struct ceph_snap_context)) / + sizeof(u64)) { + ret = -EINVAL; + goto out_err; + } + if (!ceph_has_room(&p, q, snap_count * sizeof(__le64))) + goto out_err; + + snapc = ceph_create_snap_context(snap_count, GFP_KERNEL); + if (!snapc) { + ret = -ENOMEM; + } + + snapc->seq = seq; + for (i=0; i < snap_count; i++) + snapc->snaps[i] = ceph_decode_64(&p); + ceph_put_snap_context(rbd_dev->header.snapc); + rbd_dev->header.snapc = snapc; + + ret = 0; +out_err: + kfree(snapc_buf); + return ret; +} + +static int __extract_size(struct rbd_device *rbd_dev, + struct ceph_osd_request *osd_req, + int which) +{ + struct { + u8 order; + __le64 size; + } __attribute((packed)) size_buf = { 0 }; + + rbd_obj_header_method_retrieve(osd_req, which, &size_buf, sizeof(size_buf)); + + rbd_dev->header.obj_order = size_buf.order; + rbd_dev->header.image_size = le64_to_cpu(size_buf.size); + + return 0; +} + static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev) { int ret; - ret = rbd_dev_v2_object_prefix(rbd_dev); + size_t snapc_max; + __le64 snapid = cpu_to_le64(CEPH_NOSNAP); + struct ceph_osd_request *osd_req; + + snapc_max = sizeof(__le64) + sizeof(__le32) + + RBD_MAX_SNAP_COUNT * sizeof(__le64); + + osd_req = rbd_obj_header_req_alloc(rbd_dev, 4); + + if (!osd_req) { + ret = -ENOMEM; + goto out_err; + } + + ret = rbd_obj_header_method_add(osd_req, 0, + "rbd", "get_object_prefix", + NULL, 0, RBD_OBJ_PREFIX_LEN_MAX); if (ret) goto out_err; - /* - * Get the and check features for the image. Currently the - * features are assumed to never change. - */ - ret = rbd_dev_v2_features(rbd_dev); + ret = rbd_obj_header_method_add(osd_req, 1, + "rbd", "get_features", + &snapid, sizeof(snapid), + sizeof(struct{__le64 features;__le64 incompat;} __attribute__((packed)))); if (ret) goto out_err; - /* If the image supports fancy striping, get its parameters */ + ret = rbd_obj_header_method_add(osd_req, 2, + "rbd", "get_snapcontext", + NULL, 0, snapc_max); + if (ret) + goto out_err; - if (rbd_dev->header.features & RBD_FEATURE_STRIPINGV2) { - ret = rbd_dev_v2_striping_info(rbd_dev); - if (ret < 0) - goto out_err; - } - /* No support for crypto and compression type format 2 images */ + ret = rbd_obj_header_method_add(osd_req, 3, + "rbd", "get_size", + &snapid, sizeof(snapid), + sizeof(struct{u8 order; __le64 size;}__attribute((packed)))); + if (ret) + goto out_err; + + ret = rbd_obj_header_req_exec(rbd_dev, osd_req); + if (ret) + goto out_err; + + if ((ret = __extract_prefix(rbd_dev, osd_req, 0))) + goto out_err; + if ((ret = __extract_features(rbd_dev, osd_req, 1))) + goto out_err; + if ((ret = __extract_snapcontext(rbd_dev, osd_req, 2))) + goto out_err; + if ((ret = __extract_size(rbd_dev, osd_req, 3))) + goto out_err; + + ret = 0; - return 0; out_err: - rbd_dev->header.features = 0; - kfree(rbd_dev->header.object_prefix); - rbd_dev->header.object_prefix = NULL; + rbd_obj_header_req_destroy(osd_req); return ret; } diff --git a/include/linux/ceph/osd_client.h b/include/linux/ceph/osd_client.h index 65fcf80..71c946d 100644 --- a/include/linux/ceph/osd_client.h +++ b/include/linux/ceph/osd_client.h @@ -43,7 +43,7 @@ struct ceph_osd { }; -#define CEPH_OSD_MAX_OP 3 +#define CEPH_OSD_MAX_OP 4 enum ceph_osd_data_type { CEPH_OSD_DATA_TYPE_NONE = 0,