From f32dfe2ee04120179c3358dd36aedb4f422e77d6 Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Thu, 10 Jan 2013 02:15:13 +0530 Subject: [PATCH] block: blk-merge: don't merge the pages with non-contiguous descriptors blk_rq_map_sg() function merges the physically contiguous pages to use same scatter-gather node without checking if their page descriptors are contiguous or not. Now when dma_map_sg() is called on the scatter gather list, it would take the base page pointer from each node (one by one) and iterates through all of the pages in same sg node by keep incrementing the base page pointer with the assumption that physically contiguous pages will have their page descriptor address contiguous which may not be true if SPARSEMEM config is enabled. So here we may end referring to invalid page descriptor. Following table shows the example of physically contiguous pages but their page descriptor addresses non-contiguous. ------------------------------------------- | Page Descriptor | Physical Address | ------------------------------------------ | 0xc1e43fdc | 0xdffff000 | | 0xc2052000 | 0xe0000000 | ------------------------------------------- With this patch, relevant blk-merge functions will also check if the physically contiguous pages are having page descriptors address contiguous or not? If not then, these pages are separated to be in different scatter-gather nodes. (cherry picked from commit 6e25ce37a4f5750467f7c741b549687ebbc10667) CRs-Fixed: 392141 Change-Id: I3601565e5569a69f06fb3af99061c4d4c23af241 Signed-off-by: Subhash Jadavani --- block/blk-merge.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/block/blk-merge.c b/block/blk-merge.c index 4fced1be5d97..5d74cc354e30 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -42,6 +42,9 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q, 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; @@ -141,6 +144,9 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, goto new_segment; if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec)) goto new_segment; + if ((bvprv->bv_page != bvec->bv_page) && + ((bvprv->bv_page + 1) != bvec->bv_page)) + goto new_segment; sg->length += nbytes; } else {