summaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
Diffstat (limited to 'module')
-rw-r--r--module/zfs/dmu_send.c1
-rw-r--r--module/zfs/dsl_userhold.c24
2 files changed, 23 insertions, 2 deletions
diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c
index 9c0ad406b..43e19ecbc 100644
--- a/module/zfs/dmu_send.c
+++ b/module/zfs/dmu_send.c
@@ -1282,7 +1282,6 @@ dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok,
err = dsl_pool_hold(tosnap, FTAG, &dp);
if (err != 0)
return (err);
-
if (strchr(tosnap, '@') == NULL && spa_writeable(dp->dp_spa)) {
/*
* We are sending a filesystem or volume. Ensure
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;