RAIDZ: Optimize single data column writes

When a row contains only a single data column (one ashift-sized
block or 2-wide RAIDZ), P = Q = R = data mathematically.  In this
case point all parity column ABDs at the data column ABD, skipping
both buffer allocation and parity generation.

It might be not very efficient to write so small blocks on RAIDZ,
but it is allowed and does happen.  Skipping this allocation and
memory copy saves several percents of CPU time.

Reviewed-by: Brian Behlendorf <[email protected]>
Reviewed-by: Rob Norris <[email protected]>
Signed-off-by: Alexander Motin <[email protected]>
Closes #18695
This commit is contained in:
Alexander Motin authored and GitHub committed 2026-06-24 15:44:56 -07:00
1 parent 99ab859c38
commit 41311c6651
1 file changed
+33 -1
+33 -1
View File
@@ -419,7 +419,16 @@ static int zfs_scrub_partial_writes = 1;
static void
vdev_raidz_row_free(raidz_row_t *rr)
{
for (int c = 0; c < rr->rr_cols; c++) {
abd_t *dabd = rr->rr_col[rr->rr_firstdatacol].rc_abd;
for (int c = 0; c < rr->rr_firstdatacol; c++) {
raidz_col_t *rc = &rr->rr_col[c];
if (rc->rc_size != 0 && rc->rc_abd != dabd)
abd_free(rc->rc_abd);
if (rc->rc_orig_data != NULL)
abd_free(rc->rc_orig_data);
}
for (int c = rr->rr_firstdatacol; c < rr->rr_cols; c++) {
raidz_col_t *rc = &rr->rr_col[c];
if (rc->rc_size != 0)
@@ -532,6 +541,22 @@ vdev_raidz_map_alloc_write(zio_t *zio, raidz_map_t *rm, uint64_t ashift)
*/
int skipped = rr->rr_scols - rr->rr_cols;
/*
* When there is only a single data column the parity is a copy of
* it, so point all parity columns at the data ABD directly to avoid
* allocating buffers and computing parity.
*/
if (rr->rr_cols == rr->rr_firstdatacol + 1) {
ASSERT0(nwrapped);
ASSERT0(rm->rm_nskip);
raidz_col_t *dc = &rr->rr_col[rr->rr_firstdatacol];
dc->rc_abd = abd_get_offset_struct(&dc->rc_abdstruct,
zio->io_abd, 0, dc->rc_size);
for (c = 0; c < rr->rr_firstdatacol; c++)
rr->rr_col[c].rc_abd = dc->rc_abd;
return;
}
/* Allocate buffers for the parity columns */
for (c = 0; c < rr->rr_firstdatacol; c++) {
raidz_col_t *rc = &rr->rr_col[c];
@@ -1272,6 +1297,13 @@ vdev_raidz_generate_parity_row(raidz_map_t *rm, raidz_row_t *rr)
return;
}
/*
* Single data column: parity is the data itself.
*/
if (rr->rr_col[VDEV_RAIDZ_P].rc_abd ==
rr->rr_col[rr->rr_firstdatacol].rc_abd)
return;
/* Generate using the new math implementation */
if (vdev_raidz_math_generate(rm, rr) != RAIDZ_ORIGINAL_IMPL)
return;