From patchwork Mon Jun 21 16:39:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Gardner X-Patchwork-Id: 1495201 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4G7wGv2bKJz9sXk; Tue, 22 Jun 2021 02:39:35 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1lvMxP-0002GM-DB; Mon, 21 Jun 2021 16:39:31 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1lvMxK-0002FD-No for kernel-team@lists.ubuntu.com; Mon, 21 Jun 2021 16:39:26 +0000 Received: from mail-pg1-f198.google.com ([209.85.215.198]) by youngberry.canonical.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.93) (envelope-from ) id 1lvMxK-0007aO-GL for kernel-team@lists.ubuntu.com; Mon, 21 Jun 2021 16:39:26 +0000 Received: by mail-pg1-f198.google.com with SMTP id v186-20020a632fc30000b029022192d6757dso12063451pgv.22 for ; Mon, 21 Jun 2021 09:39:26 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=xsrClqz4AUoZ8tM2uMQHyTv15DudTfenPICqJPoBZgY=; b=P9jSp+6HYbNTna1EOisoUIRDpjlnc/tR3c/z7/hJ+Wq5epDQDtJgDes3uadT1SpZw4 FP6ngpZkdh4Q2mHe3HF6iMM14OG3YTxiNsGug5IhxQDJZVIhTWud/CVtjopO4lVYwjfn eE0aEkXlgC7iVkH5tl1FKTjXhMOqLHwjpzzp+jwh+iJ02ARdq0PVr580ykx3IGyFoEQ3 QaJkEbehsXqR6iplAptznhLPqAtsFRoy8OkNAkQzb5a4f63PHzm2bUUtXL9c0eY1AVJG zgCqkLOshLK50np44rB5J4uoT0jWqE5vo04HnEdZJQlxRRddOvNhhlWk7Aa6m7xXvuAq Z4Qw== X-Gm-Message-State: AOAM530mAnEE9Nv+6o5v9ovba7e/lVZ8zADp3TJ1eHPrD9oUUnr8YcOO QoB78/4bboTFyKDx+YWDOWO5LX1nf9wWO7gfHtTbRnr2ou8BASybKCThO4WZFYmbCxvjNhenSHL be8vmNdAfHtpsCiv2cj6SPeE+C/6MVKG7GEPtuoybSA== X-Received: by 2002:aa7:8e5a:0:b029:2e9:10d3:376f with SMTP id d26-20020aa78e5a0000b02902e910d3376fmr20361600pfr.19.1624293564914; Mon, 21 Jun 2021 09:39:24 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzD6CFhEVBRuBSqoRkF9eXWF/lpba9/uRODeyjS2TtisItV/vcndgfNjrUbXnHXV3uvl/CSEg== X-Received: by 2002:aa7:8e5a:0:b029:2e9:10d3:376f with SMTP id d26-20020aa78e5a0000b02902e910d3376fmr20361582pfr.19.1624293564708; Mon, 21 Jun 2021 09:39:24 -0700 (PDT) Received: from localhost.localdomain ([69.163.84.166]) by smtp.gmail.com with ESMTPSA id p17sm19722602pjg.54.2021.06.21.09.39.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Jun 2021 09:39:23 -0700 (PDT) From: Tim Gardner To: kernel-team@lists.ubuntu.com Subject: [PATCH] block: return the correct bvec when checking for gaps Date: Mon, 21 Jun 2021 10:39:18 -0600 Message-Id: <20210621163918.10140-2-tim.gardner@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210621163918.10140-1-tim.gardner@canonical.com> References: <20210621163918.10140-1-tim.gardner@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Long Li BugLink: https://bugs.launchpad.net/bugs/1931497 After commit 07173c3ec276 ("block: enable multipage bvecs"), a bvec can have multiple pages. But bio_will_gap() still assumes one page bvec while checking for merging. If the pages in the bvec go across the seg_boundary_mask, this check for merging can potentially succeed if only the 1st page is tested, and can fail if all the pages are tested. Later, when SCSI builds the SG list the same check for merging is done in __blk_segment_map_sg_merge() with all the pages in the bvec tested. This time the check may fail if the pages in bvec go across the seg_boundary_mask (but tested okay in bio_will_gap() earlier, so those BIOs were merged). If this check fails, we end up with a broken SG list for drivers assuming the SG list not having offsets in intermediate pages. This results in incorrect pages written to the disk. Fix this by returning the multi-page bvec when testing gaps for merging. Cc: Jens Axboe Cc: Johannes Thumshirn Cc: Pavel Begunkov Cc: Ming Lei Cc: Tejun Heo Cc: "Matthew Wilcox (Oracle)" Cc: Jeffle Xu Cc: linux-kernel@vger.kernel.org Cc: stable@vger.kernel.org Fixes: 07173c3ec276 ("block: enable multipage bvecs") Signed-off-by: Long Li Reviewed-by: Ming Lei Reviewed-by: Christoph Hellwig Link: https://lore.kernel.org/r/1623094445-22332-1-git-send-email-longli@linuxonhyperv.com Signed-off-by: Jens Axboe (cherry picked from commit c9c9762d4d44dcb1b2ba90cfb4122dc11ceebf31 linux-next) Signed-off-by: Tim Gardner --- include/linux/bio.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/include/linux/bio.h b/include/linux/bio.h index 853d92ceee64e..b0927b27a8a88 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -40,9 +40,6 @@ #define bio_offset(bio) bio_iter_offset((bio), (bio)->bi_iter) #define bio_iovec(bio) bio_iter_iovec((bio), (bio)->bi_iter) -#define bio_multiple_segments(bio) \ - ((bio)->bi_iter.bi_size != bio_iovec(bio).bv_len) - #define bvec_iter_sectors(iter) ((iter).bi_size >> 9) #define bvec_iter_end_sector(iter) ((iter).bi_sector + bvec_iter_sectors((iter))) @@ -246,7 +243,7 @@ static inline void bio_clear_flag(struct bio *bio, unsigned int bit) static inline void bio_get_first_bvec(struct bio *bio, struct bio_vec *bv) { - *bv = bio_iovec(bio); + *bv = mp_bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter); } static inline void bio_get_last_bvec(struct bio *bio, struct bio_vec *bv) @@ -254,10 +251,9 @@ static inline void bio_get_last_bvec(struct bio *bio, struct bio_vec *bv) struct bvec_iter iter = bio->bi_iter; int idx; - if (unlikely(!bio_multiple_segments(bio))) { - *bv = bio_iovec(bio); - return; - } + bio_get_first_bvec(bio, bv); + if (bv->bv_len == bio->bi_iter.bi_size) + return; /* this bio only has a single bvec */ bio_advance_iter(bio, &iter, iter.bi_size);