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,
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);
* 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);
/* 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);
* 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);
}
/*
* 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
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);
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);
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);
/*
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);
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
* 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) {
/* 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);
*/
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);
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;
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;
}
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)
{
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)
{
* 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);