On 05/18/2012 05:59 AM, koverstreet@xxxxxxxxxx wrote: > From: Kent Overstreet <koverstreet@xxxxxxxxxx> > > Break out bio_split() and bio_pair_split(), and get rid of the > limitations of bio_split() > > Signed-off-by: Kent Overstreet <koverstreet@xxxxxxxxxx> > --- > drivers/block/drbd/drbd_req.c | 18 +---- > drivers/block/pktcdvd.c | 6 +- > drivers/block/rbd.c | 4 +- > drivers/md/linear.c | 6 +- > drivers/md/raid0.c | 8 +- > drivers/md/raid10.c | 23 ++----- > fs/bio-integrity.c | 44 ------------ > fs/bio.c | 149 ++++++++++++++++++++++++++--------------- > include/linux/bio.h | 27 +++----- > 9 files changed, 125 insertions(+), 160 deletions(-) > > diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c > index 4a0f314..68fa494 100644 > --- a/drivers/block/drbd/drbd_req.c > +++ b/drivers/block/drbd/drbd_req.c > @@ -1101,18 +1101,6 @@ void drbd_make_request(struct request_queue *q, struct bio *bio) > if (likely(s_enr == e_enr)) { > inc_ap_bio(mdev, 1); > drbd_make_request_common(mdev, bio, start_time); > - return; > - } > - > - /* can this bio be split generically? > - * Maybe add our own split-arbitrary-bios function. */ > - if (bio->bi_vcnt != 1 || bio->bi_idx != 0 || bio->bi_size > DRBD_MAX_BIO_SIZE) { > - /* rather error out here than BUG in bio_split */ > - dev_err(DEV, "bio would need to, but cannot, be split: " > - "(vcnt=%u,idx=%u,size=%u,sector=%llu)\n", > - bio->bi_vcnt, bio->bi_idx, bio->bi_size, > - (unsigned long long)bio->bi_sector); > - bio_endio(bio, -EINVAL); > } else { > /* This bio crosses some boundary, so we have to split it. */ > struct bio_pair *bp; > @@ -1128,7 +1116,7 @@ void drbd_make_request(struct request_queue *q, struct bio *bio) > const int sps = 1 << HT_SHIFT; /* sectors per slot */ > const int mask = sps - 1; > const sector_t first_sectors = sps - (sect & mask); > - bp = bio_split(bio, first_sectors); > + bp = bio_pair_split(bio, first_sectors); I do not see the point of this rename. See below > > /* we need to get a "reference count" (ap_bio_cnt) > * to avoid races with the disconnect/reconnect/suspend code. > @@ -1139,10 +1127,10 @@ void drbd_make_request(struct request_queue *q, struct bio *bio) > > D_ASSERT(e_enr == s_enr + 1); > > - while (drbd_make_request_common(mdev, &bp->bio1, start_time)) > + while (drbd_make_request_common(mdev, &bp->split, start_time)) > inc_ap_bio(mdev, 1); > > - while (drbd_make_request_common(mdev, &bp->bio2, start_time)) > + while (drbd_make_request_common(mdev, bio, start_time)) > inc_ap_bio(mdev, 1); > > dec_ap_bio(mdev); > diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c > index 6fe693a..1465155 100644 > --- a/drivers/block/pktcdvd.c > +++ b/drivers/block/pktcdvd.c > @@ -2467,10 +2467,10 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) > if (last_zone != zone) { > BUG_ON(last_zone != zone + pd->settings.size); > first_sectors = last_zone - bio->bi_sector; > - bp = bio_split(bio, first_sectors); > + bp = bio_pair_split(bio, first_sectors); just a rename. See below > BUG_ON(!bp); > - pkt_make_request(q, &bp->bio1); > - pkt_make_request(q, &bp->bio2); > + pkt_make_request(q, &bp->split); > + pkt_make_request(q, bio); > bio_pair_release(bp); > return; > } > diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c > index 5a953c6..dd19311 100644 > --- a/drivers/block/rbd.c > +++ b/drivers/block/rbd.c > @@ -747,11 +747,11 @@ static struct bio *bio_chain_clone(struct bio **old, struct bio **next, > > /* split the bio. We'll release it either in the next > call, or it will have to be released outside */ > - bp = bio_split(old_chain, (len - total) / SECTOR_SIZE); > + bp = bio_pair_split(old_chain, (len - total) / SECTOR_SIZE); just a rename. See below > if (!bp) > goto err_out; > > - *next = &bp->bio2; > + *next = &bp->split; > } else > *next = old_chain->bi_next; > > diff --git a/drivers/md/linear.c b/drivers/md/linear.c > index fa211d8..7c6cafd 100644 > --- a/drivers/md/linear.c > +++ b/drivers/md/linear.c > @@ -314,10 +314,10 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio) > > rcu_read_unlock(); > > - bp = bio_split(bio, end_sector - bio->bi_sector); > + bp = bio_pair_split(bio, end_sector - bio->bi_sector); > just a rename. See below > - linear_make_request(mddev, &bp->bio1); > - linear_make_request(mddev, &bp->bio2); > + linear_make_request(mddev, &bp->split); > + linear_make_request(mddev, bio); > bio_pair_release(bp); > return; > } > diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c > index de63a1f..3469adf 100644 > --- a/drivers/md/raid0.c > +++ b/drivers/md/raid0.c > @@ -516,13 +516,13 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio) > * refuse to split for us, so we need to split it. > */ > if (likely(is_power_of_2(chunk_sects))) > - bp = bio_split(bio, chunk_sects - (sector & > + bp = bio_pair_split(bio, chunk_sects - (sector & > (chunk_sects-1))); > else > - bp = bio_split(bio, chunk_sects - > + bp = bio_pair_split(bio, chunk_sects - > sector_div(sector, chunk_sects)); just a rename. See below > - raid0_make_request(mddev, &bp->bio1); > - raid0_make_request(mddev, &bp->bio2); > + raid0_make_request(mddev, &bp->split); > + raid0_make_request(mddev, bio); > bio_pair_release(bp); > return; > } > diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c > index 3e7b154..0062326 100644 > --- a/drivers/md/raid10.c > +++ b/drivers/md/raid10.c > @@ -1001,15 +1001,9 @@ static void make_request(struct mddev *mddev, struct bio * bio) > > chunk_sects && > conf->near_copies < conf->raid_disks)) { > struct bio_pair *bp; > - /* Sanity check -- queue functions should prevent this happening */ > - if (bio->bi_vcnt != 1 || > - bio->bi_idx != 0) > - goto bad_map; > - /* This is a one page bio that upper layers > - * refuse to split for us, so we need to split it. > - */ > - bp = bio_split(bio, > - chunk_sects - (bio->bi_sector & (chunk_sects - 1)) ); > + > + bp = bio_pair_split(bio, > + chunk_sects - (bio->bi_sector & (chunk_sects - 1))); just a rename. See below > > /* Each of these 'make_request' calls will call 'wait_barrier'. > * If the first succeeds but the second blocks due to the resync > @@ -1023,8 +1017,8 @@ static void make_request(struct mddev *mddev, struct bio * bio) > conf->nr_waiting++; > spin_unlock_irq(&conf->resync_lock); > > - make_request(mddev, &bp->bio1); > - make_request(mddev, &bp->bio2); > + make_request(mddev, &bp->split); > + make_request(mddev, bio); > > spin_lock_irq(&conf->resync_lock); > conf->nr_waiting--; > @@ -1033,13 +1027,6 @@ static void make_request(struct mddev *mddev, struct bio * bio) > > bio_pair_release(bp); > return; > - bad_map: > - printk("md/raid10:%s: make_request bug: can't convert block across chunks" > - " or bigger than %dk %llu %d\n", mdname(mddev), chunk_sects/2, > - (unsigned long long)bio->bi_sector, bio->bi_size >> 10); > - > - bio_io_error(bio); > - return; > } > > md_write_start(mddev, bio); > diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c > index e85c04b..9ed2c44 100644 > --- a/fs/bio-integrity.c > +++ b/fs/bio-integrity.c > @@ -682,50 +682,6 @@ void bio_integrity_trim(struct bio *bio, unsigned int offset, > EXPORT_SYMBOL(bio_integrity_trim); > > /** > - * bio_integrity_split - Split integrity metadata > - * @bio: Protected bio > - * @bp: Resulting bio_pair > - * @sectors: Offset > - * > - * Description: Splits an integrity page into a bio_pair. > - */ > -void bio_integrity_split(struct bio *bio, struct bio_pair *bp, int sectors) > -{ > - struct blk_integrity *bi; > - struct bio_integrity_payload *bip = bio->bi_integrity; > - unsigned int nr_sectors; > - > - if (bio_integrity(bio) == 0) > - return; > - > - bi = bdev_get_integrity(bio->bi_bdev); > - BUG_ON(bi == NULL); > - BUG_ON(bip->bip_vcnt != 1); > - > - nr_sectors = bio_integrity_hw_sectors(bi, sectors); > - > - bp->bio1.bi_integrity = &bp->bip1; > - bp->bio2.bi_integrity = &bp->bip2; > - > - bp->iv1 = bip->bip_vec[0]; > - bp->iv2 = bip->bip_vec[0]; > - > - bp->bip1.bip_vec[0] = bp->iv1; > - bp->bip2.bip_vec[0] = bp->iv2; > - > - bp->iv1.bv_len = sectors * bi->tuple_size; > - bp->iv2.bv_offset += sectors * bi->tuple_size; > - bp->iv2.bv_len -= sectors * bi->tuple_size; > - > - bp->bip1.bip_sector = bio->bi_integrity->bip_sector; > - bp->bip2.bip_sector = bio->bi_integrity->bip_sector + nr_sectors; > - > - bp->bip1.bip_vcnt = bp->bip2.bip_vcnt = 1; > - bp->bip1.bip_idx = bp->bip2.bip_idx = 0; > -} > -EXPORT_SYMBOL(bio_integrity_split); > - > -/** > * bio_integrity_clone - Callback for cloning bios with integrity metadata > * @bio: New bio > * @bio_src: Original bio > diff --git a/fs/bio.c b/fs/bio.c > index 3332800..781a8cf 100644 > --- a/fs/bio.c > +++ b/fs/bio.c > @@ -35,7 +35,7 @@ > */ > #define BIO_INLINE_VECS 4 > > -static mempool_t *bio_split_pool __read_mostly; > +static struct bio_set *bio_split_pool __read_mostly; > > /* > * if you change this list, also change bvec_alloc or things will > @@ -1464,84 +1464,124 @@ void bio_endio(struct bio *bio, int error) > } > EXPORT_SYMBOL(bio_endio); > > -void bio_pair_release(struct bio_pair *bp) bio_pair_release() was just moved to down there. Which makes a complete messy patch, unless I patch it on real code Its hard to see what's written. For review sake if I *must* move+change code, I split it up by doing the pure move in a separate patch, or sometime commenting the old code and remove it in a next patch. But here I don't see the point of why you switched them? > +struct bio *bio_split(struct bio *bio, int sectors, > + gfp_t gfp, struct bio_set *bs) > { > - if (atomic_dec_and_test(&bp->cnt)) { > - struct bio *master = bp->bio1.bi_private; > + unsigned idx, vcnt = 0, nbytes = sectors << 9; > + struct bio_vec *bv; > + struct bio *ret = NULL; > + > + BUG_ON(sectors <= 0); > + > + if (current->bio_list) > + gfp &= ~__GFP_WAIT; > + > + if (nbytes >= bio->bi_size) > + return bio; > + > + trace_block_split(bdev_get_queue(bio->bi_bdev), bio, > + bio->bi_sector + sectors); > + > + bio_for_each_segment(bv, bio, idx) { > + vcnt = idx - bio->bi_idx; > + > + if (!nbytes) { > + ret = bio_alloc_bioset(gfp, 0, bs); > + if (!ret) > + return NULL; > + > + ret->bi_io_vec = bio_iovec(bio); > + ret->bi_flags |= 1 << BIO_CLONED; > + break; > + } else if (nbytes < bv->bv_len) { > + ret = bio_alloc_bioset(gfp, ++vcnt, bs); > + if (!ret) > + return NULL; > + > + memcpy(ret->bi_io_vec, bio_iovec(bio), > + sizeof(struct bio_vec) * vcnt); > + > + ret->bi_io_vec[vcnt - 1].bv_len = nbytes; > + bv->bv_offset += nbytes; > + bv->bv_len -= nbytes; > + break; > + } > + > + nbytes -= bv->bv_len; > + } > + > + ret->bi_bdev = bio->bi_bdev; > + ret->bi_sector = bio->bi_sector; > + ret->bi_size = sectors << 9; > + ret->bi_rw = bio->bi_rw; > + ret->bi_vcnt = vcnt; > + ret->bi_max_vecs = vcnt; > + ret->bi_end_io = bio->bi_end_io; > + ret->bi_private = bio->bi_private; > > - bio_endio(master, bp->error); > - mempool_free(bp, bp->bio2.bi_private); > + bio->bi_sector += sectors; > + bio->bi_size -= sectors << 9; > + bio->bi_idx = idx; > + > + if (bio_integrity(bio)) { > + bio_integrity_clone(ret, bio, gfp, bs); > + bio_integrity_trim(ret, 0, bio_sectors(ret)); > + bio_integrity_trim(bio, bio_sectors(ret), bio_sectors(bio)); > } > + > + return ret; > } > -EXPORT_SYMBOL(bio_pair_release); > +EXPORT_SYMBOL_GPL(bio_split); > > -static void bio_pair_end_1(struct bio *bi, int err) > +void bio_pair_release(struct bio_pair *bp) > { > - struct bio_pair *bp = container_of(bi, struct bio_pair, bio1); > - > - if (err) > - bp->error = err; > + if (atomic_dec_and_test(&bp->cnt)) { > + bp->orig->bi_end_io = bp->bi_end_io; > + bp->orig->bi_private = bp->bi_private; > > - bio_pair_release(bp); > + bio_endio(bp->orig, 0); > + bio_put(&bp->split); > + } > } > +EXPORT_SYMBOL(bio_pair_release); > > -static void bio_pair_end_2(struct bio *bi, int err) > +static void bio_pair_end(struct bio *bio, int error) > { > - struct bio_pair *bp = container_of(bi, struct bio_pair, bio2); > + struct bio_pair *bp = bio->bi_private; > > - if (err) > - bp->error = err; > + if (error) > + clear_bit(BIO_UPTODATE, &bp->orig->bi_flags); > > bio_pair_release(bp); > } > > -/* > - * split a bio - only worry about a bio with a single page in its iovec > - */ > -struct bio_pair *bio_split(struct bio *bi, int first_sectors) > +struct bio_pair *bio_pair_split(struct bio *bio, int first_sectors) > { Here too if you would have staged the function order properly that new-split above would better merge with the old-split and the new-old-split that uses the new-split would be a new hunk by itself. I do this not only for reviewers, but also for myself to prove I have not changed something I didn't mean to change. To summarize. I think undoing code movement and better staging of the code could make this patch much cleaner. > - struct bio_pair *bp = mempool_alloc(bio_split_pool, GFP_NOIO); > - > - if (!bp) > - return bp; > + struct bio_pair *bp; > + struct bio *split = bio_split(bio, first_sectors, > + GFP_NOIO, bio_split_pool); > > - trace_block_split(bdev_get_queue(bi->bi_bdev), bi, > - bi->bi_sector + first_sectors); > - > - BUG_ON(bi->bi_vcnt != 1); > - BUG_ON(bi->bi_idx != 0); > - atomic_set(&bp->cnt, 3); > - bp->error = 0; > - bp->bio1 = *bi; > - bp->bio2 = *bi; > - bp->bio2.bi_sector += first_sectors; > - bp->bio2.bi_size -= first_sectors << 9; > - bp->bio1.bi_size = first_sectors << 9; > + if (!split) > + return NULL; > > - bp->bv1 = bi->bi_io_vec[0]; > - bp->bv2 = bi->bi_io_vec[0]; > - bp->bv2.bv_offset += first_sectors << 9; > - bp->bv2.bv_len -= first_sectors << 9; > - bp->bv1.bv_len = first_sectors << 9; > + BUG_ON(split == bio); > > - bp->bio1.bi_io_vec = &bp->bv1; > - bp->bio2.bi_io_vec = &bp->bv2; > + bp = container_of(split, struct bio_pair, split); > > - bp->bio1.bi_max_vecs = 1; > - bp->bio2.bi_max_vecs = 1; > + atomic_set(&bp->cnt, 3); > > - bp->bio1.bi_end_io = bio_pair_end_1; > - bp->bio2.bi_end_io = bio_pair_end_2; > + bp->bi_end_io = bio->bi_end_io; > + bp->bi_private = bio->bi_private; > > - bp->bio1.bi_private = bi; > - bp->bio2.bi_private = bio_split_pool; > + bio->bi_private = bp; > + bio->bi_end_io = bio_pair_end; > > - if (bio_integrity(bi)) > - bio_integrity_split(bi, bp, first_sectors); > + split->bi_private = bp; > + split->bi_end_io = bio_pair_end; > > return bp; > } > -EXPORT_SYMBOL(bio_split); > +EXPORT_SYMBOL(bio_pair_split); > > /** > * bio_sector_offset - Find hardware sector offset in bio > @@ -1694,8 +1734,7 @@ static int __init init_bio(void) > if (bioset_integrity_create(fs_bio_set, BIO_POOL_SIZE)) > panic("bio: can't create integrity pool\n"); > > - bio_split_pool = mempool_create_kmalloc_pool(BIO_SPLIT_ENTRIES, > - sizeof(struct bio_pair)); > + bio_split_pool = bioset_create(BIO_POOL_SIZE, offsetof(struct bio_pair, split)); > if (!bio_split_pool) > panic("bio: can't create split pool\n"); > > diff --git a/include/linux/bio.h b/include/linux/bio.h > index 35f7c4d..db38175 100644 > --- a/include/linux/bio.h > +++ b/include/linux/bio.h > @@ -197,16 +197,18 @@ struct bio_integrity_payload { > * in bio2.bi_private > */ > struct bio_pair { > - struct bio bio1, bio2; > - struct bio_vec bv1, bv2; > -#if defined(CONFIG_BLK_DEV_INTEGRITY) > - struct bio_integrity_payload bip1, bip2; > - struct bio_vec iv1, iv2; > -#endif > - atomic_t cnt; > - int error; > + atomic_t cnt; > + > + bio_end_io_t *bi_end_io; > + void *bi_private; > + > + struct bio *orig; > + struct bio split; > }; > -extern struct bio_pair *bio_split(struct bio *bi, int first_sectors); > + > +extern struct bio *bio_split(struct bio *bio, int sectors, > + gfp_t gfp, struct bio_set *bs); > +extern struct bio_pair *bio_pair_split(struct bio *bi, int first_sectors); I do not get this. Please explain. We have two different topics here. 1. Introduction of a new/better split function. 2. Rename of an old one. Now if you must, making the rename a patch of it's own is preferred. But why must you? can't you think of a creative name for the new one? Though I admit your names do make sense. The first belongs to the bio domain bio_DO, and the second belongs to the bio_pair domain bio_pair_DO Hey this patch and the rest are amazing. It gives one the incentive to do some more complicating things, just because it is easier now. Thanks! Boaz > extern void bio_pair_release(struct bio_pair *dbio); > > extern struct bio_set *bioset_create(unsigned int, unsigned int); > @@ -511,7 +513,6 @@ extern int bio_integrity_prep(struct bio *); > extern void bio_integrity_endio(struct bio *, int); > extern void bio_integrity_advance(struct bio *, unsigned int); > extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int); > -extern void bio_integrity_split(struct bio *, struct bio_pair *, int); > extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t, struct bio_set *); > extern int bioset_integrity_create(struct bio_set *, int); > extern void bioset_integrity_free(struct bio_set *); > @@ -555,12 +556,6 @@ static inline int bio_integrity_clone(struct bio *bio, struct bio *bio_src, > return 0; > } > > -static inline void bio_integrity_split(struct bio *bio, struct bio_pair *bp, > - int sectors) > -{ > - return; > -} > - > static inline void bio_integrity_advance(struct bio *bio, > unsigned int bytes_done) > { -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html