Skip to content

Commit

Permalink
vdev_disk: fix alignment check when buffer has non-zero starting offset
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Rob Norris <[email protected]>
Closes #16076
  • Loading branch information
robn authored and behlendorf committed Apr 11, 2024
1 parent bc27c49 commit 1bf649c
Show file tree
Hide file tree
Showing 2 changed files with 2 additions and 2 deletions.
2 changes: 1 addition & 1 deletion module/os/linux/zfs/vdev_disk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 1bf649c

Please sign in to comment.