diff options
author | Tom Caputi <[email protected]> | 2018-06-06 13:16:41 -0400 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2018-06-06 10:16:41 -0700 |
commit | e7504d7a188b666a61a8c2d8c1ffaa9713f6cdfa (patch) | |
tree | ac99e6fad89bef6a6768a233c1fb99b827c01552 | |
parent | 6969afcefdfb49fb9c0fcf56240e6eb133a2c4a8 (diff) |
Raw receive functions must not decrypt data
This patch fixes a small bug found where receive_spill() sometimes
attempted to decrypt spill blocks when doing a raw receive. In
addition, this patch fixes another small issue in arc_buf_fill()'s
error handling where a decryption failure (which could be caused by
the first bug) would attempt to set the arc header's IO_ERROR flag
without holding the header's lock.
Reviewed-by: Matthew Thode <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Reviewed by: Matthew Ahrens <[email protected]>
Signed-off-by: Tom Caputi <[email protected]>
Closes #7564
Closes #7584
Closes #7592
-rw-r--r-- | include/sys/dmu.h | 3 | ||||
-rw-r--r-- | module/zfs/arc.c | 8 | ||||
-rw-r--r-- | module/zfs/dmu.c | 9 | ||||
-rw-r--r-- | module/zfs/dmu_send.c | 7 | ||||
-rw-r--r-- | module/zfs/sa.c | 2 |
5 files changed, 23 insertions, 6 deletions
diff --git a/include/sys/dmu.h b/include/sys/dmu.h index 119584365..e5950be93 100644 --- a/include/sys/dmu.h +++ b/include/sys/dmu.h @@ -514,7 +514,8 @@ int dmu_rm_spill(objset_t *, uint64_t, dmu_tx_t *); * Special spill buffer support used by "SA" framework */ -int dmu_spill_hold_by_bonus(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp); +int dmu_spill_hold_by_bonus(dmu_buf_t *bonus, uint32_t flags, void *tag, + dmu_buf_t **dbp); int dmu_spill_hold_by_dnode(dnode_t *dn, uint32_t flags, void *tag, dmu_buf_t **dbp); int dmu_spill_hold_existing(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp); diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 71bebf277..8f90afaa1 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -2144,7 +2144,11 @@ arc_buf_fill(arc_buf_t *buf, spa_t *spa, const zbookmark_phys_t *zb, error = arc_fill_hdr_crypt(hdr, hash_lock, spa, zb, !!(flags & ARC_FILL_NOAUTH)); if (error != 0) { + if (hash_lock != NULL) + mutex_enter(hash_lock); arc_hdr_set_flags(hdr, ARC_FLAG_IO_ERROR); + if (hash_lock != NULL) + mutex_exit(hash_lock); return (error); } } @@ -2247,7 +2251,11 @@ arc_buf_fill(arc_buf_t *buf, spa_t *spa, const zbookmark_phys_t *zb, "hdr %p, compress %d, psize %d, lsize %d", hdr, arc_hdr_get_compress(hdr), HDR_GET_PSIZE(hdr), HDR_GET_LSIZE(hdr)); + if (hash_lock != NULL) + mutex_enter(hash_lock); arc_hdr_set_flags(hdr, ARC_FLAG_IO_ERROR); + if (hash_lock != NULL) + mutex_exit(hash_lock); return (SET_ERROR(EIO)); } } diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index 32a8fd319..1cb967641 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -459,15 +459,20 @@ dmu_spill_hold_existing(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp) } int -dmu_spill_hold_by_bonus(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp) +dmu_spill_hold_by_bonus(dmu_buf_t *bonus, uint32_t flags, void *tag, + dmu_buf_t **dbp) { dmu_buf_impl_t *db = (dmu_buf_impl_t *)bonus; dnode_t *dn; int err; + uint32_t db_flags = DB_RF_CANFAIL; + + if (flags & DMU_READ_NO_DECRYPT) + db_flags |= DB_RF_NO_DECRYPT; DB_DNODE_ENTER(db); dn = DB_DNODE(db); - err = dmu_spill_hold_by_dnode(dn, DB_RF_CANFAIL, tag, dbp); + err = dmu_spill_hold_by_dnode(dn, db_flags, tag, dbp); DB_DNODE_EXIT(db); return (err); diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index 9b6160254..3dfe0b73e 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -2936,6 +2936,7 @@ receive_spill(struct receive_writer_arg *rwa, struct drr_spill *drrs, dmu_tx_t *tx; dmu_buf_t *db, *db_spill; int err; + uint32_t flags = 0; if (drrs->drr_length < SPA_MINBLOCKSIZE || drrs->drr_length > spa_maxblocksize(dmu_objset_spa(rwa->os))) @@ -2946,6 +2947,8 @@ receive_spill(struct receive_writer_arg *rwa, struct drr_spill *drrs, drrs->drr_compressiontype >= ZIO_COMPRESS_FUNCTIONS || drrs->drr_compressed_size == 0) return (SET_ERROR(EINVAL)); + + flags |= DMU_READ_NO_DECRYPT; } if (dmu_object_info(rwa->os, drrs->drr_object, NULL) != 0) @@ -2955,7 +2958,8 @@ receive_spill(struct receive_writer_arg *rwa, struct drr_spill *drrs, rwa->max_object = drrs->drr_object; VERIFY0(dmu_bonus_hold(rwa->os, drrs->drr_object, FTAG, &db)); - if ((err = dmu_spill_hold_by_bonus(db, FTAG, &db_spill)) != 0) { + if ((err = dmu_spill_hold_by_bonus(db, DMU_READ_NO_DECRYPT, FTAG, + &db_spill)) != 0) { dmu_buf_rele(db, FTAG); return (err); } @@ -2971,7 +2975,6 @@ receive_spill(struct receive_writer_arg *rwa, struct drr_spill *drrs, dmu_tx_abort(tx); return (err); } - dmu_buf_will_dirty(db_spill, tx); if (db_spill->db_size < drrs->drr_length) VERIFY(0 == dbuf_spill_set_blksz(db_spill, diff --git a/module/zfs/sa.c b/module/zfs/sa.c index 5b6b90642..75f7f8d96 100644 --- a/module/zfs/sa.c +++ b/module/zfs/sa.c @@ -698,7 +698,7 @@ sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count, boolean_t dummy; if (hdl->sa_spill == NULL) { - VERIFY(dmu_spill_hold_by_bonus(hdl->sa_bonus, NULL, + VERIFY(dmu_spill_hold_by_bonus(hdl->sa_bonus, 0, NULL, &hdl->sa_spill) == 0); } dmu_buf_will_dirty(hdl->sa_spill, tx); |