-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
blk-mq: move the DMA mapping code to a separate file
While working on the new DMA API I kept getting annoyed how it was placed right in the middle of the bio splitting code in blk-merge.c. Split it out into a separate file. Signed-off-by: Christoph Hellwig <hch@lst.de> Link: https://lore.kernel.org/r/20250513071433.836797-1-hch@lst.de Signed-off-by: Jens Axboe <axboe@kernel.dk>
- Loading branch information
Christoph Hellwig
authored and
Jens Axboe
committed
May 16, 2025
1 parent
7ee4fa0
commit b0a4158
Showing
4 changed files
with
136 additions
and
135 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// SPDX-License-Identifier: GPL-2.0-only | ||
#include "blk.h" | ||
|
||
struct phys_vec { | ||
phys_addr_t paddr; | ||
u32 len; | ||
}; | ||
|
||
static bool blk_map_iter_next(struct request *req, struct req_iterator *iter, | ||
struct phys_vec *vec) | ||
{ | ||
unsigned int max_size; | ||
struct bio_vec bv; | ||
|
||
if (req->rq_flags & RQF_SPECIAL_PAYLOAD) { | ||
if (!iter->bio) | ||
return false; | ||
vec->paddr = bvec_phys(&req->special_vec); | ||
vec->len = req->special_vec.bv_len; | ||
iter->bio = NULL; | ||
return true; | ||
} | ||
|
||
if (!iter->iter.bi_size) | ||
return false; | ||
|
||
bv = mp_bvec_iter_bvec(iter->bio->bi_io_vec, iter->iter); | ||
vec->paddr = bvec_phys(&bv); | ||
max_size = get_max_segment_size(&req->q->limits, vec->paddr, UINT_MAX); | ||
bv.bv_len = min(bv.bv_len, max_size); | ||
bio_advance_iter_single(iter->bio, &iter->iter, bv.bv_len); | ||
|
||
/* | ||
* If we are entirely done with this bi_io_vec entry, check if the next | ||
* one could be merged into it. This typically happens when moving to | ||
* the next bio, but some callers also don't pack bvecs tight. | ||
*/ | ||
while (!iter->iter.bi_size || !iter->iter.bi_bvec_done) { | ||
struct bio_vec next; | ||
|
||
if (!iter->iter.bi_size) { | ||
if (!iter->bio->bi_next) | ||
break; | ||
iter->bio = iter->bio->bi_next; | ||
iter->iter = iter->bio->bi_iter; | ||
} | ||
|
||
next = mp_bvec_iter_bvec(iter->bio->bi_io_vec, iter->iter); | ||
if (bv.bv_len + next.bv_len > max_size || | ||
!biovec_phys_mergeable(req->q, &bv, &next)) | ||
break; | ||
|
||
bv.bv_len += next.bv_len; | ||
bio_advance_iter_single(iter->bio, &iter->iter, next.bv_len); | ||
} | ||
|
||
vec->len = bv.bv_len; | ||
return true; | ||
} | ||
|
||
static inline struct scatterlist * | ||
blk_next_sg(struct scatterlist **sg, struct scatterlist *sglist) | ||
{ | ||
if (!*sg) | ||
return sglist; | ||
|
||
/* | ||
* 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); | ||
return sg_next(*sg); | ||
} | ||
|
||
/* | ||
* 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 *rq, struct scatterlist *sglist, | ||
struct scatterlist **last_sg) | ||
{ | ||
struct req_iterator iter = { | ||
.bio = rq->bio, | ||
}; | ||
struct phys_vec vec; | ||
int nsegs = 0; | ||
|
||
/* the internal flush request may not have bio attached */ | ||
if (iter.bio) | ||
iter.iter = iter.bio->bi_iter; | ||
|
||
while (blk_map_iter_next(rq, &iter, &vec)) { | ||
*last_sg = blk_next_sg(last_sg, sglist); | ||
sg_set_page(*last_sg, phys_to_page(vec.paddr), vec.len, | ||
offset_in_page(vec.paddr)); | ||
nsegs++; | ||
} | ||
|
||
if (*last_sg) | ||
sg_mark_end(*last_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; | ||
} | ||
EXPORT_SYMBOL(__blk_rq_map_sg); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters