draid: fix import failure after disks replacements

Currently, it's possible that draid vdev asize would decrease
after disks replacements when the disk size is a little less than
all other disks in the pool. In such situations, import would
fail on this check in vdev_open():

        /*
         * Make sure the allocatable size hasn't shrunk too much.
         */
        if (asize < vd->vdev_min_asize) {
                vdev_set_state(vd, B_TRUE, VDEV_STATE_CANT_OPEN,
                    VDEV_AUX_BAD_LABEL);
                return (SET_ERROR(EINVAL));
        }

Solution: fix vdev_draid_min_asize() so that it would round up
the required minimal disk capacity to the VDEV_DRAID_ROWHEIGHT.
This would refuse replacements with the disks whose size is less
than minimally required to avoid draid asize decrement.

Note: we also use VDEV_DRAID_ROWHEIGHT in vdev_draid_open() when
calculating asize, and thats why we need to round up min_size at
vdev_draid_min_asize() to avoid asize drops.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Andriy Tkachuk <andriy.tkachuk@seagate.com>
Closes #18380
This commit is contained in:
Andriy Tkachuk
2026-03-31 23:41:03 +01:00
committed by Tony Hutter
parent 3ca81f610b
commit 9b8ccbd2cb
+4 -2
View File
@@ -1161,7 +1161,7 @@ vdev_draid_get_astart(vdev_t *vd, const uint64_t start)
/* /*
* Allocatable space for dRAID is (children - nspares) * sizeof(smallest child) * Allocatable space for dRAID is (children - nspares) * sizeof(smallest child)
* rounded down to the last full slice. So each child must provide at least * rounded down to the last full slice. So each child must provide at least
* 1 / (children - nspares) of its asize. * 1 / (children - nspares) of its asize rounded up to VDEV_DRAID_ROWHEIGHT.
*/ */
static uint64_t static uint64_t
vdev_draid_min_asize(vdev_t *vd) vdev_draid_min_asize(vdev_t *vd)
@@ -1171,7 +1171,9 @@ vdev_draid_min_asize(vdev_t *vd)
ASSERT3P(vd->vdev_ops, ==, &vdev_draid_ops); ASSERT3P(vd->vdev_ops, ==, &vdev_draid_ops);
return (VDEV_DRAID_REFLOW_RESERVE + return (VDEV_DRAID_REFLOW_RESERVE +
(vd->vdev_min_asize + vdc->vdc_ndisks - 1) / (vdc->vdc_ndisks)); ((vd->vdev_min_asize + vdc->vdc_ndisks - 1) / (vdc->vdc_ndisks) +
VDEV_DRAID_ROWHEIGHT - 1) / VDEV_DRAID_ROWHEIGHT *
VDEV_DRAID_ROWHEIGHT);
} }
/* /*