aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sys/arc.h2
-rw-r--r--include/sys/spa.h3
-rw-r--r--include/sys/zio.h9
-rw-r--r--module/zfs/arc.c34
-rw-r--r--module/zfs/dbuf.c20
-rw-r--r--module/zfs/dmu_objset.c6
-rw-r--r--module/zfs/dmu_send.c6
-rw-r--r--module/zfs/zfs_fm.c9
-rw-r--r--module/zfs/zio.c2
9 files changed, 68 insertions, 23 deletions
diff --git a/include/sys/arc.h b/include/sys/arc.h
index de280362d..9d6bab505 100644
--- a/include/sys/arc.h
+++ b/include/sys/arc.h
@@ -237,7 +237,7 @@ boolean_t arc_is_unauthenticated(arc_buf_t *buf);
enum zio_compress arc_get_compression(arc_buf_t *buf);
void arc_get_raw_params(arc_buf_t *buf, boolean_t *byteorder, uint8_t *salt,
uint8_t *iv, uint8_t *mac);
-int arc_untransform(arc_buf_t *buf, spa_t *spa, uint64_t dsobj,
+int arc_untransform(arc_buf_t *buf, spa_t *spa, const zbookmark_phys_t *zb,
boolean_t in_place);
void arc_convert_to_raw(arc_buf_t *buf, uint64_t dsobj, boolean_t byteorder,
dmu_object_type_t ot, const uint8_t *salt, const uint8_t *iv,
diff --git a/include/sys/spa.h b/include/sys/spa.h
index 62832eff0..4a1b1410f 100644
--- a/include/sys/spa.h
+++ b/include/sys/spa.h
@@ -1024,7 +1024,8 @@ extern void spa_history_log_internal_dd(dsl_dir_t *dd, const char *operation,
struct zbookmark_phys;
extern void spa_log_error(spa_t *spa, const zbookmark_phys_t *zb);
extern void zfs_ereport_post(const char *class, spa_t *spa, vdev_t *vd,
- zbookmark_phys_t *zb, zio_t *zio, uint64_t stateoroffset, uint64_t length);
+ const zbookmark_phys_t *zb, zio_t *zio, uint64_t stateoroffset,
+ uint64_t length);
extern nvlist_t *zfs_event_create(spa_t *spa, vdev_t *vd, const char *type,
const char *name, nvlist_t *aux);
extern void zfs_post_remove(spa_t *spa, vdev_t *vd);
diff --git a/include/sys/zio.h b/include/sys/zio.h
index 9d3adb7f5..be8e18b4b 100644
--- a/include/sys/zio.h
+++ b/include/sys/zio.h
@@ -649,8 +649,8 @@ extern hrtime_t zio_handle_io_delay(zio_t *zio);
* Checksum ereport functions
*/
extern void zfs_ereport_start_checksum(spa_t *spa, vdev_t *vd,
- zbookmark_phys_t *zb, struct zio *zio, uint64_t offset, uint64_t length,
- void *arg, struct zio_bad_cksum *info);
+ const zbookmark_phys_t *zb, struct zio *zio, uint64_t offset,
+ uint64_t length, void *arg, struct zio_bad_cksum *info);
extern void zfs_ereport_finish_checksum(zio_cksum_report_t *report,
const abd_t *good_data, const abd_t *bad_data, boolean_t drop_if_identical);
@@ -658,8 +658,9 @@ extern void zfs_ereport_free_checksum(zio_cksum_report_t *report);
/* If we have the good data in hand, this function can be used */
extern void zfs_ereport_post_checksum(spa_t *spa, vdev_t *vd,
- zbookmark_phys_t *zb, struct zio *zio, uint64_t offset, uint64_t length,
- const abd_t *good_data, const abd_t *bad_data, struct zio_bad_cksum *info);
+ const zbookmark_phys_t *zb, struct zio *zio, uint64_t offset,
+ uint64_t length, const abd_t *good_data, const abd_t *bad_data,
+ struct zio_bad_cksum *info);
/* Called from spa_sync(), but primarily an injection handler */
extern void spa_handle_ignored_writes(spa_t *spa);
diff --git a/module/zfs/arc.c b/module/zfs/arc.c
index 81da36a42..893e42d31 100644
--- a/module/zfs/arc.c
+++ b/module/zfs/arc.c
@@ -2260,14 +2260,27 @@ byteswap:
* callers.
*/
int
-arc_untransform(arc_buf_t *buf, spa_t *spa, uint64_t dsobj, boolean_t in_place)
+arc_untransform(arc_buf_t *buf, spa_t *spa, const zbookmark_phys_t *zb,
+ boolean_t in_place)
{
+ int ret;
arc_fill_flags_t flags = 0;
if (in_place)
flags |= ARC_FILL_IN_PLACE;
- return (arc_buf_fill(buf, spa, dsobj, flags));
+ ret = arc_buf_fill(buf, spa, zb->zb_objset, flags);
+ if (ret == ECKSUM) {
+ /*
+ * Convert authentication and decryption errors to EIO
+ * (and generate an ereport) before leaving the ARC.
+ */
+ ret = SET_ERROR(EIO);
+ zfs_ereport_post(FM_EREPORT_ZFS_AUTHENTICATION,
+ spa, NULL, zb, NULL, 0, 0);
+ }
+
+ return (ret);
}
/*
@@ -5810,7 +5823,8 @@ arc_read_done(zio_t *zio)
* Assert non-speculative zios didn't fail because an
* encryption key wasn't loaded
*/
- ASSERT((zio->io_flags & ZIO_FLAG_SPECULATIVE) || error == 0);
+ ASSERT((zio->io_flags & ZIO_FLAG_SPECULATIVE) ||
+ error != ENOENT);
/*
* If we failed to decrypt, report an error now (as the zio
@@ -6033,12 +6047,24 @@ top:
rc = arc_buf_alloc_impl(hdr, spa, zb->zb_objset,
private, encrypted_read, compressed_read,
noauth_read, B_TRUE, &buf);
+ if (rc == ECKSUM) {
+ /*
+ * Convert authentication and decryption errors
+ * to EIO (and generate an ereport) before
+ * leaving the ARC.
+ */
+ rc = SET_ERROR(EIO);
+ zfs_ereport_post(FM_EREPORT_ZFS_AUTHENTICATION,
+ spa, NULL, zb, NULL, 0, 0);
+ }
if (rc != 0) {
arc_buf_destroy(buf, private);
buf = NULL;
}
- ASSERT((zio_flags & ZIO_FLAG_SPECULATIVE) || rc == 0);
+ /* assert any errors weren't due to unloaded keys */
+ ASSERT((zio_flags & ZIO_FLAG_SPECULATIVE) ||
+ rc != ENOENT);
} else if (*arc_flags & ARC_FLAG_PREFETCH &&
refcount_count(&hdr->b_l1hdr.b_refcnt) == 0) {
arc_hdr_set_flags(hdr, ARC_FLAG_PREFETCH);
diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c
index 0ecdbd583..18edd7834 100644
--- a/module/zfs/dbuf.c
+++ b/module/zfs/dbuf.c
@@ -1194,8 +1194,10 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
DMU_OT_IS_ENCRYPTED(dn->dn_bonustype) &&
(flags & DB_RF_NO_DECRYPT) == 0 &&
arc_is_encrypted(dn_buf)) {
+ SET_BOOKMARK(&zb, dmu_objset_id(db->db_objset),
+ DMU_META_DNODE_OBJECT, 0, dn->dn_dbuf->db_blkid);
err = arc_untransform(dn_buf, dn->dn_objset->os_spa,
- dmu_objset_id(dn->dn_objset), B_TRUE);
+ &zb, B_TRUE);
if (err != 0) {
DB_DNODE_EXIT(db);
mutex_exit(&db->db_mtx);
@@ -1264,8 +1266,7 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
if (DBUF_IS_L2CACHEABLE(db))
aflags |= ARC_FLAG_L2CACHE;
- SET_BOOKMARK(&zb, db->db_objset->os_dsl_dataset ?
- db->db_objset->os_dsl_dataset->ds_object : DMU_META_OBJSET,
+ SET_BOOKMARK(&zb, dmu_objset_id(db->db_objset),
db->db.db_object, db->db_level, db->db_blkid);
/*
@@ -1409,9 +1410,12 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
if (db->db_buf != NULL && (flags & DB_RF_NO_DECRYPT) == 0 &&
(arc_is_encrypted(db->db_buf) ||
arc_get_compression(db->db_buf) != ZIO_COMPRESS_OFF)) {
+ zbookmark_phys_t zb;
+
+ SET_BOOKMARK(&zb, dmu_objset_id(db->db_objset),
+ db->db.db_object, db->db_level, db->db_blkid);
dbuf_fix_old_data(db, spa_syncing_txg(spa));
- err = arc_untransform(db->db_buf, spa,
- dmu_objset_id(db->db_objset), B_FALSE);
+ err = arc_untransform(db->db_buf, spa, &zb, B_FALSE);
dbuf_set_data(db, db->db_buf);
}
mutex_exit(&db->db_mtx);
@@ -3458,6 +3462,8 @@ dbuf_check_crypt(dbuf_dirty_record_t *dr)
ASSERT(MUTEX_HELD(&db->db_mtx));
if (!dr->dt.dl.dr_raw && arc_is_encrypted(db->db_buf)) {
+ zbookmark_phys_t zb;
+
/*
* Unfortunately, there is currently no mechanism for
* syncing context to handle decryption errors. An error
@@ -3465,8 +3471,10 @@ dbuf_check_crypt(dbuf_dirty_record_t *dr)
* changed a dnode block and updated the associated
* checksums going up the block tree.
*/
+ SET_BOOKMARK(&zb, dmu_objset_id(db->db_objset),
+ db->db.db_object, db->db_level, db->db_blkid);
err = arc_untransform(db->db_buf, db->db_objset->os_spa,
- dmu_objset_id(db->db_objset), B_TRUE);
+ &zb, B_TRUE);
if (err)
panic("Invalid dnode block MAC");
} else if (dr->dt.dl.dr_raw) {
diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c
index de7bbf894..8efc31546 100644
--- a/module/zfs/dmu_objset.c
+++ b/module/zfs/dmu_objset.c
@@ -686,8 +686,12 @@ dmu_objset_own_impl(dsl_dataset_t *ds, dmu_objset_type_t type,
/* if we are decrypting, we can now check MACs in os->os_phys_buf */
if (decrypt && arc_is_unauthenticated((*osp)->os_phys_buf)) {
+ zbookmark_phys_t zb;
+
+ SET_BOOKMARK(&zb, ds->ds_object, ZB_ROOT_OBJECT,
+ ZB_ROOT_LEVEL, ZB_ROOT_BLKID);
err = arc_untransform((*osp)->os_phys_buf, (*osp)->os_spa,
- ds->ds_object, B_FALSE);
+ &zb, B_FALSE);
if (err != 0)
return (err);
diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c
index 36e412bdf..e0e5fe22c 100644
--- a/module/zfs/dmu_send.c
+++ b/module/zfs/dmu_send.c
@@ -983,8 +983,12 @@ dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *to_ds,
*/
if (!rawok && os->os_encrypted &&
arc_is_unauthenticated(os->os_phys_buf)) {
+ zbookmark_phys_t zb;
+
+ SET_BOOKMARK(&zb, to_ds->ds_object, ZB_ROOT_OBJECT,
+ ZB_ROOT_LEVEL, ZB_ROOT_BLKID);
err = arc_untransform(os->os_phys_buf, os->os_spa,
- to_ds->ds_object, B_FALSE);
+ &zb, B_FALSE);
if (err != 0) {
dsl_pool_rele(dp, tag);
return (err);
diff --git a/module/zfs/zfs_fm.c b/module/zfs/zfs_fm.c
index b3c38f5b2..e28e46e7a 100644
--- a/module/zfs/zfs_fm.c
+++ b/module/zfs/zfs_fm.c
@@ -142,7 +142,7 @@ zfs_is_ratelimiting_event(const char *subclass, vdev_t *vd)
static void
zfs_ereport_start(nvlist_t **ereport_out, nvlist_t **detector_out,
- const char *subclass, spa_t *spa, vdev_t *vd, zbookmark_phys_t *zb,
+ const char *subclass, spa_t *spa, vdev_t *vd, const zbookmark_phys_t *zb,
zio_t *zio, uint64_t stateoroffset, uint64_t size)
{
nvlist_t *ereport, *detector;
@@ -767,7 +767,8 @@ annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info,
void
zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd,
- zbookmark_phys_t *zb, zio_t *zio, uint64_t stateoroffset, uint64_t size)
+ const zbookmark_phys_t *zb, zio_t *zio, uint64_t stateoroffset,
+ uint64_t size)
{
#ifdef _KERNEL
nvlist_t *ereport = NULL;
@@ -788,7 +789,7 @@ zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd,
}
void
-zfs_ereport_start_checksum(spa_t *spa, vdev_t *vd, zbookmark_phys_t *zb,
+zfs_ereport_start_checksum(spa_t *spa, vdev_t *vd, const zbookmark_phys_t *zb,
struct zio *zio, uint64_t offset, uint64_t length, void *arg,
zio_bad_cksum_t *info)
{
@@ -874,7 +875,7 @@ zfs_ereport_free_checksum(zio_cksum_report_t *rpt)
void
-zfs_ereport_post_checksum(spa_t *spa, vdev_t *vd, zbookmark_phys_t *zb,
+zfs_ereport_post_checksum(spa_t *spa, vdev_t *vd, const zbookmark_phys_t *zb,
struct zio *zio, uint64_t offset, uint64_t length,
const abd_t *good_data, const abd_t *bad_data, zio_bad_cksum_t *zbc)
{
diff --git a/module/zfs/zio.c b/module/zfs/zio.c
index 44cf984d0..c6379bfd4 100644
--- a/module/zfs/zio.c
+++ b/module/zfs/zio.c
@@ -506,7 +506,7 @@ error:
* the io_error. If this was not a speculative zio, create an ereport.
*/
if (ret == ECKSUM) {
- ret = SET_ERROR(EIO);
+ zio->io_error = SET_ERROR(EIO);
if ((zio->io_flags & ZIO_FLAG_SPECULATIVE) == 0) {
zfs_ereport_post(FM_EREPORT_ZFS_AUTHENTICATION,
spa, NULL, &zio->io_bookmark, zio, 0, 0);