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