|
@@ -110,6 +110,49 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static 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 (*bvprv && *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)->page_link &= ~0x02;
|
|
|
+ *sg = sg_next(*sg);
|
|
|
+ }
|
|
|
+
|
|
|
+ sg_set_page(*sg, bvec->bv_page, nbytes, bvec->bv_offset);
|
|
|
+ (*nsegs)++;
|
|
|
+ }
|
|
|
+ *bvprv = bvec;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* map a request to scatterlist, return number of sg entries setup. Caller
|
|
|
* must make sure sg can hold rq->nr_phys_segments entries
|
|
@@ -131,41 +174,8 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq,
|
|
|
bvprv = NULL;
|
|
|
sg = NULL;
|
|
|
rq_for_each_segment(bvec, rq, iter) {
|
|
|
- int nbytes = bvec->bv_len;
|
|
|
-
|
|
|
- if (bvprv && 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->page_link &= ~0x02;
|
|
|
- sg = sg_next(sg);
|
|
|
- }
|
|
|
-
|
|
|
- sg_set_page(sg, bvec->bv_page, nbytes, bvec->bv_offset);
|
|
|
- nsegs++;
|
|
|
- }
|
|
|
- bvprv = bvec;
|
|
|
+ __blk_segment_map_sg(q, bvec, sglist, &bvprv, &sg,
|
|
|
+ &nsegs, &cluster);
|
|
|
} /* segments in rq */
|
|
|
|
|
|
|