aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Norris <rob.norris@klarasystems.com>2024-04-10 03:14:13 +0000
committerBrian Behlendorf <behlendorf1@llnl.gov>2024-04-11 21:43:27 +0000
commit1bf649cb0a1cc6e48dce848611ba327eb283000e (patch)
treed0f03cc09ea043c10910d8e7bdd84be7cc5b4b5a
parentbc27c494049e5282f90b103ee45d0fe12310aac4 (diff)
downloadsrc-1bf649cb0a1cc6e48dce848611ba327eb283000e.tar.gz
src-1bf649cb0a1cc6e48dce848611ba327eb283000e.zip
vdev_disk: fix alignment check when buffer has non-zero starting offset
If a linear buffer spans multiple pages, and the first page has a non-zero starting offset, the checker would not include the offset, and so would think there was an alignment gap at the end of the first page, rather than at the start. That is, for a 16K buffer spread across five pages with an initial 512B offset: [.XXXXXXX][XXXXXXXX][XXXXXXXX][XXXXXXXX][XXXXXXX.] It would be interpreted as: [XXXXXXX.][XXXXXXXX]... And be rejected as misaligned. Since it's already a linear ABD, the "linearising" copy would just reuse the buffer as-is, and the second check would failing, tripping the VERIFY in vdev_disk_io_rw(). This commit fixes all this by including the offset in the check for end-of-page alignment. Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc. Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Rob Norris <rob.norris@klarasystems.com> Closes #16076
-rw-r--r--module/os/linux/zfs/vdev_disk.c2
-rw-r--r--tests/zfs-tests/tests/functional/vdev_disk/page_alignment.c2
2 files changed, 2 insertions, 2 deletions
diff --git a/module/os/linux/zfs/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c
index 77773c4f2bf2..f3f0c0875210 100644
--- a/module/os/linux/zfs/vdev_disk.c
+++ b/module/os/linux/zfs/vdev_disk.c
@@ -882,7 +882,7 @@ vdev_disk_check_pages_cb(struct page *page, size_t off, size_t len, void *priv)
* Note if we're taking less than a full block, so we can check it
* above on the next call.
*/
- s->end = len & s->bmask;
+ s->end = (off+len) & s->bmask;
/* All blocks after the first must start on a block size boundary. */
if (s->npages != 0 && (off & s->bmask) != 0)
diff --git a/tests/zfs-tests/tests/functional/vdev_disk/page_alignment.c b/tests/zfs-tests/tests/functional/vdev_disk/page_alignment.c
index 98d19a1280ea..5c6d28eb2c44 100644
--- a/tests/zfs-tests/tests/functional/vdev_disk/page_alignment.c
+++ b/tests/zfs-tests/tests/functional/vdev_disk/page_alignment.c
@@ -61,7 +61,7 @@ vdev_disk_check_pages_cb(struct page *page, size_t off, size_t len, void *priv)
* Note if we're taking less than a full block, so we can check it
* above on the next call.
*/
- s->end = len & s->bmask;
+ s->end = (off+len) & s->bmask;
/* All blocks after the first must start on a block size boundary. */
if (s->npages != 0 && (off & s->bmask) != 0)