From patchwork Fri Aug 24 16:36:27 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Elder X-Patchwork-Id: 1372211 Return-Path: X-Original-To: patchwork-ceph-devel@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id 2D949DFFCC for ; Fri, 24 Aug 2012 16:36:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1030224Ab2HXQgb (ORCPT ); Fri, 24 Aug 2012 12:36:31 -0400 Received: from mail-iy0-f174.google.com ([209.85.210.174]:49774 "EHLO mail-iy0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S964934Ab2HXQg3 (ORCPT ); Fri, 24 Aug 2012 12:36:29 -0400 Received: by mail-iy0-f174.google.com with SMTP id o24so3740650ial.19 for ; Fri, 24 Aug 2012 09:36:28 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:subject:references :in-reply-to:content-type:content-transfer-encoding :x-gm-message-state; bh=JYkX86RxusLyuKFn4IhtssN3/CjecSbDruOmiRKm7ic=; b=pU3mRs+mqztWDUFWOirYHHy7QmoytvEFUQAQe4+/fp0MlcKLmRUq/g0+2r1EMzw4SK QXZ1+Ate+zLb8gEWP8Py9GP8eFwG1crSo0QmwyrCzOUfZxmyecYrcNZYm24yj9Lb7j0m +oHPyKweRJxMDUTRiIKHSzSOaltLp4lPhP57pFptOMRBZTvwvQxHxQ3O8qEYlrDXpIj/ iVJxuOOCAaSSW1TQqfPvXxhZoPo0D6ggjRBr/PodOKQy9u8MPppcV3zQf6xC6e+AjUKV pn2ePMhNNfz37eo0GYqsHw3BGBUkQkMWWHskRpYcbf1+JBurwyP63Znq2C34DPrMcJGc k0kw== Received: by 10.50.158.196 with SMTP id ww4mr2915830igb.5.1345826188808; Fri, 24 Aug 2012 09:36:28 -0700 (PDT) Received: from [172.22.22.4] (c-71-195-31-37.hsd1.mn.comcast.net. [71.195.31.37]) by mx.google.com with ESMTPS id df1sm691131igc.10.2012.08.24.09.36.27 (version=SSLv3 cipher=OTHER); Fri, 24 Aug 2012 09:36:28 -0700 (PDT) Message-ID: <5037AD8B.2020805@inktank.com> Date: Fri, 24 Aug 2012 11:36:27 -0500 From: Alex Elder User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:14.0) Gecko/20120714 Thunderbird/14.0 MIME-Version: 1.0 To: ceph-devel@vger.kernel.org Subject: [PATCH 11/11] rbd: split up rbd_get_segment() References: <5037AB20.4000103@inktank.com> In-Reply-To: <5037AB20.4000103@inktank.com> X-Gm-Message-State: ALoCoQlhOWyd1Jf7/bisUc1g/qc9uHRAdFLRz4wCvQEBMXv/f9FKO5TYBTR9AE2W5AEuum9vOWUf Sender: ceph-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org There are two places where rbd_get_segment() is called. One, in rbd_rq_fn(), only needs to know the length within a segment that an I/O request should be. The other, in rbd_do_op(), also needs the name of the object and the offset within it for the I/O request. Split out rbd_segment_name() into three dedicated functions: - rbd_segment_name() allocates and formats the name of the object for a segment containing a given rbd image offset - rbd_segment_offset() computes the offset within a segment for a given rbd image offset - rbd_segment_length() computes the length to use for I/O within a segment for a request, not to exceed the end of a segment object. In the new functions be a bit more careful, checking for possible error conditions: - watch for errors or overflows returned by snprintf() - catch (using BUG_ON()) potential overflow conditions when computing segment length Signed-off-by: Alex Elder Reviewed-by: Yehuda Sadeh --- drivers/block/rbd.c | 66 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 26 deletions(-) static int rbd_get_num_segments(struct rbd_image_header *header, @@ -1114,14 +1134,11 @@ static int rbd_do_op(struct request *rq, struct ceph_osd_req_op *ops; u32 payload_len; - seg_name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO); + seg_name = rbd_segment_name(rbd_dev, ofs); if (!seg_name) return -ENOMEM; - - seg_len = rbd_get_segment(&rbd_dev->header, - rbd_dev->header.object_prefix, - ofs, len, - seg_name, &seg_ofs); + seg_len = rbd_segment_length(rbd_dev, ofs, len); + seg_ofs = rbd_segment_offset(rbd_dev, ofs); payload_len = (flags & CEPH_OSD_FLAG_WRITE ? seg_len : 0); @@ -1532,10 +1549,7 @@ static void rbd_rq_fn(struct request_queue *q) do { /* a bio clone to be passed down to OSD req */ dout("rq->bio->bi_vcnt=%hu\n", rq->bio->bi_vcnt); - op_size = rbd_get_segment(&rbd_dev->header, - rbd_dev->header.object_prefix, - ofs, size, - NULL, NULL); + op_size = rbd_segment_length(rbd_dev, ofs, size); kref_get(&coll->kref); bio = bio_chain_clone(&rq_bio, &next_bio, &bp, op_size, GFP_ATOMIC); diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index b649446..3a79e58 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -656,27 +656,47 @@ static void rbd_header_free(struct rbd_image_header *header) header->snapc = NULL; } -/* - * get the actual striped segment name, offset and length - */ -static u64 rbd_get_segment(struct rbd_image_header *header, - const char *object_prefix, - u64 ofs, u64 len, - char *seg_name, u64 *segofs) +static char *rbd_segment_name(struct rbd_device *rbd_dev, u64 offset) +{ + char *name; + u64 segment; + int ret; + + name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO); + if (!name) + return NULL; + segment = offset >> rbd_dev->header.obj_order; + ret = snprintf(name, RBD_MAX_SEG_NAME_LEN, "%s.%012llx", + rbd_dev->header.object_prefix, segment); + if (ret < 0 || ret >= RBD_MAX_SEG_NAME_LEN) { + pr_err("error formatting segment name for #%llu (%d)\n", + segment, ret); + kfree(name); + name = NULL; + } + + return name; +} + +static u64 rbd_segment_offset(struct rbd_device *rbd_dev, u64 offset) { - u64 seg = ofs >> header->obj_order; + u64 segment_size = (u64) 1 << rbd_dev->header.obj_order; - if (seg_name) - snprintf(seg_name, RBD_MAX_SEG_NAME_LEN, - "%s.%012llx", object_prefix, seg); + return offset & (segment_size - 1); +} + +static u64 rbd_segment_length(struct rbd_device *rbd_dev, + u64 offset, u64 length) +{ + u64 segment_size = (u64) 1 << rbd_dev->header.obj_order; - ofs = ofs & ((1 << header->obj_order) - 1); - len = min_t(u64, len, (1 << header->obj_order) - ofs); + offset &= segment_size - 1; - if (segofs) - *segofs = ofs; + BUG_ON(length > U64_MAX - offset); + if (offset + length > segment_size) + length = segment_size - offset; - return len; + return length; }