Print this page
Matt's code review fixes

@@ -4091,23 +4091,26 @@
 }
 
 /*
  * Extract properties that cannot be set PRIOR to the receipt of a dataset.
  * For example, refquota cannot be set until after the receipt of a dataset,
- * because a prior snapshot may exceed the refquota, and refquotas only apply
- * to the current dataset.  The caller (libzfs) will manage these properties
- * somewhat as well to make sure they only come down with the last dataset in
- * a replication stream, but we still need to be safe about it here in
- * kernel-land.
+ * because in replication streams, an older/earlier snapshot may exceed the
+ * refquota.  We want to receive the older/earlier snapshot, but setting
+ * refquota pre-receipt will set the dsl's ACTUAL quota, which will prevent
+ * the older/earlier snapshot from being received (with EDQUOT).
+ *
+ * The ZFS test "zfs_receive_011_pos" demonstrates such a scenario.
+ *
+ * libzfs will need to be judicious handling errors encountered by props
+ * extracted by this function.
  */
 static nvlist_t *
 extract_delay_props(nvlist_t *props)
 {
         nvlist_t *delayprops;
         nvpair_t *nvp, *tmp;
         static const zfs_prop_t delayable[] = { ZFS_PROP_REFQUOTA, 0 };
-        boolean_t dontbother = B_TRUE;
         int i;
 
         VERIFY(nvlist_alloc(&delayprops, NV_UNIQUE_NAME, KM_SLEEP) == 0);
 
         for (nvp = nvlist_next_nvpair(props, NULL); nvp != NULL;

@@ -4125,15 +4128,14 @@
                 if (delayable[i] != 0) {
                         tmp = nvlist_prev_nvpair(props, nvp);
                         VERIFY(nvlist_add_nvpair(delayprops, nvp) == 0);
                         VERIFY(nvlist_remove_nvpair(props, nvp) == 0);
                         nvp = tmp;
-                        dontbother = B_FALSE;  /* Actually, do bother! */
                 }
         }
 
-        if (dontbother) {
+        if (nvlist_empty(delayprops)) {
                 nvlist_free(delayprops);
                 delayprops = NULL;
         }
         return (delayprops);
 }

@@ -4291,17 +4293,25 @@
                         (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED,
                             delayprops, errors);
                 }
         }
 
-        /* Merge delayprops back in with regular props, in case of errors. */
+        /*
+         * Merge delayed props back in with initial props, so errors (which is
+         * one list) can match up with the order in which props were set.
+         * Also, the error cleanup code only deals with the unsplit props
+         * list.
+         */
         if (delayprops != NULL) {
                 VERIFY(nvlist_merge(props, delayprops, 0) == 0);
                 nvlist_free(delayprops);
         }
 
-        /* Put the props error list into zc AFTER the delayprops. */
+        /*
+         * Now that all props, initial and delayed, are set, report the prop
+         * errors to the caller.
+         */
         if (zc->zc_nvlist_dst_size != 0 &&
             (nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 ||
             put_nvlist(zc, errors) != 0)) {
                 /*
                  * Caller made zc->zc_nvlist_dst less than the minimum expected