diff --git a/block/blk-mq-dma.c b/block/blk-mq-dma.c index 752060d7261c..33c1b6a0a738 100644 --- a/block/blk-mq-dma.c +++ b/block/blk-mq-dma.c @@ -4,8 +4,75 @@ */ #include #include +#include #include "blk.h" +static void dump_rq_mapping_debug(struct request *rq, struct scatterlist *sglist, + int nsegs) +{ + struct scatterlist *sg; + struct bio *bio; + struct bvec_iter iter; + struct bio_vec bv; + int i; + + pr_err("=== __blk_rq_map_sg DEBUG DUMP ===\n"); + pr_err("DISK: %s\n", rq->q->disk ? rq->q->disk->disk_name : "(null)"); + + /* Dump nsegs vs expected */ + pr_err("nsegs=%d nr_phys_segments=%u\n", + nsegs, blk_rq_nr_phys_segments(rq)); + + /* Dump request info */ + pr_err("REQUEST: __data_len=%u __sector=%llu cmd_flags=0x%x " + "rq_flags=0x%x nr_phys_segments=%u phys_gap_bit=%u\n", + rq->__data_len, (unsigned long long)rq->__sector, + rq->cmd_flags, (__force unsigned int)rq->rq_flags, + rq->nr_phys_segments, rq->phys_gap_bit); + + /* Dump each SG element */ + pr_err("--- SG LIST (%d entries) ---\n", nsegs); + for_each_sg(sglist, sg, nsegs, i) { + pr_err(" sg[%d]: pfn=0x%lx offset=%u len=%u dma_addr=0x%llx\n", + i, page_to_pfn(sg_page(sg)), sg->offset, sg->length, + (unsigned long long)sg_dma_address(sg)); + } + + /* Dump each bio */ + pr_err("--- BIO LIST ---\n"); + for (bio = rq->bio; bio; bio = bio->bi_next) { + pr_err(" BIO %p: bi_iter={sector=%llu size=%u idx=%u bvec_done=%u} " + "bi_flags=0x%x bi_opf=0x%x bi_vcnt=%u bi_bvec_gap_bit=%u\n", + bio, + (unsigned long long)bio->bi_iter.bi_sector, + bio->bi_iter.bi_size, bio->bi_iter.bi_idx, + bio->bi_iter.bi_bvec_done, + bio->bi_flags, bio->bi_opf, bio->bi_vcnt, + bio->bi_bvec_gap_bit); + + /* Dump each bvec in this bio */ + pr_err(" --- BVECS (bi_vcnt=%u) ---\n", bio->bi_vcnt); + for (i = 0; i < bio->bi_vcnt; i++) { + struct bio_vec *bvp = &bio->bi_io_vec[i]; + + pr_err(" bvec[%d]: pfn=0x%lx len=%u offset=%u\n", + i, page_to_pfn(bvp->bv_page), bvp->bv_len, + bvp->bv_offset); + } + + /* Also dump effective bvecs via iterator */ + pr_err(" --- EFFECTIVE BVECS (via iter) ---\n"); + i = 0; + bio_for_each_bvec(bv, bio, iter) { + pr_err(" eff_bvec[%d]: pfn=0x%lx len=%u offset=%u\n", + i++, page_to_pfn(bv.bv_page), bv.bv_len, + bv.bv_offset); + } + } + + pr_err("=== END DEBUG DUMP ===\n"); +} + static bool __blk_map_iter_next(struct blk_map_iter *iter) { if (iter->iter.bi_size) @@ -306,6 +373,8 @@ int __blk_rq_map_sg(struct request *rq, struct scatterlist *sglist, * Something must have been wrong if the figured number of * segment is bigger than number of req's physical segments */ + if (nsegs > blk_rq_nr_phys_segments(rq)) + dump_rq_mapping_debug(rq, sglist, nsegs); WARN_ON(nsegs > blk_rq_nr_phys_segments(rq)); return nsegs; diff --git a/block/blk.h b/block/blk.h index 98f4dfd4ec75..980eef1f5690 100644 --- a/block/blk.h +++ b/block/blk.h @@ -380,7 +380,7 @@ static inline bool bio_may_need_split(struct bio *bio, return true; bv = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter); - if (bio->bi_iter.bi_size > bv->bv_len) + if (bio->bi_iter.bi_size > bv->bv_len - bio->bi_iter.bi_bvec_done) return true; return bv->bv_len + bv->bv_offset > lim->max_fast_segment_size; }