/** * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements * @q: request queue * @bio: bio with integrity metadata attached * * Description: Returns the number of elements required in a * scatterlist corresponding to the integrity metadata in a bio. */ int blk_rq_count_integrity_sg(struct request_queue *q, struct bio *bio) { struct bio_vec iv, ivprv = { NULL }; unsigned int segments = 0; unsigned int seg_size = 0; struct bvec_iter iter; int prev = 0; bio_for_each_integrity_vec(iv, bio, iter) { if (prev) { if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv)) goto new_segment; if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv)) goto new_segment; if (seg_size + iv.bv_len > queue_max_segment_size(q)) goto new_segment; seg_size += iv.bv_len; } else { new_segment: segments++; seg_size = iv.bv_len; } prev = 1; ivprv = iv; } return segments; }
/** * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements * @q: request queue * @bio: bio with integrity metadata attached * * Description: Returns the number of elements required in a * scatterlist corresponding to the integrity metadata in a bio. */ int blk_rq_count_integrity_sg(struct request_queue *q, struct bio *bio) { struct bio_vec *iv, *ivprv = NULL; unsigned int segments = 0; unsigned int seg_size = 0; unsigned int i = 0; bio_for_each_integrity_vec(iv, bio, i) { if (ivprv) { if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv)) goto new_segment; if (!BIOVEC_SEG_BOUNDARY(q, ivprv, iv)) goto new_segment; if (seg_size + iv->bv_len > queue_max_segment_size(q)) goto new_segment; seg_size += iv->bv_len; } else { new_segment: segments++; seg_size = iv->bv_len; } ivprv = iv; } return 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; struct bvec_iter iter; 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_for_each_segment(end_bv, bio, iter) if (end_bv.bv_len == iter.bi_size) break; nxt_bv = bio_iovec(nxt); 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; }
static unsigned int __blk_recalc_rq_segments(struct request_queue *q, struct bio *bio) { struct bio_vec *bv, *bvprv = NULL; int cluster, i, high, highprv = 1; unsigned int seg_size, nr_phys_segs; struct bio *fbio, *bbio; if (!bio) return 0; fbio = bio; cluster = blk_queue_cluster(q); seg_size = 0; nr_phys_segs = 0; for_each_bio(bio) { bio_for_each_segment(bv, bio, i) { /* */ high = page_to_pfn(bv->bv_page) > queue_bounce_pfn(q); if (high || highprv) goto new_segment; if (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; if ((bvprv->bv_page != bv->bv_page) && (bvprv->bv_page + 1) != bv->bv_page) 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; seg_size = bv->bv_len; highprv = high; } bbio = bio; }
static unsigned int __blk_recalc_rq_segments(struct request_queue *q, struct bio *bio) { unsigned int phys_size; struct bio_vec *bv, *bvprv = NULL; int cluster, i, high, highprv = 1; unsigned int seg_size, nr_phys_segs; struct bio *fbio, *bbio; if (!bio) return 0; fbio = bio; cluster = test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); seg_size = 0; phys_size = nr_phys_segs = 0; for_each_bio(bio) { bio_for_each_segment(bv, bio, i) { /* * the trick here is making sure that a high page is * never considered part of another segment, since that * might change with the bounce page. */ high = page_to_pfn(bv->bv_page) > queue_bounce_pfn(q); if (high || highprv) goto new_segment; if (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; seg_size = bv->bv_len; highprv = high; } bbio = bio; }
static unsigned int __blk_recalc_rq_segments(struct request_queue *q, struct bio *bio) { struct bio_vec bv, bvprv = { NULL }; int cluster, high, highprv = 1; unsigned int seg_size, nr_phys_segs; struct bio *fbio, *bbio; struct bvec_iter iter; if (!bio) return 0; 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) { /* * the trick here is making sure that a high page is * never considered part of another segment, since that * might change with the bounce page. */ high = page_to_pfn(bv.bv_page) > queue_bounce_pfn(q); if (!high && !highprv && 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; seg_size = bv.bv_len; highprv = high; } bbio = bio; }
void blk_recalc_rq_segments(struct request *rq) { int nr_phys_segs; unsigned int phys_size; struct bio_vec *bv, *bvprv = NULL; int seg_size; int cluster; struct req_iterator iter; int high, highprv = 1; struct request_queue *q = rq->q; if (!rq->bio) return; cluster = test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); seg_size = 0; phys_size = nr_phys_segs = 0; rq_for_each_segment(bv, rq, iter) { /* * the trick here is making sure that a high page is never * considered part of another segment, since that might * change with the bounce page. */ high = page_to_pfn(bv->bv_page) > q->bounce_pfn; if (high || highprv) goto new_segment; if (cluster) { if (seg_size + bv->bv_len > q->max_segment_size) 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 > rq->bio->bi_seg_front_size) rq->bio->bi_seg_front_size = seg_size; nr_phys_segs++; bvprv = bv; seg_size = bv->bv_len; highprv = high; }
static unsigned int __blk_recalc_rq_segments(struct request_queue *q, struct bio *bio) { struct bio_vec *bv, *bvprv = NULL; int cluster, i, high, highprv = 1; unsigned int seg_size, nr_phys_segs; struct bio *fbio, *bbio; if (!bio) return 0; fbio = bio; cluster = blk_queue_cluster(q); seg_size = 0; nr_phys_segs = 0; for_each_bio(bio) { bio_for_each_segment(bv, bio, i) { /* * the trick here is making sure that a high page is * never considered part of another segment, since that * might change with the bounce page. */ high = page_to_pfn(bv->bv_page) > queue_bounce_pfn(q); if (high || highprv) goto new_segment; if (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; <<<<<<< HEAD if ((bvprv->bv_page != bv->bv_page) && (bvprv->bv_page + 1) != bv->bv_page) goto new_segment; ======= <<<<<<< HEAD if ((bvprv->bv_page != bv->bv_page) && (bvprv->bv_page + 1) != bv->bv_page) goto new_segment; ======= >>>>>>> 58a75b6a81be54a8b491263ca1af243e9d8617b9 >>>>>>> ae1773bb70f3d7cf73324ce8fba787e01d8fa9f2
/** * blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist * @q: request queue * @bio: bio with integrity metadata attached * @sglist: target scatterlist * * Description: Map the integrity vectors in request into a * scatterlist. The scatterlist must be big enough to hold all * elements. I.e. sized using blk_rq_count_integrity_sg(). */ int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio, struct scatterlist *sglist) { struct bio_vec iv, ivprv = { NULL }; struct scatterlist *sg = NULL; unsigned int segments = 0; struct bvec_iter iter; int prev = 0; bio_for_each_integrity_vec(iv, bio, iter) { if (prev) { if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv)) goto new_segment; if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv)) goto new_segment; if (sg->length + iv.bv_len > queue_max_segment_size(q)) goto new_segment; sg->length += iv.bv_len; } else { new_segment: if (!sg) sg = sglist; else { sg_unmark_end(sg); sg = sg_next(sg); } sg_set_page(sg, iv.bv_page, iv.bv_len, iv.bv_offset); segments++; } prev = 1; ivprv = iv; } if (sg) sg_mark_end(sg); return segments; }
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; }
/** * blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist * @q: request queue * @bio: bio with integrity metadata attached * @sglist: target scatterlist * * Description: Map the integrity vectors in request into a * scatterlist. The scatterlist must be big enough to hold all * elements. I.e. sized using blk_rq_count_integrity_sg(). */ int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio, struct scatterlist *sglist) { struct bio_vec *iv, *ivprv = NULL; struct scatterlist *sg = NULL; unsigned int segments = 0; unsigned int i = 0; bio_for_each_integrity_vec(iv, bio, i) { if (ivprv) { if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv)) goto new_segment; if (!BIOVEC_SEG_BOUNDARY(q, ivprv, iv)) goto new_segment; if (sg->length + iv->bv_len > queue_max_segment_size(q)) goto new_segment; sg->length += iv->bv_len; } else { new_segment: if (!sg) sg = sglist; else { sg->page_link &= ~0x02; sg = sg_next(sg); } sg_set_page(sg, iv->bv_page, iv->bv_len, iv->bv_offset); segments++; } ivprv = iv; } if (sg) sg_mark_end(sg); return segments; }
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, high, highprv = 1; unsigned int seg_size, nr_phys_segs; struct bio *fbio, *bbio; struct bvec_iter iter; if (!bio) return 0; /* * This should probably be returning 0, but blk_add_request_payload() * (Christoph!!!!) */ if (bio->bi_rw & REQ_DISCARD) return 1; if (bio->bi_rw & REQ_WRITE_SAME) return 1; fbio = bio; cluster = blk_queue_cluster(q); seg_size = 0; nr_phys_segs = 0; high = 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; /* * the trick here is making sure that a high page is * never considered part of another segment, since * that might change with the bounce page. */ high = page_to_pfn(bv.bv_page) > queue_bounce_pfn(q); if (!high && !highprv && 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; seg_size = bv.bv_len; highprv = high; } 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; }
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, i, high, highprv = 1; unsigned int seg_size, nr_phys_segs; struct bio *fbio, *bbio; if (!bio) return 0; fbio = bio; cluster = blk_queue_cluster(q); seg_size = 0; nr_phys_segs = 0; high = 0; for_each_bio(bio) { bio_for_each_segment(bv, bio, i) { /* * If SG merging is disabled, each bio vector is * a segment */ if (no_sg_merge) goto new_segment; /* * the trick here is making sure that a high page is * never considered part of another segment, since * that might change with the bounce page. */ high = page_to_pfn(bv->bv_page) > queue_bounce_pfn(q); if (high || highprv) goto new_segment; if (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; seg_size = bv->bv_len; highprv = high; } 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; }