Skip to content

Commit df6ddaf

Browse files
Tom Caputilundman
Tom Caputi
authored andcommitted
Send / Recv Fixes following b52563
This patch fixes several issues discovered after the encryption patch was merged: Fixed a bug where encrypted datasets could attempt to receive embedded data records. Fixed a bug where dirty records created by the recv code wasn't properly setting the dr_raw flag. Fixed a typo where a dmu_tx_commit() was changed to dmu_tx_abort() Fixed a few error handling bugs unrelated to the encryption patch in dmu_recv_stream() Signed-off-by: Tom Caputi <[email protected]>
1 parent 1b0174c commit df6ddaf

File tree

6 files changed

+87
-47
lines changed

6 files changed

+87
-47
lines changed

usr/src/lib/libzfs/common/libzfs_sendrecv.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3537,6 +3537,8 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
35373537
DMU_BACKUP_FEATURE_RESUMING;
35383538
boolean_t raw = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
35393539
DMU_BACKUP_FEATURE_RAW;
3540+
boolean_t embedded = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
3541+
DMU_BACKUP_FEATURE_EMBED_DATA;
35403542
stream_wantsnewfs = (drrb->drr_fromguid == NULL ||
35413543
(drrb->drr_flags & DRR_FLAG_CLONE) || originsnap) && !resuming;
35423544

