diff mbox series

block: avoid scatterlist offsets > PAGE_SIZE

Message ID 20190419065624.25583-1-hch@lst.de (mailing list archive)
State New, archived
Headers show
Series block: avoid scatterlist offsets > PAGE_SIZE | expand

Commit Message

Christoph Hellwig April 19, 2019, 6:56 a.m. UTC
While we generally allow scatterlists to have offsets larger than page
size for an entry, and other subsystems like the crypto code make use of
that, the block layer isn't quite ready for that.  Flip the switch back
to avoid them for now, and revisit that decision early in a merge window
once the known offenders are fixed.

Fixes: 8a96a0e40810 ("block: rewrite blk_bvec_map_sg to avoid a nth_page call")
Reported-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 block/blk-merge.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

Comments

Ming Lei April 22, 2019, 9:35 a.m. UTC | #1
On Sat, Apr 20, 2019 at 6:55 AM Christoph Hellwig <hch@lst.de> wrote:
>
> While we generally allow scatterlists to have offsets larger than page
> size for an entry, and other subsystems like the crypto code make use of
> that, the block layer isn't quite ready for that.  Flip the switch back
> to avoid them for now, and revisit that decision early in a merge window
> once the known offenders are fixed.
>
> Fixes: 8a96a0e40810 ("block: rewrite blk_bvec_map_sg to avoid a nth_page call")
> Reported-by: Guenter Roeck <linux@roeck-us.net>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>  block/blk-merge.c | 14 +++++++++++++-
>  1 file changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/block/blk-merge.c b/block/blk-merge.c
> index 247b17f2a0f6..21e87a714a73 100644
> --- a/block/blk-merge.c
> +++ b/block/blk-merge.c
> @@ -474,9 +474,21 @@ static unsigned blk_bvec_map_sg(struct request_queue *q,
>         while (nbytes > 0) {
>                 unsigned offset = bvec->bv_offset + total;
>                 unsigned len = min(get_max_segment_size(q, offset), nbytes);
> +               struct page *page = bvec->bv_page;
> +
> +               /*
> +                * Unfortunately a fair number of drivers barf on scatterlists
> +                * that have an offset larger than PAGE_SIZE, despite other
> +                * subsystems dealing with that invariant just fine.  For now
> +                * stick to the legacy format where we never present those from
> +                * the block layer, but the code below should be removed once
> +                * these offenders (mostly MMC/SD drivers) are fixed.
> +                */
> +               page += (offset >> PAGE_SHIFT);
> +               offset &= ~PAGE_MASK;
>
>                 *sg = blk_next_sg(sg, sglist);
> -               sg_set_page(*sg, bvec->bv_page, len, offset);
> +               sg_set_page(*sg, page, len, offset);

Reviewed-by: Ming Lei <ming.lei@redhat.com>
Jens Axboe April 22, 2019, 2:22 p.m. UTC | #2
On 4/19/19 12:56 AM, Christoph Hellwig wrote:
> While we generally allow scatterlists to have offsets larger than page
> size for an entry, and other subsystems like the crypto code make use of
> that, the block layer isn't quite ready for that.  Flip the switch back
> to avoid them for now, and revisit that decision early in a merge window
> once the known offenders are fixed.

Applied, thanks.
diff mbox series

Patch

diff --git a/block/blk-merge.c b/block/blk-merge.c
index 247b17f2a0f6..21e87a714a73 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -474,9 +474,21 @@  static unsigned blk_bvec_map_sg(struct request_queue *q,
 	while (nbytes > 0) {
 		unsigned offset = bvec->bv_offset + total;
 		unsigned len = min(get_max_segment_size(q, offset), nbytes);
+		struct page *page = bvec->bv_page;
+
+		/*
+		 * Unfortunately a fair number of drivers barf on scatterlists
+		 * that have an offset larger than PAGE_SIZE, despite other
+		 * subsystems dealing with that invariant just fine.  For now
+		 * stick to the legacy format where we never present those from
+		 * the block layer, but the code below should be removed once
+		 * these offenders (mostly MMC/SD drivers) are fixed.
+		 */
+		page += (offset >> PAGE_SHIFT);
+		offset &= ~PAGE_MASK;
 
 		*sg = blk_next_sg(sg, sglist);
-		sg_set_page(*sg, bvec->bv_page, len, offset);
+		sg_set_page(*sg, page, len, offset);
 
 		total += len;
 		nbytes -= len;