aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorAlex Elder <elder@inktank.com>2012-08-09 13:33:26 -0400
committerAlex Elder <elder@inktank.com>2012-10-01 15:30:50 -0400
commit65ccfe21dd8fb402547bb1c50bbc2737c4ef37b8 (patch)
treedc2406bae46fd943deee2ca03e4edacaa0cd65bf /drivers/block
parentdf111be6310fc41d059a485368e3c51a684859c2 (diff)
rbd: split up rbd_get_segment()
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 <elder@inktank.com> Reviewed-by: Yehuda Sadeh <yehuda@inktank.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/rbd.c66
1 files changed, 40 insertions, 26 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 6da6990a7b57..7ba70c49bbdb 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -669,27 +669,47 @@ static void rbd_header_free(struct rbd_image_header *header)
669 header->snapc = NULL; 669 header->snapc = NULL;
670} 670}
671 671
672/* 672static char *rbd_segment_name(struct rbd_device *rbd_dev, u64 offset)
673 * get the actual striped segment name, offset and length 673{
674 */ 674 char *name;
675static u64 rbd_get_segment(struct rbd_image_header *header, 675 u64 segment;
676 const char *object_prefix, 676 int ret;
677 u64 ofs, u64 len, 677
678 char *seg_name, u64 *segofs) 678 name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO);
679 if (!name)
680 return NULL;
681 segment = offset >> rbd_dev->header.obj_order;
682 ret = snprintf(name, RBD_MAX_SEG_NAME_LEN, "%s.%012llx",
683 rbd_dev->header.object_prefix, segment);
684 if (ret < 0 || ret >= RBD_MAX_SEG_NAME_LEN) {
685 pr_err("error formatting segment name for #%llu (%d)\n",
686 segment, ret);
687 kfree(name);
688 name = NULL;
689 }
690
691 return name;
692}
693
694static u64 rbd_segment_offset(struct rbd_device *rbd_dev, u64 offset)
679{ 695{
680 u64 seg = ofs >> header->obj_order; 696 u64 segment_size = (u64) 1 << rbd_dev->header.obj_order;
681 697
682 if (seg_name) 698 return offset & (segment_size - 1);
683 snprintf(seg_name, RBD_MAX_SEG_NAME_LEN, 699}
684 "%s.%012llx", object_prefix, seg); 700
701static u64 rbd_segment_length(struct rbd_device *rbd_dev,
702 u64 offset, u64 length)
703{
704 u64 segment_size = (u64) 1 << rbd_dev->header.obj_order;
685 705
686 ofs = ofs & ((1 << header->obj_order) - 1); 706 offset &= segment_size - 1;
687 len = min_t(u64, len, (1 << header->obj_order) - ofs);
688 707
689 if (segofs) 708 BUG_ON(length > U64_MAX - offset);
690 *segofs = ofs; 709 if (offset + length > segment_size)
710 length = segment_size - offset;
691 711
692 return len; 712 return length;
693} 713}
694 714
695static int rbd_get_num_segments(struct rbd_image_header *header, 715static int rbd_get_num_segments(struct rbd_image_header *header,
@@ -1127,14 +1147,11 @@ static int rbd_do_op(struct request *rq,
1127 struct ceph_osd_req_op *ops; 1147 struct ceph_osd_req_op *ops;
1128 u32 payload_len; 1148 u32 payload_len;
1129 1149
1130 seg_name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO); 1150 seg_name = rbd_segment_name(rbd_dev, ofs);
1131 if (!seg_name) 1151 if (!seg_name)
1132 return -ENOMEM; 1152 return -ENOMEM;
1133 1153 seg_len = rbd_segment_length(rbd_dev, ofs, len);
1134 seg_len = rbd_get_segment(&rbd_dev->header, 1154 seg_ofs = rbd_segment_offset(rbd_dev, ofs);
1135 rbd_dev->header.object_prefix,
1136 ofs, len,
1137 seg_name, &seg_ofs);
1138 1155
1139 payload_len = (flags & CEPH_OSD_FLAG_WRITE ? seg_len : 0); 1156 payload_len = (flags & CEPH_OSD_FLAG_WRITE ? seg_len : 0);
1140 1157
@@ -1545,10 +1562,7 @@ static void rbd_rq_fn(struct request_queue *q)
1545 do { 1562 do {
1546 /* a bio clone to be passed down to OSD req */ 1563 /* a bio clone to be passed down to OSD req */
1547 dout("rq->bio->bi_vcnt=%hu\n", rq->bio->bi_vcnt); 1564 dout("rq->bio->bi_vcnt=%hu\n", rq->bio->bi_vcnt);
1548 op_size = rbd_get_segment(&rbd_dev->header, 1565 op_size = rbd_segment_length(rbd_dev, ofs, size);
1549 rbd_dev->header.object_prefix,
1550 ofs, size,
1551 NULL, NULL);
1552 kref_get(&coll->kref); 1566 kref_get(&coll->kref);
1553 bio = bio_chain_clone(&rq_bio, &next_bio, &bp, 1567 bio = bio_chain_clone(&rq_bio, &next_bio, &bp,
1554 op_size, GFP_ATOMIC); 1568 op_size, GFP_ATOMIC);