Release 4.12 block/blk-merge.c
/*
* Functions related to segment and merge handling
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/scatterlist.h>
#include <trace/events/block.h>
#include "blk.h"
static struct bio *blk_bio_discard_split(struct request_queue *q,
struct bio *bio,
struct bio_set *bs,
unsigned *nsegs)
{
unsigned int max_discard_sectors, granularity;
int alignment;
sector_t tmp;
unsigned split_sectors;
*nsegs = 1;
/* Zero-sector (unknown) and one-sector granularities are the same. */
granularity = max(q->limits.discard_granularity >> 9, 1U);
max_discard_sectors = min(q->limits.max_discard_sectors, UINT_MAX >> 9);
max_discard_sectors -= max_discard_sectors % granularity;
if (unlikely(!max_discard_sectors)) {
/* XXX: warn */
return NULL;
}
if (bio_sectors(bio) <= max_discard_sectors)
return NULL;
split_sectors = max_discard_sectors;
/*
* If the next starting sector would be misaligned, stop the discard at
* the previous aligned sector.
*/
alignment = (q->limits.discard_alignment >> 9) % granularity;
tmp = bio->bi_iter.bi_sector + split_sectors - alignment;
tmp = sector_div(tmp, granularity);
if (split_sectors > tmp)
split_sectors -= tmp;
return bio_split(bio, split_sectors, GFP_NOIO, bs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Kent Overstreet | 163 | 94.77% | 1 | 50.00% |
Ming Lei | 9 | 5.23% | 1 | 50.00% |
Total | 172 | 100.00% | 2 | 100.00% |
static struct bio *blk_bio_write_zeroes_split(struct request_queue *q,
struct bio *bio, struct bio_set *bs, unsigned *nsegs)
{
*nsegs = 1;
if (!q->limits.max_write_zeroes_sectors)
return NULL;
if (bio_sectors(bio) <= q->limits.max_write_zeroes_sectors)
return NULL;
return bio_split(bio, q->limits.max_write_zeroes_sectors, GFP_NOIO, bs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Christoph Hellwig | 76 | 100.00% | 1 | 100.00% |
Total | 76 | 100.00% | 1 | 100.00% |
static struct bio *blk_bio_write_same_split(struct request_queue *q,
struct bio *bio,
struct bio_set *bs,
unsigned *nsegs)
{
*nsegs = 1;
if (!q->limits.max_write_same_sectors)
return NULL;
if (bio_sectors(bio) <= q->limits.max_write_same_sectors)
return NULL;
return bio_split(bio, q->limits.max_write_same_sectors, GFP_NOIO, bs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Kent Overstreet | 67 | 88.16% | 1 | 50.00% |
Ming Lei | 9 | 11.84% | 1 | 50.00% |
Total | 76 | 100.00% | 2 | 100.00% |
static inline unsigned get_max_io_size(struct request_queue *q,
struct bio *bio)
{
unsigned sectors = blk_max_size_offset(q, bio->bi_iter.bi_sector);
unsigned mask = queue_logical_block_size(q) - 1;
/* aligned to logical block size */
sectors &= ~(mask >> 9);
return sectors;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Lei Ming | 54 | 100.00% | 1 | 100.00% |
Total | 54 | 100.00% | 1 | 100.00% |
static struct bio *blk_bio_segment_split(struct request_queue *q,
struct bio *bio,
struct bio_set *bs,
unsigned *segs)
{
struct bio_vec bv, bvprv, *bvprvp = NULL;
struct bvec_iter iter;
unsigned seg_size = 0, nsegs = 0, sectors = 0;
unsigned front_seg_size = bio->bi_seg_front_size;
bool do_split = true;
struct bio *new = NULL;
const unsigned max_sectors = get_max_io_size(q, bio);
unsigned bvecs = 0;
bio_for_each_segment(bv, bio, iter) {
/*
* With arbitrary bio size, the incoming bio may be very
* big. We have to split the bio into small bios so that
* each holds at most BIO_MAX_PAGES bvecs because
* bio_clone() can fail to allocate big bvecs.
*
* It should have been better to apply the limit per
* request queue in which bio_clone() is involved,
* instead of globally. The biggest blocker is the
* bio_clone() in bio bounce.
*
* If bio is splitted by this reason, we should have
* allowed to continue bios merging, but don't do
* that now for making the change simple.
*
* TODO: deal with bio bounce's bio_clone() gracefully
* and convert the global limit into per-queue limit.
*/
if (bvecs++ >= BIO_MAX_PAGES)
goto split;
/*
* If the queue doesn't support SG gaps and adding this
* offset would create a gap, disallow it.
*/
if (bvprvp && bvec_gap_to_prev(q, bvprvp, bv.bv_offset))
goto split;
if (sectors + (bv.bv_len >> 9) > max_sectors) {
/*
* Consider this a new segment if we're splitting in
* the middle of this vector.
*/
if (nsegs < queue_max_segments(q) &&
sectors < max_sectors) {
nsegs++;
sectors = max_sectors;
}
if (sectors)
goto split;
/* Make this single bvec as the 1st segment */
}
if (bvprvp && blk_queue_cluster(q)) {
if (seg_size + bv.bv_len > queue_max_segment_size(q))
goto new_segment;
if (!BIOVEC_PHYS_MERGEABLE(bvprvp, &bv))
goto new_segment;
if (!BIOVEC_SEG_BOUNDARY(q, bvprvp, &bv))
goto new_segment;
seg_size += bv.bv_len;
bvprv = bv;
bvprvp = &bvprv;
sectors += bv.bv_len >> 9;
if (nsegs == 1 && seg_size > front_seg_size)
front_seg_size = seg_size;
continue;
}
new_segment:
if (nsegs == queue_max_segments(q))
goto split;
nsegs++;
bvprv = bv;
bvprvp = &bvprv;
seg_size = bv.bv_len;
sectors += bv.bv_len >> 9;
if (nsegs == 1 && seg_size > front_seg_size)
front_seg_size = seg_size;
}
do_split = false;
split:
*segs = nsegs;
if (do_split) {
new = bio_split(bio, sectors, GFP_NOIO, bs);
if (new)
bio = new;
}
bio->bi_seg_front_size = front_seg_size;
if (seg_size > bio->bi_seg_back_size)
bio->bi_seg_back_size = seg_size;
return do_split ? new : NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Kent Overstreet | 177 | 45.27% | 2 | 18.18% |
Ming Lei | 145 | 37.08% | 6 | 54.55% |
Keith Busch | 38 | 9.72% | 1 | 9.09% |
Lei Ming | 19 | 4.86% | 1 | 9.09% |
Jens Axboe | 12 | 3.07% | 1 | 9.09% |
Total | 391 | 100.00% | 11 | 100.00% |
void blk_queue_split(struct request_queue *q, struct bio **bio,
struct bio_set *bs)
{
struct bio *split, *res;
unsigned nsegs;
switch (bio_op(*bio)) {
case REQ_OP_DISCARD:
case REQ_OP_SECURE_ERASE:
split = blk_bio_discard_split(q, *bio, bs, &nsegs);
break;
case REQ_OP_WRITE_ZEROES:
split = blk_bio_write_zeroes_split(q, *bio, bs, &nsegs);
break;
case REQ_OP_WRITE_SAME:
split = blk_bio_write_same_split(q, *bio, bs, &nsegs);
break;
default:
split = blk_bio_segment_split(q, *bio, q->bio_split, &nsegs);
break;
}
/* physical segments can be figured out during splitting */
res = split ? split : *bio;
res->bi_phys_segments = nsegs;
bio_set_flag(res, BIO_SEG_VALID);
if (split) {
/* there isn't chance to merge the splitted bio */
split->bi_opf |= REQ_NOMERGE;
bio_chain(split, *bio);
trace_block_split(q, split, (*bio)->bi_iter.bi_sector);
generic_make_request(*bio);
*bio = split;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Kent Overstreet | 93 | 48.44% | 1 | 11.11% |
Ming Lei | 44 | 22.92% | 2 | 22.22% |
Mike Krinkin | 16 | 8.33% | 1 | 11.11% |
Adrian Hunter | 15 | 7.81% | 1 | 11.11% |
Christoph Hellwig | 10 | 5.21% | 1 | 11.11% |
Chaitanya Kulkarni | 9 | 4.69% | 1 | 11.11% |
Michael Christie | 4 | 2.08% | 1 | 11.11% |
Jens Axboe | 1 | 0.52% | 1 | 11.11% |
Total | 192 | 100.00% | 9 | 100.00% |
EXPORT_SYMBOL(blk_queue_split);
static unsigned int __blk_recalc_rq_segments(struct request_queue *q,
struct bio *bio,
bool no_sg_merge)
{
struct bio_vec bv, bvprv = { NULL };
int cluster, prev = 0;
unsigned int seg_size, nr_phys_segs;
struct bio *fbio, *bbio;
struct bvec_iter iter;
if (!bio)
return 0;
switch (bio_op(bio)) {
case REQ_OP_DISCARD:
case REQ_OP_SECURE_ERASE:
case REQ_OP_WRITE_ZEROES:
return 0;
case REQ_OP_WRITE_SAME:
return 1;
}
fbio = bio;
cluster = blk_queue_cluster(q);
seg_size = 0;
nr_phys_segs = 0;
for_each_bio(bio) {
bio_for_each_segment(bv, bio, iter) {
/*
* If SG merging is disabled, each bio vector is
* a segment
*/
if (no_sg_merge)
goto new_segment;
if (prev && cluster) {
if (seg_size + bv.bv_len
> queue_max_segment_size(q))
goto new_segment;
if (!BIOVEC_PHYS_MERGEABLE(&bvprv, &bv))
goto new_segment;
if (!BIOVEC_SEG_BOUNDARY(q, &bvprv, &bv))
goto new_segment;
seg_size += bv.bv_len;
bvprv = bv;
continue;
}
new_segment:
if (nr_phys_segs == 1 && seg_size >
fbio->bi_seg_front_size)
fbio->bi_seg_front_size = seg_size;
nr_phys_segs++;
bvprv = bv;
prev = 1;
seg_size = bv.bv_len;
}
bbio = bio;
}
if (nr_phys_segs == 1 && seg_size > fbio->bi_seg_front_size)
fbio->bi_seg_front_size = seg_size;
if (seg_size > bbio->bi_seg_back_size)
bbio->bi_seg_back_size = seg_size;
return nr_phys_segs;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jens Axboe | 199 | 72.10% | 4 | 25.00% |
Kent Overstreet | 27 | 9.78% | 3 | 18.75% |
FUJITA Tomonori | 19 | 6.88% | 1 | 6.25% |
Chaitanya Kulkarni | 12 | 4.35% | 1 | 6.25% |
Christoph Hellwig | 5 | 1.81% | 1 | 6.25% |
Michael Christie | 4 | 1.45% | 1 | 6.25% |
Martin K. Petersen | 4 | 1.45% | 2 | 12.50% |
Ming Lei | 3 | 1.09% | 1 | 6.25% |
Nicholas Piggin | 2 | 0.72% | 1 | 6.25% |
Adrian Hunter | 1 | 0.36% | 1 | 6.25% |
Total | 276 | 100.00% | 16 | 100.00% |
void blk_recalc_rq_segments(struct request *rq)
{
bool no_sg_merge = !!test_bit(QUEUE_FLAG_NO_SG_MERGE,
&rq->q->queue_flags);
rq->nr_phys_segments = __blk_recalc_rq_segments(rq->q, rq->bio,
no_sg_merge);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jens Axboe | 25 | 56.82% | 3 | 75.00% |
Ming Lei | 19 | 43.18% | 1 | 25.00% |
Total | 44 | 100.00% | 4 | 100.00% |
void blk_recount_segments(struct request_queue *q, struct bio *bio)
{
unsigned short seg_cnt;
/* estimate segment number by bi_vcnt for non-cloned bio */
if (bio_flagged(bio, BIO_CLONED))
seg_cnt = bio_segments(bio);
else
seg_cnt = bio->bi_vcnt;
if (test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags) &&
(seg_cnt < queue_max_segments(q)))
bio->bi_phys_segments = seg_cnt;
else {
struct bio *nxt = bio->bi_next;
bio->bi_next = NULL;
bio->bi_phys_segments = __blk_recalc_rq_segments(q, bio, false);
bio->bi_next = nxt;
}
bio_set_flag(bio, BIO_SEG_VALID);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jens Axboe | 72 | 63.16% | 4 | 57.14% |
Lei Ming | 41 | 35.96% | 2 | 28.57% |
Ming Lei | 1 | 0.88% | 1 | 14.29% |
Total | 114 | 100.00% | 7 | 100.00% |
EXPORT_SYMBOL(blk_recount_segments);
static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
struct bio *nxt)
{
struct bio_vec end_bv = { NULL }, nxt_bv;
if (!blk_queue_cluster(q))
return 0;
if (bio->bi_seg_back_size + nxt->bi_seg_front_size >
queue_max_segment_size(q))
return 0;
if (!bio_has_data(bio))
return 1;
bio_get_last_bvec(bio, &end_bv);
bio_get_first_bvec(nxt, &nxt_bv);
if (!BIOVEC_PHYS_MERGEABLE(&end_bv, &nxt_bv))
return 0;
/*
* bio and nxt are contiguous in memory; check if the queue allows
* these two to be merged into one
*/
if (BIOVEC_SEG_BOUNDARY(q, &end_bv, &nxt_bv))
return 1;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jens Axboe | 54 | 44.26% | 1 | 11.11% |
Kent Overstreet | 26 | 21.31% | 2 | 22.22% |
David Woodhouse | 25 | 20.49% | 1 | 11.11% |
Ming Lei | 9 | 7.38% | 1 | 11.11% |
Martin K. Petersen | 4 | 3.28% | 2 | 22.22% |
FUJITA Tomonori | 2 | 1.64% | 1 | 11.11% |
Nicholas Piggin | 2 | 1.64% | 1 | 11.11% |
Total | 122 | 100.00% | 9 | 100.00% |
static inline void
__blk_segment_map_sg(struct request_queue *q, struct bio_vec *bvec,
struct scatterlist *sglist, struct bio_vec *bvprv,
struct scatterlist **sg, int *nsegs, int *cluster)
{
int nbytes = bvec->bv_len;
if (*sg && *cluster) {
if ((*sg)->length + nbytes > queue_max_segment_size(q))
goto new_segment;
if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec))
goto new_segment;
if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec))
goto new_segment;
(*sg)->length += nbytes;
} else {
new_segment:
if (!*sg)
*sg = sglist;
else {
/*
* If the driver previously mapped a shorter
* list, we could see a termination bit
* prematurely unless it fully inits the sg
* table on each mapping. We KNOW that there
* must be more entries here or the driver
* would be buggy, so force clear the
* termination bit to avoid doing a full
* sg_init_table() in drivers for each command.
*/
sg_unmark_end(*sg);
*sg = sg_next(*sg);
}
sg_set_page(*sg, bvec->bv_page, nbytes, bvec->bv_offset);
(*nsegs)++;
}
*bvprv = *bvec;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jens Axboe | 135 | 76.27% | 1 | 20.00% |
Asias He | 33 | 18.64% | 1 | 20.00% |
Martin K. Petersen | 3 | 1.69% | 1 | 20.00% |
Kent Overstreet | 3 | 1.69% | 1 | 20.00% |
Paolo Bonzini | 3 | 1.69% | 1 | 20.00% |
Total | 177 | 100.00% | 5 | 100.00% |
static inline int __blk_bvec_map_sg(struct request_queue *q, struct bio_vec bv,
struct scatterlist *sglist, struct scatterlist **sg)
{
*sg = sglist;
sg_set_page(*sg, bv.bv_page, bv.bv_len, bv.bv_offset);
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Christoph Hellwig | 53 | 100.00% | 1 | 100.00% |
Total | 53 | 100.00% | 1 | 100.00% |
static int __blk_bios_map_sg(struct request_queue *q, struct bio *bio,
struct scatterlist *sglist,
struct scatterlist **sg)
{
struct bio_vec bvec, bvprv = { NULL };
struct bvec_iter iter;
int cluster = blk_queue_cluster(q), nsegs = 0;
for_each_bio(bio)
bio_for_each_segment(bvec, bio, iter)
__blk_segment_map_sg(q, &bvec, sglist, &bvprv, sg,
&nsegs, &cluster);
return nsegs;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Asias He | 58 | 65.17% | 1 | 20.00% |
Kent Overstreet | 26 | 29.21% | 3 | 60.00% |
Christoph Hellwig | 5 | 5.62% | 1 | 20.00% |
Total | 89 | 100.00% | 5 | 100.00% |
/*
* map a request to scatterlist, return number of sg entries setup. Caller
* must make sure sg can hold rq->nr_phys_segments entries
*/
int blk_rq_map_sg(struct request_queue *q, struct request *rq,
struct scatterlist *sglist)
{
struct scatterlist *sg = NULL;
int nsegs = 0;
if (rq->rq_flags & RQF_SPECIAL_PAYLOAD)
nsegs = __blk_bvec_map_sg(q, rq->special_vec, sglist, &sg);
else if (rq->bio && bio_op(rq->bio) == REQ_OP_WRITE_SAME)
nsegs = __blk_bvec_map_sg(q, bio_iovec(rq->bio), sglist, &sg);
else if (rq->bio)
nsegs = __blk_bios_map_sg(q, rq->bio, sglist, &sg);
if (unlikely(rq->rq_flags & RQF_COPY_USER) &&
(blk_rq_bytes(rq) & q->dma_pad_mask)) {
unsigned int pad_len =
(q->dma_pad_mask & ~blk_rq_bytes(rq)) + 1;
sg->length += pad_len;
rq->extra_len += pad_len;
}
if (q->dma_drain_size && q->dma_drain_needed(rq)) {
if (op_is_write(req_op(rq)))
memset(q->dma_drain_buffer, 0, q->dma_drain_size);
sg_unmark_end(sg);
sg = sg_next(sg);
sg_set_page(sg, virt_to_page(q->dma_drain_buffer),
q->dma_drain_size,
((unsigned long)q->dma_drain_buffer) &
(PAGE_SIZE - 1));
nsegs++;
rq->extra_len += q->dma_drain_size;
}
if (sg)
sg_mark_end(sg);
/*
* Something must have been wrong if the figured number of
* segment is bigger than number of req's physical segments
*/
WARN_ON(nsegs > blk_rq_nr_phys_segments(rq));
return nsegs;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jens Axboe | 65 | 22.89% | 1 | 7.69% |
Christoph Hellwig | 65 | 22.89% | 2 | 15.38% |
Kent Overstreet | 53 | 18.66% | 1 | 7.69% |
FUJITA Tomonori | 47 | 16.55% | 2 | 15.38% |
Tejun Heo | 37 | 13.03% | 4 | 30.77% |
Ming Lei | 8 | 2.82% | 1 | 7.69% |
Michael Christie | 6 | 2.11% | 1 | 7.69% |
Dan J Williams | 3 | 1.06% | 1 | 7.69% |
Total | 284 | 100.00% | 13 | 100.00% |
EXPORT_SYMBOL(blk_rq_map_sg);
static inline int ll_new_hw_segment(struct request_queue *q,
struct request *req,
struct bio *bio)
{
int nr_phys_segs = bio_phys_segments(q, bio);
if (req->nr_phys_segments + nr_phys_segs > queue_max_segments(q))
goto no_merge;
if (blk_integrity_merge_bio(q, req, bio) == false)
goto no_merge;
/*
* This will form the start of a new hw segment. Bump both
* counters.
*/
req->nr_phys_segments += nr_phys_segs;
return 1;
no_merge:
req_set_nomerge(q, req);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jens Axboe | 45 | 52.33% | 1 | 14.29% |
Martin K. Petersen | 34 | 39.53% | 4 | 57.14% |
Ritesh Harjani | 5 | 5.81% | 1 | 14.29% |
Mikulas Patocka | 2 | 2.33% | 1 | 14.29% |
Total | 86 | 100.00% | 7 | 100.00% |
int ll_back_merge_fn(struct request_queue *q, struct request *req,
struct bio *bio)
{
if (req_gap_back_merge(req, bio))
return 0;
if (blk_integrity_rq(req) &&
integrity_req_gap_back_merge(req, bio))
return 0;
if (blk_rq_sectors(req) + bio_sectors(bio) >
blk_rq_get_max_sectors(req, blk_rq_pos(req))) {
req_set_nomerge(q, req);
return 0;
}
if (!bio_flagged(req->biotail, BIO_SEG_VALID))
blk_recount_segments(q, req->biotail);
if (!bio_flagged(bio, BIO_SEG_VALID))
blk_recount_segments(q, bio);
return ll_new_hw_segment(q, req, bio);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jens Axboe | 97 | 74.05% | 2 | 28.57% |
Sagi Grimberg | 17 | 12.98% | 1 | 14.29% |
Ritesh Harjani | 5 | 3.82% | 1 | 14.29% |
Damien Le Moal | 5 | 3.82% | 1 | 14.29% |
Martin K. Petersen | 4 | 3.05% | 1 | 14.29% |
Tejun Heo | 3 | 2.29% | 1 | 14.29% |
Total | 131 | 100.00% | 7 | 100.00% |
int ll_front_merge_fn(struct request_queue *q, struct request *req,
struct bio *bio)
{
if (req_gap_front_merge(req, bio))
return 0;
if (blk_integrity_rq(req) &&
integrity_req_gap_front_merge(req, bio))
return 0;
if (blk_rq_sectors(req) + bio_sectors(bio) >
blk_rq_get_max_sectors(req, bio->bi_iter.bi_sector)) {
req_set_nomerge(q, req);
return 0;
}
if (!bio_flagged(bio, BIO_SEG_VALID))
blk_recount_segments(q, bio);
if (!bio_flagged(req->bio, BIO_SEG_VALID))
blk_recount_segments(q, req->bio);
return ll_new_hw_segment(q, req, bio);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jens Axboe | 97 | 73.48% | 2 | 28.57% |
Sagi Grimberg | 17 | 12.88% | 1 | 14.29% |
Damien Le Moal | 6 | 4.55% | 1 | 14.29% |
Ritesh Harjani | 5 | 3.79% | 1 | 14.29% |
Martin K. Petersen | 4 | 3.03% | 1 | 14.29% |
Tejun Heo | 3 | 2.27% | 1 | 14.29% |
Total | 132 | 100.00% | 7 | 100.00% |
/*
* blk-mq uses req->special to carry normal driver per-request payload, it
* does not indicate a prepared command that we cannot merge with.
*/
static bool req_no_special_merge(struct request *req)
{
struct request_queue *q = req->q;
return !q->mq_ops && req->special;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jens Axboe | 30 | 100.00% | 1 | 100.00% |
Total | 30 | 100.00% | 1 | 100.00% |
static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
struct request *next)
{
int total_phys_segments;
unsigned int seg_size =
req->biotail->bi_seg_back_size + next->bio->bi_seg_front_size;
/*
* First check if the either of the requests are re-queued
* requests. Can't merge them if they are.
*/
if (req_no_special_merge(req) || req_no_special_merge(next))
return 0;
if (req_gap_back_merge(req, next->bio))
return 0;
/*
* Will it become too large?
*/
if ((blk_rq_sectors(req) + blk_rq_sectors(next)) >
blk_rq_get_max_sectors(req, blk_rq_pos(req)))
return 0;
total_phys_segments = req->nr_phys_segments + next->nr_phys_segments;
if (blk_phys_contig_segment(q, req->biotail, next->bio)) {
if (req->nr_phys_segments == 1)
req->bio->bi_seg_front_size = seg_size;
if (next->nr_phys_segments == 1)
next->biotail->bi_seg_back_size = seg_size;
total_phys_segments--;
}
if (total_phys_segments > queue_max_segments(q))
return 0;
if (blk_integrity_merge_rq(q, req, next) == false)
return 0;
/* Merge is OK... */
req->nr_phys_segments = total_phys_segments;
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jens Axboe | 101 | 51.01% | 3 | 23.08% |
FUJITA Tomonori | 50 | 25.25% | 1 | 7.69% |
Martin K. Petersen | 23 | 11.62% | 5 | 38.46% |
Keith Busch | 13 | 6.57% | 2 | 15.38% |
Tejun Heo | 6 | 3.03% | 1 | 7.69% |
Damien Le Moal | 5 | 2.53% | 1 | 7.69% |
Total | 198 | 100.00% | 13 | 100.00% |
/**
* blk_rq_set_mixed_merge - mark a request as mixed merge
* @rq: request to mark as mixed merge
*
* Description:
* @rq is about to be mixed merged. Make sure the attributes
* which can be mixed are set in each bio and mark @rq as mixed
* merged.
*/
void blk_rq_set_mixed_merge(struct request *rq)
{
unsigned int ff = rq->cmd_flags & REQ_FAILFAST_MASK;
struct bio *bio;
if (rq->rq_flags & RQF_MIXED_MERGE)
return;
/*
* @rq will no longer represent mixable attributes for all the
* contained bios. It will just track those of the first one.
* Distributes the attributs to each bio.
*/
for (bio = rq->bio; bio; bio = bio