Rebase master to b117
[zfs.git] / module / zfs / dsl_prop.c
index 212acbb..664ccff 100644 (file)
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident  "%Z%%M% %I%     %E% SMI"
-
 #include <sys/dmu.h>
 #include <sys/dmu_objset.h>
 #include <sys/dmu_tx.h>
@@ -416,6 +414,34 @@ dsl_prop_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
 }
 
 void
+dsl_props_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
+{
+       dsl_dataset_t *ds = arg1;
+       nvlist_t *nvl = arg2;
+       nvpair_t *elem = NULL;
+
+       while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
+               struct prop_set_arg psa;
+
+               psa.name = nvpair_name(elem);
+
+               if (nvpair_type(elem) == DATA_TYPE_STRING) {
+                       VERIFY(nvpair_value_string(elem,
+                           (char **)&psa.buf) == 0);
+                       psa.intsz = 1;
+                       psa.numints = strlen(psa.buf) + 1;
+               } else {
+                       uint64_t intval;
+                       VERIFY(nvpair_value_uint64(elem, &intval) == 0);
+                       psa.intsz = sizeof (intval);
+                       psa.numints = 1;
+                       psa.buf = &intval;
+               }
+               dsl_prop_set_sync(ds, &psa, cr, tx);
+       }
+}
+
+void
 dsl_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val,
     cred_t *cr, dmu_tx_t *tx)
 {
@@ -438,6 +464,7 @@ dsl_prop_set(const char *dsname, const char *propname,
     int intsz, int numints, const void *buf)
 {
        dsl_dataset_t *ds;
+       uint64_t version;
        int err;
        struct prop_set_arg psa;
 
@@ -447,15 +474,19 @@ dsl_prop_set(const char *dsname, const char *propname,
         */
        if (strlen(propname) >= ZAP_MAXNAMELEN)
                return (ENAMETOOLONG);
-       if (intsz * numints >= ZAP_MAXVALUELEN)
-               return (E2BIG);
 
        err = dsl_dataset_hold(dsname, FTAG, &ds);
        if (err)
                return (err);
 
+       version = spa_version(ds->ds_dir->dd_pool->dp_spa);
+       if (intsz * numints >= (version < SPA_VERSION_STMF_PROP ?
+           ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
+               dsl_dataset_rele(ds, FTAG);
+               return (E2BIG);
+       }
        if (dsl_dataset_is_snapshot(ds) &&
-           spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_SNAP_PROPS) {
+           version < SPA_VERSION_SNAP_PROPS) {
                dsl_dataset_rele(ds, FTAG);
                return (ENOTSUP);
        }
@@ -471,6 +502,50 @@ dsl_prop_set(const char *dsname, const char *propname,
        return (err);
 }
 
+int
+dsl_props_set(const char *dsname, nvlist_t *nvl)
+{
+       dsl_dataset_t *ds;
+       uint64_t version;
+       nvpair_t *elem = NULL;
+       int err;
+
+       if (err = dsl_dataset_hold(dsname, FTAG, &ds))
+               return (err);
+       /*
+        * Do these checks before the syncfunc, since it can't fail.
+        */
+       version = spa_version(ds->ds_dir->dd_pool->dp_spa);
+       while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
+               if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
+                       dsl_dataset_rele(ds, FTAG);
+                       return (ENAMETOOLONG);
+               }
+               if (nvpair_type(elem) == DATA_TYPE_STRING) {
+                       char *valstr;
+                       VERIFY(nvpair_value_string(elem, &valstr) == 0);
+                       if (strlen(valstr) >= (version <
+                           SPA_VERSION_STMF_PROP ?
+                           ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
+                               dsl_dataset_rele(ds, FTAG);
+                               return (E2BIG);
+                       }
+               }
+       }
+
+       if (dsl_dataset_is_snapshot(ds) &&
+           version < SPA_VERSION_SNAP_PROPS) {
+               dsl_dataset_rele(ds, FTAG);
+               return (ENOTSUP);
+       }
+
+       err = dsl_sync_task_do(ds->ds_dir->dd_pool,
+           NULL, dsl_props_set_sync, ds, nvl, 2);
+
+       dsl_dataset_rele(ds, FTAG);
+       return (err);
+}
+
 /*
  * Iterate over all properties for this dataset and return them in an nvlist.
  */