aboutsummaryrefslogtreecommitdiff
path: root/sys/contrib/openzfs/module/zfs/vdev_raidz.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/openzfs/module/zfs/vdev_raidz.c')
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev_raidz.c55
1 files changed, 45 insertions, 10 deletions
diff --git a/sys/contrib/openzfs/module/zfs/vdev_raidz.c b/sys/contrib/openzfs/module/zfs/vdev_raidz.c
index 2db7422e772e..ab9f62c3c2d0 100644
--- a/sys/contrib/openzfs/module/zfs/vdev_raidz.c
+++ b/sys/contrib/openzfs/module/zfs/vdev_raidz.c
@@ -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];
@@ -546,12 +571,13 @@ vdev_raidz_map_alloc_write(zio_t *zio, raidz_map_t *rm, uint64_t ashift)
* VDEV queue locks (vq_lock).
*/
if (c < nwrapped) {
- rc->rc_abd = abd_alloc_linear(
+ rc->rc_abd = abd_alloc_linear_struct(&rc->rc_abdstruct,
rc->rc_size + (1ULL << ashift), B_FALSE);
abd_zero_off(rc->rc_abd, rc->rc_size, 1ULL << ashift);
skipped++;
} else {
- rc->rc_abd = abd_alloc_linear(rc->rc_size, B_FALSE);
+ rc->rc_abd = abd_alloc_linear_struct(&rc->rc_abdstruct,
+ rc->rc_size, B_FALSE);
}
}
@@ -599,9 +625,11 @@ vdev_raidz_map_alloc_read(zio_t *zio, raidz_map_t *rm)
ASSERT3U(rm->rm_nrows, ==, 1);
/* Allocate buffers for the parity columns */
- for (c = 0; c < rr->rr_firstdatacol; c++)
- rr->rr_col[c].rc_abd =
- abd_alloc_linear(rr->rr_col[c].rc_size, B_FALSE);
+ for (c = 0; c < rr->rr_firstdatacol; c++) {
+ raidz_col_t *rc = &rr->rr_col[c];
+ rc->rc_abd = abd_alloc_linear_struct(&rc->rc_abdstruct,
+ rc->rc_size, B_FALSE);
+ }
for (uint64_t off = 0; c < rr->rr_cols; c++) {
raidz_col_t *rc = &rr->rr_col[c];
@@ -1046,8 +1074,8 @@ vdev_raidz_map_alloc_expanded(zio_t *zio,
continue;
prc->rc_abd =
- abd_alloc_linear(rm->rm_phys_col[i].rc_size,
- B_FALSE);
+ abd_alloc_linear_struct(&prc->rc_abdstruct,
+ prc->rc_size, B_FALSE);
}
/*
@@ -1075,8 +1103,8 @@ vdev_raidz_map_alloc_expanded(zio_t *zio,
for (int c = 0; c < rr->rr_firstdatacol; c++) {
raidz_col_t *rc = &rr->rr_col[c];
rc->rc_abd =
- abd_alloc_linear(rc->rc_size,
- B_TRUE);
+ abd_alloc_linear_struct(&rc->rc_abdstruct,
+ rc->rc_size, B_TRUE);
}
}
}
@@ -1272,6 +1300,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;