@@ -3922,6 +3924,10 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
39223924
*cp = '@';
39233925
break;
39243926
case EINVAL:
3927+
if (embedded && !raw)
3928+
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3929+
"incompatible embedded data stream "
3930+
"feature with encrypted receive."));
39253931
(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
39263932
break;
39273933
case ECKSUM:

usr/src/man/man1m/zfs.1m

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3086,7 +3086,8 @@ feature enabled.
30863086
If the
30873087
.Sy lz4_compress
30883088
feature is active on the sending system, then the receiving system must have
3089-
that feature enabled as well.
3089+
that feature enabled as well. Note that streams generated using this flag are
3090+
unable to be received into an encrypted dataset.
30903091
See
30913092
.Xr zpool-features 5
30923093
for details on ZFS feature flags and the

usr/src/uts/common/fs/zfs/dmu.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2018,6 +2018,25 @@ dmu_object_set_compress(objset_t *os, uint64_t object, uint8_t compress,
20182018
dnode_rele(dn, FTAG);
20192019
}
20202020

2021+
/*
2022+
* Dirty an object and set the dirty record's raw flag. This is used
2023+
* when writing raw data to an object that will not effect the
2024+
* encryption parameters, specifically during raw receives.
2025+
*/
2026+
int
2027+
dmu_object_dirty_raw(objset_t *os, uint64_t object, dmu_tx_t *tx)
2028+
{
2029+
dnode_t *dn;
2030+
int err;
2031+
2032+
err = dnode_hold(os, object, FTAG, &dn);
2033+
if (err)
2034+
return (err);
2035+
dmu_buf_will_change_crypt_params((dmu_buf_t *)dn->dn_dbuf, tx);
2036+
dnode_rele(dn, FTAG);
2037+
return (err);
2038+
}
2039+
20212040
int zfs_mdcomp_disable = 0;
20222041

20232042
/*

usr/src/uts/common/fs/zfs/dmu_send.c

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -293,12 +293,11 @@ dump_write(dmu_sendarg_t *dsp, dmu_object_type_t type, uint64_t object,
293293
ASSERT(BP_IS_PROTECTED(bp));
294294

295295
/*
296-
* This is a raw protected block so we set the encrypted
297-
* flag. We need to pass along everything the receiving
298-
* side will need to interpret this block, including the
299-
* byteswap, salt, IV, and MAC.
296+
* This is a raw protected block so we need to pass
297+
* along everything the receiving side will need to
298+
* interpret this block, including the byteswap, salt,
299+
* IV, and MAC.
300300
*/
301-
drrw->drr_flags |= DRR_RAW_ENCRYPTED;
302301
if (BP_SHOULD_BYTESWAP(bp))
303302
drrw->drr_flags |= DRR_RAW_BYTESWAP;
304303
zio_crypt_decode_params_bp(bp, drrw->drr_salt,
@@ -401,9 +400,9 @@ dump_spill(dmu_sendarg_t *dsp, const blkptr_t *bp, uint64_t object, void *data)
401400
drrs->drr_toguid = dsp->dsa_toguid;
402401

403402
/* handle raw send fields */
404-
if ((dsp->dsa_featureflags & DMU_BACKUP_FEATURE_RAW) != 0 &&
405-
BP_IS_PROTECTED(bp)) {
406-
drrs->drr_flags |= DRR_RAW_ENCRYPTED;
403+
if (dsp->dsa_featureflags & DMU_BACKUP_FEATURE_RAW) {
404+
ASSERT(BP_IS_PROTECTED(bp));
405+
407406
if (BP_SHOULD_BYTESWAP(bp))
408407
drrs->drr_flags |= DRR_RAW_BYTESWAP;
409408
drrs->drr_compressiontype = BP_GET_COMPRESS(bp);
@@ -508,9 +507,9 @@ dump_dnode(dmu_sendarg_t *dsp, const blkptr_t *bp, uint64_t object,
508507
drro->drr_blksz > SPA_OLD_MAXBLOCKSIZE)
509508
drro->drr_blksz = SPA_OLD_MAXBLOCKSIZE;
510509

511-
if ((dsp->dsa_featureflags & DMU_BACKUP_FEATURE_RAW) &&
512-
BP_IS_PROTECTED(bp)) {
513-
drro->drr_flags |= DRR_RAW_ENCRYPTED;
510+
if ((dsp->dsa_featureflags & DMU_BACKUP_FEATURE_RAW)) {
511+
ASSERT(BP_IS_ENCRYPTED(bp));
512+
514513
if (BP_SHOULD_BYTESWAP(bp))
515514
drro->drr_flags |= DRR_RAW_BYTESWAP;
516515

@@ -567,7 +566,6 @@ dump_object_range(dmu_sendarg_t *dsp, const blkptr_t *bp, uint64_t firstobj,
567566
drror->drr_firstobj = firstobj;
568567
drror->drr_numslots = numslots;
569568
drror->drr_toguid = dsp->dsa_toguid;
570-
drror->drr_flags |= DRR_RAW_ENCRYPTED;
571569
if (BP_SHOULD_BYTESWAP(bp))
572570
drror->drr_flags |= DRR_RAW_BYTESWAP;
573571
zio_crypt_decode_params_bp(bp, drror->drr_salt, drror->drr_iv);
@@ -1684,15 +1682,13 @@ dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
16841682
return (error);
16851683
}
16861684
if (!origin->ds_is_snapshot) {
1687-
dsl_dataset_rele_flags(origin,
1688-
DS_HOLD_FLAG_DECRYPT, FTAG);
1685+
dsl_dataset_rele_flags(origin, dsflags, FTAG);
16891686
dsl_dataset_rele_flags(ds, dsflags, FTAG);
16901687
return (SET_ERROR(EINVAL));
16911688
}
16921689
if (dsl_dataset_phys(origin)->ds_guid != fromguid &&
16931690
fromguid != 0) {
1694-
dsl_dataset_rele_flags(origin,
1695-
DS_HOLD_FLAG_DECRYPT, FTAG);
1691+
dsl_dataset_rele_flags(origin, dsflags, FTAG);
16961692
dsl_dataset_rele_flags(ds, dsflags, FTAG);
16971693
return (SET_ERROR(ENODEV));
16981694
}
@@ -2081,6 +2077,7 @@ struct receive_writer_arg {
20812077
/* A map from guid to dataset to help handle dedup'd streams. */
20822078
avl_tree_t *guid_to_ds_map;
20832079
boolean_t resumable;
2080+
boolean_t raw;
20842081
uint64_t last_object, last_offset;
20852082
uint64_t bytes_read; /* bytes read when current record created */
20862083
};
@@ -2115,6 +2112,7 @@ struct receive_arg {
21152112
zio_cksum_t prev_cksum;
21162113
int err;
21172114
boolean_t byteswap;
2115+
boolean_t raw;
21182116
uint64_t featureflags;
21192117
/* Sorted list of objects not to issue prefetches for. */
21202118
struct objlist ignore_objlist;
@@ -2359,7 +2357,7 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
23592357
return (SET_ERROR(EINVAL));
23602358
}
23612359

2362-
if (DRR_IS_RAW_ENCRYPTED(drro->drr_flags)) {
2360+
if (rwa->raw) {
23632361
if (drro->drr_raw_bonuslen < drro->drr_bonuslen ||
23642362
drro->drr_indblkshift > SPA_MAXBLOCKSHIFT ||
23652363
drro->drr_nlevels > DN_MAX_LEVELS ||
@@ -2394,13 +2392,12 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
23942392
drro->drr_bonuslen);
23952393

23962394
/* nblkptr will be bounded by the bonus size and type */
2397-
if (DRR_IS_RAW_ENCRYPTED(drro->drr_flags) &&
2398-
nblkptr != drro->drr_nblkptr)
2395+
if (rwa->raw && nblkptr != drro->drr_nblkptr)
23992396
return (SET_ERROR(EINVAL));
24002397

24012398
if (drro->drr_blksz != doi.doi_data_block_size ||
24022399
nblkptr < doi.doi_nblkptr ||
2403-
(DRR_IS_RAW_ENCRYPTED(drro->drr_flags) &&
2400+
(rwa->raw &&
24042401
(indblksz != doi.doi_metadata_block_size ||
24052402
drro->drr_nlevels < doi.doi_indirection))) {
24062403
err = dmu_free_long_range(rwa->os, drro->drr_object,
@@ -2438,13 +2435,16 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
24382435
return (SET_ERROR(EINVAL));
24392436
}
24402437

2438+
if (rwa->raw)
2439+
VERIFY0(dmu_object_dirty_raw(rwa->os, drro->drr_object, tx));
2440+
24412441
dmu_object_set_checksum(rwa->os, drro->drr_object,
24422442
drro->drr_checksumtype, tx);
24432443
dmu_object_set_compress(rwa->os, drro->drr_object,
24442444
drro->drr_compress, tx);
24452445

24462446
/* handle more restrictive dnode structuring for raw recvs */
2447-
if (DRR_IS_RAW_ENCRYPTED(drro->drr_flags)) {
2447+
if (rwa->raw) {
24482448
/*
24492449
* Set the indirect block shift and nlevels. This will not fail
24502450
* because we ensured all of the blocks were free earlier if
@@ -2460,7 +2460,7 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
24602460
dmu_buf_t *db;
24612461
uint32_t flags = DMU_READ_NO_PREFETCH;
24622462

2463-
if (DRR_IS_RAW_ENCRYPTED(drro->drr_flags))
2463+
if (rwa->raw)
24642464
flags |= DMU_READ_NO_DECRYPT;
24652465

24662466
VERIFY0(dmu_bonus_hold_impl(rwa->os, drro->drr_object,
@@ -2474,7 +2474,7 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
24742474
* Raw bonus buffers have their byteorder determined by the
24752475
* DRR_OBJECT_RANGE record.
24762476
*/
2477-
if (rwa->byteswap && !DRR_IS_RAW_ENCRYPTED(drro->drr_flags)) {
2477+
if (rwa->byteswap && !rwa->raw) {
24782478
dmu_object_byteswap_t byteswap =
24792479
DMU_OT_BYTESWAP(drro->drr_bonustype);
24802480
dmu_ot_byteswap[byteswap].ob_func(db->db_data,
@@ -2550,6 +2550,10 @@ receive_write(struct receive_writer_arg *rwa, struct drr_write *drrw,
25502550
dmu_tx_abort(tx);
25512551
return (err);
25522552
}
2553+
2554+
if (rwa->raw)
2555+
VERIFY0(dmu_object_dirty_raw(rwa->os, drrw->drr_object, tx));
2556+
25532557
if (rwa->byteswap && !arc_is_encrypted(abuf) &&
25542558
arc_get_compression(abuf) == ZIO_COMPRESS_OFF) {
25552559
dmu_object_byteswap_t byteswap =
@@ -2616,9 +2620,8 @@ receive_write_byref(struct receive_writer_arg *rwa,
26162620
ref_os = rwa->os;
26172621
}
26182622

2619-
if (DRR_IS_RAW_ENCRYPTED(drrwbr->drr_flags)) {
2623+
if (rwa->raw)
26202624
flags |= DMU_READ_NO_DECRYPT;
2621-
}
26222625

26232626
/* may return either a regular db or an encrypted one */
26242627
err = dmu_buf_hold(ref_os, drrwbr->drr_refobject,
@@ -2636,7 +2639,8 @@ receive_write_byref(struct receive_writer_arg *rwa,
26362639
return (err);
26372640
}
26382641

2639-
if (DRR_IS_RAW_ENCRYPTED(drrwbr->drr_flags)) {
2642+
if (rwa->raw) {
2643+
VERIFY0(dmu_object_dirty_raw(rwa->os, drrwbr->drr_object, tx));
26402644
dmu_copy_from_buf(rwa->os, drrwbr->drr_object,
26412645
drrwbr->drr_offset, dbp, tx);
26422646
} else {
@@ -2702,7 +2706,7 @@ receive_spill(struct receive_writer_arg *rwa, struct drr_spill *drrs,
27022706
drrs->drr_length > spa_maxblocksize(dmu_objset_spa(rwa->os)))
27032707
return (SET_ERROR(EINVAL));
27042708

2705-
if (DRR_IS_RAW_ENCRYPTED(drrs->drr_flags)) {
2709+
if (rwa->raw) {
27062710
if (!DMU_OT_IS_VALID(drrs->drr_type) ||
27072711
drrs->drr_compressiontype >= ZIO_COMPRESS_FUNCTIONS ||
27082712
drrs->drr_compressed_size == 0)
@@ -2730,6 +2734,8 @@ receive_spill(struct receive_writer_arg *rwa, struct drr_spill *drrs,
27302734
return (err);
27312735
}
27322736
dmu_buf_will_dirty(db_spill, tx);
2737+
if (rwa->raw)
2738+
VERIFY0(dmu_object_dirty_raw(rwa->os, drrs->drr_object, tx));
27332739

27342740
if (db_spill->db_size < drrs->drr_length)
27352741
VERIFY(0 == dbuf_spill_set_blksz(db_spill,
@@ -2795,7 +2801,7 @@ receive_object_range(struct receive_writer_arg *rwa,
27952801
*/
27962802
if (drror->drr_numslots != DNODES_PER_BLOCK ||
27972803
P2PHASE(drror->drr_firstobj, DNODES_PER_BLOCK) != 0 ||
2798-
!DRR_IS_RAW_ENCRYPTED(drror->drr_flags))
2804+
!rwa->raw)
27992805
return (SET_ERROR(EINVAL));
28002806

28012807
offset = drror->drr_firstobj * sizeof (dnode_phys_t);
@@ -3075,7 +3081,7 @@ receive_read_record(struct receive_arg *ra)
30753081
arc_buf_t *abuf;
30763082
boolean_t is_meta = DMU_OT_IS_METADATA(drrw->drr_type);
30773083

3078-
if (DRR_IS_RAW_ENCRYPTED(drrw->drr_flags)) {
3084+
if (ra->raw) {
30793085
boolean_t byteorder = ZFS_HOST_BYTEORDER ^
30803086
!!DRR_IS_RAW_BYTESWAPPED(drrw->drr_flags) ^
30813087
ra->byteswap;
@@ -3159,7 +3165,7 @@ receive_read_record(struct receive_arg *ra)
31593165
int len = DRR_SPILL_PAYLOAD_SIZE(drrs);
31603166

31613167
/* DRR_SPILL records are either raw or uncompressed */
3162-
if (DRR_IS_RAW_ENCRYPTED(drrs->drr_flags)) {
3168+
if (ra->raw) {
31633169
boolean_t byteorder = ZFS_HOST_BYTEORDER ^
31643170
!!DRR_IS_RAW_BYTESWAPPED(drrs->drr_flags) ^
31653171
ra->byteswap;
@@ -3360,6 +3366,7 @@ dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp,
33603366
nvlist_t *begin_nvl = NULL;
33613367

33623368
ra.byteswap = drc->drc_byteswap;
3369+
ra.raw = drc->drc_raw;
33633370
ra.cksum = drc->drc_cksum;
33643371
ra.vp = vp;
33653372
ra.voff = *voffp;
@@ -3387,16 +3394,23 @@ dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp,
33873394
featureflags = DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo);
33883395
ra.featureflags = featureflags;
33893396

3397+
/* embedded data is incompatible with encrypted datasets */
3398+
if (ra.os->os_encrypted &&
3399+
(featureflags & DMU_BACKUP_FEATURE_EMBED_DATA)) {
3400+
err = SET_ERROR(EINVAL);
3401+
goto out;
3402+
}
3403+
33903404
/* if this stream is dedup'ed, set up the avl tree for guid mapping */
33913405
if (featureflags & DMU_BACKUP_FEATURE_DEDUP) {
33923406
minor_t minor;
33933407

33943408
if (cleanup_fd == -1) {
3395-
ra.err = SET_ERROR(EBADF);
3409+
err = SET_ERROR(EBADF);
33963410
goto out;
33973411
}
3398-
ra.err = zfs_onexit_fd_hold(cleanup_fd, &minor);
3399-
if (ra.err != 0) {
3412+
err = zfs_onexit_fd_hold(cleanup_fd, &minor);
3413+
if (err != 0) {
34003414
cleanup_fd = -1;
34013415
goto out;
34023416
}
@@ -3410,12 +3424,12 @@ dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp,
34103424
err = zfs_onexit_add_cb(minor,
34113425
free_guid_map_onexit, rwa.guid_to_ds_map,
34123426
action_handlep);
3413-
if (ra.err != 0)
3427+
if (err != 0)
34143428
goto out;
34153429
} else {
34163430
err = zfs_onexit_cb_data(minor, *action_handlep,
34173431
(void **)&rwa.guid_to_ds_map);
3418-
if (ra.err != 0)
3432+
if (err != 0)
34193433
goto out;
34203434
}
34213435

@@ -3471,6 +3485,7 @@ dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp,
34713485
rwa.os = ra.os;
34723486
rwa.byteswap = drc->drc_byteswap;
34733487
rwa.resumable = drc->drc_resumable;
3488+
rwa.raw = drc->drc_raw;
34743489

34753490
(void) thread_create(NULL, 0, receive_writer_thread, &rwa, 0, curproc,
34763491
TS_RUN, minclsyspri);

usr/src/uts/common/fs/zfs/sys/dmu.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,8 +437,9 @@ void dmu_object_set_checksum(objset_t *os, uint64_t object, uint8_t checksum,
437437
void dmu_object_set_compress(objset_t *os, uint64_t object, uint8_t compress,
438438
dmu_tx_t *tx);
439439

440-
void
441-
dmu_write_embedded(objset_t *os, uint64_t object, uint64_t offset,
440+
int dmu_object_dirty_raw(objset_t *os, uint64_t object, dmu_tx_t *tx);
441+
442+
void dmu_write_embedded(objset_t *os, uint64_t object, uint64_t offset,
442443
void *data, uint8_t etype, uint8_t comp, int uncompressed_size,
443444
int compressed_size, int byteorder, dmu_tx_t *tx);
444445

0 commit comments

Comments
 (0)