|
26 | 26 | * Copyright (c) 2017, 2019, Datto Inc. All rights reserved.
|
27 | 27 | * Copyright (c) 2015, Nexenta Systems, Inc. All rights reserved.
|
28 | 28 | * Copyright 2019 Joyent, Inc.
|
| 29 | + * Copyright 2025 ConnectWise, Inc. |
29 | 30 | */
|
30 | 31 |
|
31 | 32 | #include <sys/dsl_scan.h>
|
|
56 | 57 | #include <sys/abd.h>
|
57 | 58 | #include <sys/range_tree.h>
|
58 | 59 | #include <sys/dbuf.h>
|
| 60 | +#include <sys/fm/fs/zfs.h> |
59 | 61 | #ifdef _KERNEL
|
60 | 62 | #include <sys/zfs_vfsops.h>
|
61 | 63 | #endif
|
@@ -246,6 +248,13 @@ static int zfs_free_bpobj_enabled = 1;
|
246 | 248 | /* Error blocks to be scrubbed in one txg. */
|
247 | 249 | static uint_t zfs_scrub_error_blocks_per_txg = 1 << 12;
|
248 | 250 |
|
| 251 | +/* |
| 252 | + * When set to a non-zero value will cause scrub to decompress blocks it |
| 253 | + * reads so that it will catch the rare type of corruption where the |
| 254 | + * checksum matches the data, but decompression fails. |
| 255 | + */ |
| 256 | +static uint_t zfs_scrub_decompress = 0; |
| 257 | + |
249 | 258 | /* the order has to match pool_scan_type */
|
250 | 259 | static scan_cb_t *scan_funcs[POOL_SCAN_FUNCS] = {
|
251 | 260 | NULL,
|
@@ -4874,6 +4883,41 @@ dsl_scan_scrub_done(zio_t *zio)
|
4874 | 4883 | blkptr_t *bp = zio->io_bp;
|
4875 | 4884 | dsl_scan_io_queue_t *queue = zio->io_private;
|
4876 | 4885 |
|
| 4886 | + /* |
| 4887 | + * If the block was read without error, is compressed, and we're doing |
| 4888 | + * a decompression scrub we will now attempt to decompress it to |
| 4889 | + * further verify its integrity. |
| 4890 | + */ |
| 4891 | + if (zio->io_error == 0 && (BP_GET_COMPRESS(bp) != ZIO_COMPRESS_OFF) && |
| 4892 | + zfs_scrub_decompress != 0) { |
| 4893 | + abd_t *dabd = abd_alloc_linear(BP_GET_PSIZE(bp), B_FALSE); |
| 4894 | + if (dabd != NULL) { |
| 4895 | + if (zio_decompress_data(BP_GET_COMPRESS(bp), |
| 4896 | + zio->io_abd, dabd, |
| 4897 | + abd_get_size(zio->io_abd), abd_get_size(dabd), |
| 4898 | + &zio->io_prop.zp_complevel) != 0) { |
| 4899 | + // checksum was valid but decompression failed |
| 4900 | + if (dsl_errorscrubbing(spa->spa_dsl_pool) && |
| 4901 | + !dsl_errorscrub_is_paused( |
| 4902 | + spa->spa_dsl_pool->dp_scan)) { |
| 4903 | + atomic_inc_64(&spa->spa_dsl_pool-> |
| 4904 | + dp_scan->errorscrub_phys |
| 4905 | + .dep_errors); |
| 4906 | + } else { |
| 4907 | + atomic_inc_64(&spa->spa_dsl_pool-> |
| 4908 | + dp_scan->scn_phys.scn_errors); |
| 4909 | + } |
| 4910 | + // errlog this so it's in the zpool status -v |
| 4911 | + spa_log_error(zio->io_spa, &zio->io_bookmark, |
| 4912 | + BP_GET_LOGICAL_BIRTH(zio->io_bp)); |
| 4913 | + (void) zfs_ereport_post(FM_EREPORT_ZFS_DATA, |
| 4914 | + zio->io_spa, NULL, &zio->io_bookmark, |
| 4915 | + zio, 0); |
| 4916 | + } |
| 4917 | + abd_free(dabd); |
| 4918 | + } |
| 4919 | + } |
| 4920 | + |
4877 | 4921 | abd_free(zio->io_abd);
|
4878 | 4922 |
|
4879 | 4923 | if (queue == NULL) {
|
@@ -5362,3 +5406,6 @@ ZFS_MODULE_PARAM(zfs, zfs_, resilver_defer_percent, UINT, ZMOD_RW,
|
5362 | 5406 |
|
5363 | 5407 | ZFS_MODULE_PARAM(zfs, zfs_, scrub_error_blocks_per_txg, UINT, ZMOD_RW,
|
5364 | 5408 | "Error blocks to be scrubbed in one txg");
|
| 5409 | + |
| 5410 | +ZFS_MODULE_PARAM(zfs, zfs_, scrub_decompress, UINT, ZMOD_RW, |
| 5411 | + "Scrub will decompress compressed blocks"); |
0 commit comments