Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1034261AbcJ2IOu (ORCPT ); Sat, 29 Oct 2016 04:14:50 -0400 Received: from mail-pf0-f195.google.com ([209.85.192.195]:35150 "EHLO mail-pf0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1033989AbcJ2IOi (ORCPT ); Sat, 29 Oct 2016 04:14:38 -0400 From: Ming Lei To: Jens Axboe , linux-kernel@vger.kernel.org Cc: linux-block@vger.kernel.org, linux-fsdevel@vger.kernel.org, Christoph Hellwig , "Kirill A . Shutemov" , Ming Lei , Jens Axboe , Mike Christie , Hannes Reinecke , Keith Busch , Mike Snitzer Subject: [PATCH 34/60] block: introduce bio_clone_sp() Date: Sat, 29 Oct 2016 16:08:33 +0800 Message-Id: <1477728600-12938-35-git-send-email-tom.leiming@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1477728600-12938-1-git-send-email-tom.leiming@gmail.com> References: <1477728600-12938-1-git-send-email-tom.leiming@gmail.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5116 Lines: 164 Firstly bio_clone() and bio_clone_bioset() are changed to clone mp bvecs because our iterator helpers are capable of splitting mp bvecs into sp bvecs. But sometimes we still need cloned bio with singlepage bvecs, for example, in bio bounce/bcache(bch_data_verify), bvecs of cloned bio need to be updated. Signed-off-by: Ming Lei --- block/bio.c | 27 +++++++++++++++++++++------ include/linux/bio.h | 42 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/block/bio.c b/block/bio.c index a49d1d89a85c..a9bf01784f37 100644 --- a/block/bio.c +++ b/block/bio.c @@ -626,16 +626,22 @@ EXPORT_SYMBOL(bio_clone_fast); * @bio_src: bio to clone * @gfp_mask: allocation priority * @bs: bio_set to allocate from + * @sp_bvecs: if clone to singlepage bvecs. * * Clone bio. Caller will own the returned bio, but not the actual data it * points to. Reference count of returned bio will be one. + * + * If @sp_bvecs is true, the caller must make sure number of singlepage + * bvecs is less than maximum bvec count. + * */ -struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask, - struct bio_set *bs) +struct bio *__bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask, + struct bio_set *bs, bool sp_bvecs) { struct bvec_iter iter; struct bio_vec bv; struct bio *bio; + unsigned segs; /* * Pre immutable biovecs, __bio_clone() used to just do a memcpy from @@ -659,7 +665,12 @@ struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask, * __bio_clone_fast() anyways. */ - bio = bio_alloc_bioset(gfp_mask, bio_segments(bio_src), bs); + if (sp_bvecs) + segs = bio_segments(bio_src); + else + segs = bio_segments_mp(bio_src); + + bio = bio_alloc_bioset(gfp_mask, segs, bs); if (!bio) return NULL; bio->bi_bdev = bio_src->bi_bdev; @@ -675,8 +686,12 @@ struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask, bio->bi_io_vec[bio->bi_vcnt++] = bio_src->bi_io_vec[0]; break; default: - bio_for_each_segment(bv, bio_src, iter) - bio->bi_io_vec[bio->bi_vcnt++] = bv; + if (sp_bvecs) + bio_for_each_segment(bv, bio_src, iter) + bio->bi_io_vec[bio->bi_vcnt++] = bv; + else + bio_for_each_segment_mp(bv, bio_src, iter) + bio->bi_io_vec[bio->bi_vcnt++] = bv; break; } @@ -694,7 +709,7 @@ struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask, return bio; } -EXPORT_SYMBOL(bio_clone_bioset); +EXPORT_SYMBOL(__bio_clone_bioset); /** * bio_add_pc_page - attempt to add page to bio diff --git a/include/linux/bio.h b/include/linux/bio.h index 17852ba0e40f..ec1c0f2aaa19 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -217,7 +217,7 @@ static inline void bio_advance_iter_mp(struct bio *bio, struct bvec_iter *iter, #define bio_iter_last(bvec, iter) ((iter).bi_size == (bvec).bv_len) -static inline unsigned bio_segments(struct bio *bio) +static inline unsigned __bio_segments(struct bio *bio, bool mp) { unsigned segs = 0; struct bio_vec bv; @@ -237,12 +237,26 @@ static inline unsigned bio_segments(struct bio *bio) if (bio_op(bio) == REQ_OP_WRITE_SAME) return 1; - bio_for_each_segment(bv, bio, iter) - segs++; + if (!mp) + bio_for_each_segment(bv, bio, iter) + segs++; + else + bio_for_each_segment_mp(bv, bio, iter) + segs++; return segs; } +static inline unsigned bio_segments(struct bio *bio) +{ + return __bio_segments(bio, false); +} + +static inline unsigned bio_segments_mp(struct bio *bio) +{ + return __bio_segments(bio, true); +} + /* * get a reference to a bio, so it won't disappear. the intended use is * something like: @@ -415,10 +429,24 @@ extern void bio_put(struct bio *); extern void __bio_clone_fast(struct bio *, struct bio *); extern struct bio *bio_clone_fast(struct bio *, gfp_t, struct bio_set *); -extern struct bio *bio_clone_bioset(struct bio *, gfp_t, struct bio_set *bs); +extern struct bio *__bio_clone_bioset(struct bio *, gfp_t, + struct bio_set *bs, bool); extern struct bio_set *fs_bio_set; +/* at default we clone bio with multipage bvecs */ +static inline struct bio *bio_clone_bioset(struct bio *bio, gfp_t gfp, + struct bio_set *bs) +{ + return __bio_clone_bioset(bio, gfp, bs, false); +} + +static inline struct bio *bio_clone_bioset_sp(struct bio *bio, gfp_t gfp, + struct bio_set *bs) +{ + return __bio_clone_bioset(bio, gfp, bs, true); +} + static inline struct bio *bio_alloc(gfp_t gfp_mask, unsigned int nr_iovecs) { return bio_alloc_bioset(gfp_mask, nr_iovecs, fs_bio_set); @@ -429,6 +457,12 @@ static inline struct bio *bio_clone(struct bio *bio, gfp_t gfp_mask) return bio_clone_bioset(bio, gfp_mask, fs_bio_set); } +/* Sometimes we have to clone one bio with singlepage bvec */ +static inline struct bio *bio_clone_sp(struct bio *bio, gfp_t gfp_mask) +{ + return __bio_clone_bioset(bio, gfp_mask, fs_bio_set, true); +} + static inline struct bio *bio_kmalloc(gfp_t gfp_mask, unsigned int nr_iovecs) { return bio_alloc_bioset(gfp_mask, nr_iovecs, NULL); -- 2.7.4