vdev_raidz_asize_to_psize: return psize, not asize

Since 246e588, gang blocks written to raidz vdevs will write past the
end of their allocation, corrupting themselves, other data, or both.

The reason is simple - when allocating the gang children, we call
vdev_psize_to_asize() to find out how much data we should load into the
allocation we just did. vdev_raidz_asize_to_psize() had a bug; it
computed the psize, but returned the original asize. The raidz layer
dutifully writes that much out, into space beyond the end of the
allocation.

If there's existing data there, it gets overwritten, causing checksum
errors when that data is read. Even there's not data there (unlikely,
given that gang blocks are in play at all), that area is not considered
allocated, so can be allocated and overwritten later.

The fix is simple: return the psize we just computed.

Sponsored-by: Klara, Inc.
Sponsored-by: Wasabi Technology, Inc.
Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Reviewed-by: Allan Jude <allan@klarasystems.com>
Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
Closes #17488
This commit is contained in:
Rob Norris 2025-06-27 00:19:59 +10:00 committed by GitHub
parent 0a2163d194
commit ea076d6921
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -2260,7 +2260,7 @@ vdev_raidz_asize_to_psize(vdev_t *vd, uint64_t asize, uint64_t txg)
psize -= nparity * DIV_ROUND_UP(psize, cols); psize -= nparity * DIV_ROUND_UP(psize, cols);
psize <<= ashift; psize <<= ashift;
return (asize); return (psize);
} }
/* /*