Skip to content

Commit 3b73b0e

Browse files
authored
Merge pull request #253 from truenas/NAS-131081-EE
NAS-131081 / 24.10 / Sync stable/electriceel branch with openzfs/master
2 parents 45de819 + 80110e7 commit 3b73b0e

39 files changed

+1425
-167
lines changed

cmd/mount_zfs.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,7 @@ main(int argc, char **argv)
269269
return (MOUNT_USAGE);
270270
}
271271

272-
if (!zfsutil || sloppy ||
273-
libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
272+
if (sloppy || libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
274273
zfs_adjust_mount_options(zhp, mntpoint, mntopts, mtabopt);
275274
}
276275

@@ -337,7 +336,7 @@ main(int argc, char **argv)
337336
dataset, mntpoint, mntflags, zfsflags, mntopts, mtabopt);
338337

339338
if (!fake) {
340-
if (zfsutil && !sloppy &&
339+
if (!remount && !sloppy &&
341340
!libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
342341
error = zfs_mount_at(zhp, mntopts, mntflags, mntpoint);
343342
if (error) {

cmd/zdb/zdb.c

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2045,7 +2045,7 @@ dump_all_ddts(spa_t *spa)
20452045

20462046
for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {
20472047
ddt_t *ddt = spa->spa_ddt[c];
2048-
if (!ddt)
2048+
if (!ddt || ddt->ddt_version == DDT_VERSION_UNCONFIGURED)
20492049
continue;
20502050
for (ddt_type_t type = 0; type < DDT_TYPES; type++) {
20512051
for (ddt_class_t class = 0; class < DDT_CLASSES;
@@ -2072,6 +2072,32 @@ dump_all_ddts(spa_t *spa)
20722072
}
20732073

20742074
dump_dedup_ratio(&dds_total);
2075+
2076+
/*
2077+
* Dump a histogram of unique class entry age
2078+
*/
2079+
if (dump_opt['D'] == 3 && getenv("ZDB_DDT_UNIQUE_AGE_HIST") != NULL) {
2080+
ddt_age_histo_t histogram;
2081+
2082+
(void) printf("DDT walk unique, building age histogram...\n");
2083+
ddt_prune_walk(spa, 0, &histogram);
2084+
2085+
/*
2086+
* print out histogram for unique entry class birth
2087+
*/
2088+
if (histogram.dah_entries > 0) {
2089+
(void) printf("%5s %9s %4s\n",
2090+
"age", "blocks", "amnt");
2091+
(void) printf("%5s %9s %4s\n",
2092+
"-----", "---------", "----");
2093+
for (int i = 0; i < HIST_BINS; i++) {
2094+
(void) printf("%5d %9d %4d%%\n", 1 << i,
2095+
(int)histogram.dah_age_histo[i],
2096+
(int)((histogram.dah_age_histo[i] * 100) /
2097+
histogram.dah_entries));
2098+
}
2099+
}
2100+
}
20752101
}
20762102

20772103
static void
@@ -5749,12 +5775,17 @@ zdb_count_block(zdb_cb_t *zcb, zilog_t *zilog, const blkptr_t *bp,
57495775
ddt_entry_t *dde = ddt_lookup(ddt, bp);
57505776

57515777
/*
5752-
* ddt_lookup() can only return NULL if this block didn't exist
5778+
* ddt_lookup() can return NULL if this block didn't exist
57535779
* in the DDT and creating it would take the DDT over its
57545780
* quota. Since we got the block from disk, it must exist in
5755-
* the DDT, so this can't happen.
5781+
* the DDT, so this can't happen. However, when unique entries
5782+
* are pruned, the dedup bit can be set with no corresponding
5783+
* entry in the DDT.
57565784
*/
5757-
VERIFY3P(dde, !=, NULL);
5785+
if (dde == NULL) {
5786+
ddt_exit(ddt);
5787+
goto skipped;
5788+
}
57585789

57595790
/* Get the phys for this variant */
57605791
ddt_phys_variant_t v = ddt_phys_select(ddt, dde, bp);
@@ -5774,8 +5805,8 @@ zdb_count_block(zdb_cb_t *zcb, zilog_t *zilog, const blkptr_t *bp,
57745805
(void *)(((uintptr_t)dde->dde_io) | (1 << v));
57755806

57765807
/* Consume a reference for this block. */
5777-
VERIFY3U(ddt_phys_total_refcnt(ddt, dde->dde_phys), >, 0);
5778-
ddt_phys_decref(dde->dde_phys, v);
5808+
if (ddt_phys_total_refcnt(ddt, dde->dde_phys) > 0)
5809+
ddt_phys_decref(dde->dde_phys, v);
57795810

57805811
/*
57815812
* If this entry has a single flat phys, it may have been
@@ -5864,6 +5895,7 @@ zdb_count_block(zdb_cb_t *zcb, zilog_t *zilog, const blkptr_t *bp,
58645895
}
58655896
}
58665897

5898+
skipped:
58675899
for (i = 0; i < 4; i++) {
58685900
int l = (i < 2) ? BP_GET_LEVEL(bp) : ZB_TOTAL;
58695901
int t = (i & 1) ? type : ZDB_OT_TOTAL;
@@ -8138,7 +8170,7 @@ dump_mos_leaks(spa_t *spa)
81388170

81398171
for (uint64_t c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {
81408172
ddt_t *ddt = spa->spa_ddt[c];
8141-
if (!ddt)
8173+
if (!ddt || ddt->ddt_version == DDT_VERSION_UNCONFIGURED)
81428174
continue;
81438175

81448176
/* DDT store objects */
@@ -8150,11 +8182,14 @@ dump_mos_leaks(spa_t *spa)
81508182
}
81518183

81528184
/* FDT container */
8153-
mos_obj_refd(ddt->ddt_dir_object);
8185+
if (ddt->ddt_version == DDT_VERSION_FDT)
8186+
mos_obj_refd(ddt->ddt_dir_object);
81548187

81558188
/* FDT log objects */
8156-
mos_obj_refd(ddt->ddt_log[0].ddl_object);
8157-
mos_obj_refd(ddt->ddt_log[1].ddl_object);
8189+
if (ddt->ddt_flags & DDT_FLAG_LOG) {
8190+
mos_obj_refd(ddt->ddt_log[0].ddl_object);
8191+
mos_obj_refd(ddt->ddt_log[1].ddl_object);
8192+
}
81588193
}
81598194

81608195
if (spa->spa_brt != NULL) {

cmd/zpool/zpool_main.c

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
#include "zpool_util.h"
7676
#include "zfs_comutil.h"
7777
#include "zfeature_common.h"
78+
#include "zfs_valstr.h"
7879

7980
#include "statcommon.h"
8081

@@ -130,6 +131,8 @@ static int zpool_do_version(int, char **);
130131

131132
static int zpool_do_wait(int, char **);
132133

134+
static int zpool_do_ddt_prune(int, char **);
135+
133136
static int zpool_do_help(int argc, char **argv);
134137

135138
static zpool_compat_status_t zpool_do_load_compat(
@@ -170,6 +173,7 @@ typedef enum {
170173
HELP_CLEAR,
171174
HELP_CREATE,
172175
HELP_CHECKPOINT,
176+
HELP_DDT_PRUNE,
173177
HELP_DESTROY,
174178
HELP_DETACH,
175179
HELP_EXPORT,
@@ -426,6 +430,8 @@ static zpool_command_t command_table[] = {
426430
{ "sync", zpool_do_sync, HELP_SYNC },
427431
{ NULL },
428432
{ "wait", zpool_do_wait, HELP_WAIT },
433+
{ NULL },
434+
{ "ddtprune", zpool_do_ddt_prune, HELP_DDT_PRUNE },
429435
};
430436

431437
#define NCOMMAND (ARRAY_SIZE(command_table))
@@ -545,6 +551,8 @@ get_usage(zpool_help_t idx)
545551
case HELP_WAIT:
546552
return (gettext("\twait [-Hp] [-T d|u] [-t <activity>[,...]] "
547553
"<pool> [interval]\n"));
554+
case HELP_DDT_PRUNE:
555+
return (gettext("\tddtprune -d|-p <amount> <pool>\n"));
548556
default:
549557
__builtin_unreachable();
550558
}
@@ -11929,6 +11937,7 @@ static void
1192911937
zpool_do_events_nvprint(nvlist_t *nvl, int depth)
1193011938
{
1193111939
nvpair_t *nvp;
11940+
static char flagstr[256];
1193211941

1193311942
for (nvp = nvlist_next_nvpair(nvl, NULL);
1193411943
nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) {
@@ -11988,7 +11997,21 @@ zpool_do_events_nvprint(nvlist_t *nvl, int depth)
1198811997

1198911998
case DATA_TYPE_UINT32:
1199011999
(void) nvpair_value_uint32(nvp, &i32);
11991-
printf(gettext("0x%x"), i32);
12000+
if (strcmp(name,
12001+
FM_EREPORT_PAYLOAD_ZFS_ZIO_STAGE) == 0 ||
12002+
strcmp(name,
12003+
FM_EREPORT_PAYLOAD_ZFS_ZIO_PIPELINE) == 0) {
12004+
zfs_valstr_zio_stage(i32, flagstr,
12005+
sizeof (flagstr));
12006+
printf(gettext("0x%x [%s]"), i32, flagstr);
12007+
} else if (strcmp(name,
12008+
FM_EREPORT_PAYLOAD_ZFS_ZIO_PRIORITY) == 0) {
12009+
zfs_valstr_zio_priority(i32, flagstr,
12010+
sizeof (flagstr));
12011+
printf(gettext("0x%x [%s]"), i32, flagstr);
12012+
} else {
12013+
printf(gettext("0x%x"), i32);
12014+
}
1199212015
break;
1199312016

1199412017
case DATA_TYPE_INT64:
@@ -12009,6 +12032,12 @@ zpool_do_events_nvprint(nvlist_t *nvl, int depth)
1200912032
printf(gettext("\"%s\" (0x%llx)"),
1201012033
zpool_state_to_name(i64, VDEV_AUX_NONE),
1201112034
(u_longlong_t)i64);
12035+
} else if (strcmp(name,
12036+
FM_EREPORT_PAYLOAD_ZFS_ZIO_FLAGS) == 0) {
12037+
zfs_valstr_zio_flag(i64, flagstr,
12038+
sizeof (flagstr));
12039+
printf(gettext("0x%llx [%s]"),
12040+
(u_longlong_t)i64, flagstr);
1201212041
} else {
1201312042
printf(gettext("0x%llx"), (u_longlong_t)i64);
1201412043
}
@@ -13342,6 +13371,88 @@ found:;
1334213371
return (error);
1334313372
}
1334413373

13374+
/*
13375+
* zpool ddtprune -d|-p <amount> <pool>
13376+
*
13377+
* -d <days> Prune entries <days> old and older
13378+
* -p <percent> Prune <percent> amount of entries
13379+
*
13380+
* Prune single reference entries from DDT to satisfy the amount specified.
13381+
*/
13382+
int
13383+
zpool_do_ddt_prune(int argc, char **argv)
13384+
{
13385+
zpool_ddt_prune_unit_t unit = ZPOOL_DDT_PRUNE_NONE;
13386+
uint64_t amount = 0;
13387+
zpool_handle_t *zhp;
13388+
char *endptr;
13389+
int c;
13390+
13391+
while ((c = getopt(argc, argv, "d:p:")) != -1) {
13392+
switch (c) {
13393+
case 'd':
13394+
if (unit == ZPOOL_DDT_PRUNE_PERCENTAGE) {
13395+
(void) fprintf(stderr, gettext("-d cannot be "
13396+
"combined with -p option\n"));
13397+
usage(B_FALSE);
13398+
}
13399+
errno = 0;
13400+
amount = strtoull(optarg, &endptr, 0);
13401+
if (errno != 0 || *endptr != '\0' || amount == 0) {
13402+
(void) fprintf(stderr,
13403+
gettext("invalid days value\n"));
13404+
usage(B_FALSE);
13405+
}
13406+
amount *= 86400; /* convert days to seconds */
13407+
unit = ZPOOL_DDT_PRUNE_AGE;
13408+
break;
13409+
case 'p':
13410+
if (unit == ZPOOL_DDT_PRUNE_AGE) {
13411+
(void) fprintf(stderr, gettext("-p cannot be "
13412+
"combined with -d option\n"));
13413+
usage(B_FALSE);
13414+
}
13415+
errno = 0;
13416+
amount = strtoull(optarg, &endptr, 0);
13417+
if (errno != 0 || *endptr != '\0' ||
13418+
amount == 0 || amount > 100) {
13419+
(void) fprintf(stderr,
13420+
gettext("invalid percentage value\n"));
13421+
usage(B_FALSE);
13422+
}
13423+
unit = ZPOOL_DDT_PRUNE_PERCENTAGE;
13424+
break;
13425+
case '?':
13426+
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
13427+
optopt);
13428+
usage(B_FALSE);
13429+
}
13430+
}
13431+
argc -= optind;
13432+
argv += optind;
13433+
13434+
if (unit == ZPOOL_DDT_PRUNE_NONE) {
13435+
(void) fprintf(stderr,
13436+
gettext("missing amount option (-d|-p <value>)\n"));
13437+
usage(B_FALSE);
13438+
} else if (argc < 1) {
13439+
(void) fprintf(stderr, gettext("missing pool argument\n"));
13440+
usage(B_FALSE);
13441+
} else if (argc > 1) {
13442+
(void) fprintf(stderr, gettext("too many arguments\n"));
13443+
usage(B_FALSE);
13444+
}
13445+
zhp = zpool_open(g_zfs, argv[0]);
13446+
if (zhp == NULL)
13447+
return (-1);
13448+
13449+
int error = zpool_ddt_prune(zhp, unit, amount);
13450+
13451+
zpool_close(zhp);
13452+
13453+
return (error);
13454+
}
13455+
1334513456
static int
1334613457
find_command_idx(const char *command, int *idx)
1334713458
{

cmd/ztest.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ extern unsigned long zio_decompress_fail_fraction;
276276
extern unsigned long zfs_reconstruct_indirect_damage_fraction;
277277
extern uint64_t raidz_expand_max_reflow_bytes;
278278
extern uint_t raidz_expand_pause_point;
279+
extern boolean_t ddt_prune_artificial_age;
280+
extern boolean_t ddt_dump_prune_histogram;
279281

280282

281283
static ztest_shared_opts_t *ztest_shared_opts;
@@ -446,6 +448,7 @@ ztest_func_t ztest_fletcher;
446448
ztest_func_t ztest_fletcher_incr;
447449
ztest_func_t ztest_verify_dnode_bt;
448450
ztest_func_t ztest_pool_prefetch_ddt;
451+
ztest_func_t ztest_ddt_prune;
449452

450453
static uint64_t zopt_always = 0ULL * NANOSEC; /* all the time */
451454
static uint64_t zopt_incessant = 1ULL * NANOSEC / 10; /* every 1/10 second */
@@ -502,6 +505,7 @@ static ztest_info_t ztest_info[] = {
502505
ZTI_INIT(ztest_fletcher_incr, 1, &zopt_rarely),
503506
ZTI_INIT(ztest_verify_dnode_bt, 1, &zopt_sometimes),
504507
ZTI_INIT(ztest_pool_prefetch_ddt, 1, &zopt_rarely),
508+
ZTI_INIT(ztest_ddt_prune, 1, &zopt_rarely),
505509
};
506510

507511
#define ZTEST_FUNCS (sizeof (ztest_info) / sizeof (ztest_info_t))
@@ -6211,13 +6215,14 @@ void
62116215
ztest_spa_prop_get_set(ztest_ds_t *zd, uint64_t id)
62126216
{
62136217
(void) zd, (void) id;
6214-
nvlist_t *props = NULL;
62156218

62166219
(void) pthread_rwlock_rdlock(&ztest_name_lock);
62176220

62186221
(void) ztest_spa_prop_set_uint64(ZPOOL_PROP_AUTOTRIM, ztest_random(2));
62196222

6220-
VERIFY0(spa_prop_get(ztest_spa, &props));
6223+
nvlist_t *props = fnvlist_alloc();
6224+
6225+
VERIFY0(spa_prop_get(ztest_spa, props));
62216226

62226227
if (ztest_opts.zo_verbose >= 6)
62236228
dump_nvlist(props, 4);
@@ -7288,6 +7293,17 @@ ztest_trim(ztest_ds_t *zd, uint64_t id)
72887293
mutex_exit(&ztest_vdev_lock);
72897294
}
72907295

7296+
void
7297+
ztest_ddt_prune(ztest_ds_t *zd, uint64_t id)
7298+
{
7299+
(void) zd, (void) id;
7300+
7301+
spa_t *spa = ztest_spa;
7302+
uint64_t pct = ztest_random(15) + 1;
7303+
7304+
(void) ddt_prune_unique_entries(spa, ZPOOL_DDT_PRUNE_PERCENTAGE, pct);
7305+
}
7306+
72917307
/*
72927308
* Verify pool integrity by running zdb.
72937309
*/
@@ -7469,6 +7485,13 @@ ztest_resume_thread(void *arg)
74697485
{
74707486
spa_t *spa = arg;
74717487

7488+
/*
7489+
* Synthesize aged DDT entries for ddt prune testing
7490+
*/
7491+
ddt_prune_artificial_age = B_TRUE;
7492+
if (ztest_opts.zo_verbose >= 3)
7493+
ddt_dump_prune_histogram = B_TRUE;
7494+
74727495
while (!ztest_exiting) {
74737496
if (spa_suspended(spa))
74747497
ztest_resume(spa);
@@ -8587,6 +8610,12 @@ ztest_init(ztest_shared_t *zs)
85878610
if (i == SPA_FEATURE_LOG_SPACEMAP && ztest_random(4) == 0)
85888611
continue;
85898612

8613+
/*
8614+
* split 50/50 between legacy and fast dedup
8615+
*/
8616+
if (i == SPA_FEATURE_FAST_DEDUP && ztest_random(2) != 0)
8617+
continue;
8618+
85908619
VERIFY3S(-1, !=, asprintf(&buf, "feature@%s",
85918620
spa_feature_table[i].fi_uname));
85928621
fnvlist_add_uint64(props, buf, 0);

contrib/debian/openzfs-zfsutils.install

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ usr/share/man/man8/zpool-clear.8
100100
usr/share/man/man8/zpool-create.8
101101
usr/share/man/man8/zpool-destroy.8
102102
usr/share/man/man8/zpool-detach.8
103+
usr/share/man/man8/zpool-ddtprune.8
103104
usr/share/man/man8/zpool-events.8
104105
usr/share/man/man8/zpool-export.8
105106
usr/share/man/man8/zpool-get.8

0 commit comments

Comments
 (0)