diff options
Diffstat (limited to 'module/zfs/vdev_indirect.c')
-rw-r--r-- | module/zfs/vdev_indirect.c | 39 |
1 files changed, 30 insertions, 9 deletions
diff --git a/module/zfs/vdev_indirect.c b/module/zfs/vdev_indirect.c index 12ee393bd5db..07d1c922a50c 100644 --- a/module/zfs/vdev_indirect.c +++ b/module/zfs/vdev_indirect.c @@ -239,6 +239,7 @@ typedef struct indirect_child { */ struct indirect_child *ic_duplicate; list_node_t ic_node; /* node on is_unique_child */ + int ic_error; /* set when a child does not contain the data */ } indirect_child_t; /* @@ -1272,15 +1273,14 @@ vdev_indirect_read_all(zio_t *zio) continue; /* - * Note, we may read from a child whose DTL - * indicates that the data may not be present here. - * While this might result in a few i/os that will - * likely return incorrect data, it simplifies the - * code since we can treat scrub and resilver - * identically. (The incorrect data will be - * detected and ignored when we verify the - * checksum.) + * If a child is missing the data, set ic_error. Used + * in vdev_indirect_repair(). We perform the read + * nevertheless which provides the opportunity to + * reconstruct the split block if at all possible. */ + if (vdev_dtl_contains(ic->ic_vdev, DTL_MISSING, + zio->io_txg, 1)) + ic->ic_error = SET_ERROR(ESTALE); ic->ic_data = abd_alloc_sametype(zio->io_abd, is->is_size); @@ -1410,7 +1410,11 @@ vdev_indirect_checksum_error(zio_t *zio, * Issue repair i/os for any incorrect copies. We do this by comparing * each split segment's correct data (is_good_child's ic_data) with each * other copy of the data. If they differ, then we overwrite the bad data - * with the good copy. Note that we do this without regard for the DTL's, + * with the good copy. The DTL is checked in vdev_indirect_read_all() and + * if a vdev is missing a copy of the data we set ic_error and the read is + * performed. This provides the opportunity to reconstruct the split block + * if at all possible. ic_error is checked here and if set it suppresses + * incrementing the checksum counter. Aside from this DTLs are not checked, * which simplifies this code and also issues the optimal number of writes * (based on which copies actually read bad data, as opposed to which we * think might be wrong). For the same reason, we always use @@ -1447,6 +1451,14 @@ vdev_indirect_repair(zio_t *zio) ZIO_FLAG_IO_REPAIR | ZIO_FLAG_SELF_HEAL, NULL, NULL)); + /* + * If ic_error is set the current child does not have + * a copy of the data, so suppress incrementing the + * checksum counter. + */ + if (ic->ic_error == ESTALE) + continue; + vdev_indirect_checksum_error(zio, is, ic); } } @@ -1844,9 +1856,13 @@ vdev_indirect_io_done(zio_t *zio) } vdev_ops_t vdev_indirect_ops = { + .vdev_op_init = NULL, + .vdev_op_fini = NULL, .vdev_op_open = vdev_indirect_open, .vdev_op_close = vdev_indirect_close, .vdev_op_asize = vdev_default_asize, + .vdev_op_min_asize = vdev_default_min_asize, + .vdev_op_min_alloc = NULL, .vdev_op_io_start = vdev_indirect_io_start, .vdev_op_io_done = vdev_indirect_io_done, .vdev_op_state_change = NULL, @@ -1855,6 +1871,11 @@ vdev_ops_t vdev_indirect_ops = { .vdev_op_rele = NULL, .vdev_op_remap = vdev_indirect_remap, .vdev_op_xlate = NULL, + .vdev_op_rebuild_asize = NULL, + .vdev_op_metaslab_init = NULL, + .vdev_op_config_generate = NULL, + .vdev_op_nparity = NULL, + .vdev_op_ndisks = NULL, .vdev_op_type = VDEV_TYPE_INDIRECT, /* name of this vdev type */ .vdev_op_leaf = B_FALSE /* leaf vdev */ }; |