summaryrefslogtreecommitdiffstats
path: root/module/zfs/dsl_userhold.c
diff options
context:
space:
mode:
authorPaul Zuchowski <[email protected]>2019-02-15 15:41:38 -0500
committerBrian Behlendorf <[email protected]>2019-02-15 12:41:38 -0800
commit9c5e88b1ded19cb4b19b9d767d5c71b34c189540 (patch)
tree08a51e07bb19bae06bdfbc61ae36b140514870ae /module/zfs/dsl_userhold.c
parente73ab1b38cd099f3416eed0ab5576639383bbdcc (diff)
zfs should optionally send holds
Add -h switch to zfs send command to send dataset holds. If holds are present in the stream, zfs receive will create them on the target dataset, unless the zfs receive -h option is used to skip receive of holds. Reviewed-by: Alek Pinchuk <[email protected]> Reviewed-by: loli10K <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Reviewed by: Paul Dagnelie <[email protected]> Signed-off-by: Paul Zuchowski <[email protected]> Closes #7513
Diffstat (limited to 'module/zfs/dsl_userhold.c')
-rw-r--r--module/zfs/dsl_userhold.c24
1 files changed, 23 insertions, 1 deletions
diff --git a/module/zfs/dsl_userhold.c b/module/zfs/dsl_userhold.c
index c80b35d48..638805d0b 100644
--- a/module/zfs/dsl_userhold.c
+++ b/module/zfs/dsl_userhold.c
@@ -83,6 +83,7 @@ dsl_dataset_user_hold_check(void *arg, dmu_tx_t *tx)
{
dsl_dataset_user_hold_arg_t *dduha = arg;
dsl_pool_t *dp = dmu_tx_pool(tx);
+ nvlist_t *tmp_holds;
if (spa_version(dp->dp_spa) < SPA_VERSION_USERREFS)
return (SET_ERROR(ENOTSUP));
@@ -90,6 +91,26 @@ dsl_dataset_user_hold_check(void *arg, dmu_tx_t *tx)
if (!dmu_tx_is_syncing(tx))
return (0);
+ /*
+ * Ensure the list has no duplicates by copying name/values from
+ * non-unique dduha_holds to unique tmp_holds, and comparing counts.
+ */
+ tmp_holds = fnvlist_alloc();
+ for (nvpair_t *pair = nvlist_next_nvpair(dduha->dduha_holds, NULL);
+ pair != NULL; pair = nvlist_next_nvpair(dduha->dduha_holds, pair)) {
+ size_t len = strlen(nvpair_name(pair)) +
+ strlen(fnvpair_value_string(pair));
+ char *nameval = kmem_zalloc(len + 2, KM_SLEEP);
+ (void) strcpy(nameval, nvpair_name(pair));
+ (void) strcat(nameval, "@");
+ (void) strcat(nameval, fnvpair_value_string(pair));
+ fnvlist_add_string(tmp_holds, nameval, "");
+ kmem_free(nameval, len + 2);
+ }
+ size_t tmp_count = fnvlist_num_pairs(tmp_holds);
+ fnvlist_free(tmp_holds);
+ if (tmp_count != fnvlist_num_pairs(dduha->dduha_holds))
+ return (SET_ERROR(EEXIST));
for (nvpair_t *pair = nvlist_next_nvpair(dduha->dduha_holds, NULL);
pair != NULL; pair = nvlist_next_nvpair(dduha->dduha_holds, pair)) {
dsl_dataset_t *ds;
@@ -312,7 +333,8 @@ dsl_dataset_user_hold(nvlist_t *holds, minor_t cleanup_minor, nvlist_t *errlist)
return (0);
dduha.dduha_holds = holds;
- dduha.dduha_chkholds = fnvlist_alloc();
+ /* chkholds can have non-unique name */
+ VERIFY(0 == nvlist_alloc(&dduha.dduha_chkholds, 0, KM_SLEEP));
dduha.dduha_errlist = errlist;
dduha.dduha_minor = cleanup_minor;