aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs/dmu_recv.c
diff options
context:
space:
mode:
authorRob Norris <[email protected]>2024-10-03 13:47:11 +1000
committerGitHub <[email protected]>2024-10-02 20:47:11 -0700
commit224393a3211b12c2cbac90a1d4dc730ceee1bbd0 (patch)
treeb0a0f84956ce1f10a6a7b55fe29c0c79d1f5f06b /module/zfs/dmu_recv.c
parent412105977c5cb1dcdd9a0b742ceaf04c75da24d0 (diff)
feature: large_microzap
In a4b21eadec we added the zap_micro_max_size tuneable to raise the size at which "micro" (single-block) ZAPs are upgraded to "fat" (multi-block) ZAPs. Before this, a microZAP was limited to 128KiB, which was the old largest block size. The side effect of raising the max size past 128KiB is that it be stored in a large block, requiring the large_blocks feature. Unfortunately, this means that a backup stream created without the --large-block (-L) flag to zfs send would split the microZAP block into smaller blocks and send those, as is normal behaviour for large blocks. This would be received correctly, but since microZAPs are limited to the first block in the object by definition, the entries in the later blocks would be inaccessible. For directory ZAPs, this gives the appearance of files being lost. This commit adds a feature flag, large_microzap, that must be enabled for microZAPs to grow beyond 128KiB, and which will be activated the first time that occurs. This feature is later checked when generating the stream and if active, the send operation will abort unless --large-block has also been requested. Changing the limit still requires zap_micro_max_size to be changed. The state of this flag effectively sets the upper value for this tuneable, that is, if the feature is disabled, the tuneable will be clamped to 128KiB. A stream flag is also added to ensure that the receiver also activates its own feature flag upon receiving the stream. This is not strictly necessary to _use_ the received microZAP, since it doesn't care how large its block is, but it is required to send the microZAP object on, otherwise the original problem occurs again. Because it's difficult to reliably distinguish a microZAP from a fatZAP from outside the ZAP code, and because it seems unlikely that most users are affected (a fairly niche tuneable combined with what should be an uncommon use of send), and for the sake of expediency, this change activates the feature the first time a microZAP grows to use a large block, and is never deactivated after that. This can be improved in the future. This commit changes nothing for existing pools that already have large microZAPs. The feature will not be retroactively applied, but will be activated the next time a microZAP grows past the limit. Don't use large_blocks feature for enable/disable tests. The large_microzap depends on large_blocks, so it gets enabled as a dependency, breaking the test. Instead use feature "longname", which has the exact same feature characteristics. Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc. Reviewed-by: Allan Jude <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Alexander Motin <[email protected]> Signed-off-by: Rob Norris <[email protected]> Closes #16593
Diffstat (limited to 'module/zfs/dmu_recv.c')
-rw-r--r--module/zfs/dmu_recv.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/module/zfs/dmu_recv.c b/module/zfs/dmu_recv.c
index 4877eb7e6..b1cd981ce 100644
--- a/module/zfs/dmu_recv.c
+++ b/module/zfs/dmu_recv.c
@@ -25,7 +25,7 @@
* Copyright (c) 2014, Joyent, Inc. All rights reserved.
* Copyright 2014 HybridCluster. All rights reserved.
* Copyright (c) 2018, loli10K <[email protected]>. All rights reserved.
- * Copyright (c) 2019, Klara Inc.
+ * Copyright (c) 2019, 2024, Klara, Inc.
* Copyright (c) 2019, Allan Jude
* Copyright (c) 2019 Datto Inc.
* Copyright (c) 2022 Axcient.
@@ -593,6 +593,9 @@ recv_begin_check_feature_flags_impl(uint64_t featureflags, spa_t *spa)
if ((featureflags & DMU_BACKUP_FEATURE_LARGE_DNODE) &&
!spa_feature_is_enabled(spa, SPA_FEATURE_LARGE_DNODE))
return (SET_ERROR(ENOTSUP));
+ if ((featureflags & DMU_BACKUP_FEATURE_LARGE_MICROZAP) &&
+ !spa_feature_is_enabled(spa, SPA_FEATURE_LARGE_MICROZAP))
+ return (SET_ERROR(ENOTSUP));
/*
* Receiving redacted streams requires that redacted datasets are
@@ -994,6 +997,24 @@ dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
numredactsnaps, tx);
}
+ if (featureflags & DMU_BACKUP_FEATURE_LARGE_MICROZAP) {
+ /*
+ * The source has seen a large microzap at least once in its
+ * life, so we activate the feature here to match. It's not
+ * strictly necessary since a large microzap is usable without
+ * the feature active, but if that object is sent on from here,
+ * we need this info to know to add the stream feature.
+ *
+ * There may be no large microzap in the incoming stream, or
+ * ever again, but this is a very niche feature and its very
+ * difficult to spot a large microzap in the stream, so its
+ * not worth the effort of trying harder to activate the
+ * feature at first use.
+ */
+ dsl_dataset_activate_feature(dsobj, SPA_FEATURE_LARGE_MICROZAP,
+ (void *)B_TRUE, tx);
+ }
+
dmu_buf_will_dirty(newds->ds_dbuf, tx);
dsl_dataset_phys(newds)->ds_flags |= DS_FLAG_INCONSISTENT;