mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 10:37:35 +03:00
OpenZFS 6950 - ARC should cache compressed data
Authored by: George Wilson <george.wilson@delphix.com> Reviewed by: Prakash Surya <prakash.surya@delphix.com> Reviewed by: Dan Kimmel <dan.kimmel@delphix.com> Reviewed by: Matt Ahrens <mahrens@delphix.com> Reviewed by: Paul Dagnelie <pcd@delphix.com> Reviewed by: Tom Caputi <tcaputi@datto.com> Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov> Ported by: David Quigley <david.quigley@intel.com> This review covers the reading and writing of compressed arc headers, sharing data between the arc_hdr_t and the arc_buf_t, and the implementation of a new dbuf cache to keep frequently access data uncompressed. I've added a new member to l1 arc hdr called b_pdata. The b_pdata always hangs off the arc_buf_hdr_t (if an L1 hdr is in use) and points to the physical block for that DVA. The physical block may or may not be compressed. If compressed arc is enabled and the block on-disk is compressed, then the b_pdata will match the block on-disk and remain compressed in memory. If the block on disk is not compressed, then neither will the b_pdata. Lastly, if compressed arc is disabled, then b_pdata will always be an uncompressed version of the on-disk block. Typically the arc will cache only the arc_buf_hdr_t and will aggressively evict any arc_buf_t's that are no longer referenced. This means that the arc will primarily have compressed blocks as the arc_buf_t's are considered overhead and are always uncompressed. When a consumer reads a block we first look to see if the arc_buf_hdr_t is cached. If the hdr is cached then we allocate a new arc_buf_t and decompress the b_pdata contents into the arc_buf_t's b_data. If the hdr already has a arc_buf_t, then we will allocate an additional arc_buf_t and bcopy the uncompressed contents from the first arc_buf_t to the new one. Writing to the compressed arc requires that we first discard the b_pdata since the physical block is about to be rewritten. The new data contents will be passed in via an arc_buf_t (uncompressed) and during the I/O pipeline stages we will copy the physical block contents to a newly allocated b_pdata. When an l2arc is inuse it will also take advantage of the b_pdata. Now the l2arc will always write the contents of b_pdata to the l2arc. This means that when compressed arc is enabled that the l2arc blocks are identical to those stored in the main data pool. This provides a significant advantage since we can leverage the bp's checksum when reading from the l2arc to determine if the contents are valid. If the compressed arc is disabled, then we must first transform the read block to look like the physical block in the main data pool before comparing the checksum and determining it's valid. OpenZFS-issue: https://www.illumos.org/issues/6950 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/7fc10f0 Issue #5078
This commit is contained in:
committed by
Brian Behlendorf
parent
b8eb3c4e3c
commit
d3c2ae1c08
+1825
-1695
File diff suppressed because it is too large
Load Diff
+454
-208
File diff suppressed because it is too large
Load Diff
@@ -95,7 +95,7 @@ __dbuf_stats_hash_table_data(char *buf, size_t size, dmu_buf_impl_t *db)
|
||||
abi.abi_state_type,
|
||||
abi.abi_state_contents,
|
||||
abi.abi_flags,
|
||||
(ulong_t)abi.abi_datacnt,
|
||||
(ulong_t)abi.abi_bufcnt,
|
||||
(u_longlong_t)abi.abi_size,
|
||||
(u_longlong_t)abi.abi_access,
|
||||
(ulong_t)abi.abi_mru_hits,
|
||||
|
||||
+3
-4
@@ -1337,7 +1337,7 @@ void
|
||||
dmu_return_arcbuf(arc_buf_t *buf)
|
||||
{
|
||||
arc_return_buf(buf, FTAG);
|
||||
VERIFY(arc_buf_remove_ref(buf, FTAG));
|
||||
arc_buf_destroy(buf, FTAG);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1681,8 +1681,7 @@ dmu_sync(zio_t *pio, uint64_t txg, dmu_sync_cb_t *done, zgd_t *zgd)
|
||||
|
||||
zio_nowait(arc_write(pio, os->os_spa, txg,
|
||||
bp, dr->dt.dl.dr_data, DBUF_IS_L2CACHEABLE(db),
|
||||
DBUF_IS_L2COMPRESSIBLE(db), &zp, dmu_sync_ready,
|
||||
NULL, NULL, dmu_sync_done, dsa,
|
||||
&zp, dmu_sync_ready, NULL, NULL, dmu_sync_done, dsa,
|
||||
ZIO_PRIORITY_SYNC_WRITE, ZIO_FLAG_CANFAIL, &zb));
|
||||
|
||||
return (0);
|
||||
@@ -2040,11 +2039,11 @@ dmu_init(void)
|
||||
xuio_stat_init();
|
||||
dmu_objset_init();
|
||||
dnode_init();
|
||||
dbuf_init();
|
||||
zfetch_init();
|
||||
dmu_tx_init();
|
||||
l2arc_init();
|
||||
arc_init();
|
||||
dbuf_init();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/dmu.h>
|
||||
@@ -146,7 +146,7 @@ diff_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
(void) arc_buf_remove_ref(abuf, &abuf);
|
||||
arc_buf_destroy(abuf, &abuf);
|
||||
if (err)
|
||||
return (err);
|
||||
/* Don't care about the data blocks */
|
||||
|
||||
+5
-10
@@ -358,8 +358,6 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
|
||||
|
||||
if (DMU_OS_IS_L2CACHEABLE(os))
|
||||
aflags |= ARC_FLAG_L2CACHE;
|
||||
if (DMU_OS_IS_L2COMPRESSIBLE(os))
|
||||
aflags |= ARC_FLAG_L2COMPRESS;
|
||||
|
||||
dprintf_bp(os->os_rootbp, "reading %s", "");
|
||||
err = arc_read(NULL, spa, os->os_rootbp,
|
||||
@@ -376,14 +374,13 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
|
||||
/* Increase the blocksize if we are permitted. */
|
||||
if (spa_version(spa) >= SPA_VERSION_USERSPACE &&
|
||||
arc_buf_size(os->os_phys_buf) < sizeof (objset_phys_t)) {
|
||||
arc_buf_t *buf = arc_buf_alloc(spa,
|
||||
arc_buf_t *buf = arc_alloc_buf(spa,
|
||||
sizeof (objset_phys_t), &os->os_phys_buf,
|
||||
ARC_BUFC_METADATA);
|
||||
bzero(buf->b_data, sizeof (objset_phys_t));
|
||||
bcopy(os->os_phys_buf->b_data, buf->b_data,
|
||||
arc_buf_size(os->os_phys_buf));
|
||||
(void) arc_buf_remove_ref(os->os_phys_buf,
|
||||
&os->os_phys_buf);
|
||||
arc_buf_destroy(os->os_phys_buf, &os->os_phys_buf);
|
||||
os->os_phys_buf = buf;
|
||||
}
|
||||
|
||||
@@ -392,7 +389,7 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
|
||||
} else {
|
||||
int size = spa_version(spa) >= SPA_VERSION_USERSPACE ?
|
||||
sizeof (objset_phys_t) : OBJSET_OLD_PHYS_SIZE;
|
||||
os->os_phys_buf = arc_buf_alloc(spa, size,
|
||||
os->os_phys_buf = arc_alloc_buf(spa, size,
|
||||
&os->os_phys_buf, ARC_BUFC_METADATA);
|
||||
os->os_phys = os->os_phys_buf->b_data;
|
||||
bzero(os->os_phys, size);
|
||||
@@ -475,8 +472,7 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
|
||||
if (needlock)
|
||||
dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
|
||||
if (err != 0) {
|
||||
VERIFY(arc_buf_remove_ref(os->os_phys_buf,
|
||||
&os->os_phys_buf));
|
||||
arc_buf_destroy(os->os_phys_buf, &os->os_phys_buf);
|
||||
kmem_free(os, sizeof (objset_t));
|
||||
return (err);
|
||||
}
|
||||
@@ -787,7 +783,7 @@ dmu_objset_evict_done(objset_t *os)
|
||||
}
|
||||
zil_free(os->os_zil);
|
||||
|
||||
VERIFY(arc_buf_remove_ref(os->os_phys_buf, &os->os_phys_buf));
|
||||
arc_buf_destroy(os->os_phys_buf, &os->os_phys_buf);
|
||||
|
||||
/*
|
||||
* This is a barrier to prevent the objset from going away in
|
||||
@@ -1183,7 +1179,6 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx)
|
||||
|
||||
zio = arc_write(pio, os->os_spa, tx->tx_txg,
|
||||
os->os_rootbp, os->os_phys_buf, DMU_OS_IS_L2CACHEABLE(os),
|
||||
DMU_OS_IS_L2COMPRESSIBLE(os),
|
||||
&zp, dmu_objset_write_ready, NULL, NULL, dmu_objset_write_done,
|
||||
os, ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_MUSTSUCCEED, &zb);
|
||||
|
||||
|
||||
@@ -647,7 +647,7 @@ do_dump(dmu_sendarg_t *dsa, struct send_block_record *data)
|
||||
if (err != 0)
|
||||
break;
|
||||
}
|
||||
(void) arc_buf_remove_ref(abuf, &abuf);
|
||||
arc_buf_destroy(abuf, &abuf);
|
||||
} else if (type == DMU_OT_SA) {
|
||||
arc_flags_t aflags = ARC_FLAG_WAIT;
|
||||
arc_buf_t *abuf;
|
||||
@@ -659,7 +659,7 @@ do_dump(dmu_sendarg_t *dsa, struct send_block_record *data)
|
||||
return (SET_ERROR(EIO));
|
||||
|
||||
err = dump_spill(dsa, zb->zb_object, blksz, abuf->b_data);
|
||||
(void) arc_buf_remove_ref(abuf, &abuf);
|
||||
arc_buf_destroy(abuf, &abuf);
|
||||
} else if (backup_do_embed(dsa, bp)) {
|
||||
/* it's an embedded level-0 block of a regular object */
|
||||
int blksz = dblkszsec << SPA_MINBLOCKSHIFT;
|
||||
@@ -684,7 +684,7 @@ do_dump(dmu_sendarg_t *dsa, struct send_block_record *data)
|
||||
if (zfs_send_corrupt_data) {
|
||||
uint64_t *ptr;
|
||||
/* Send a block filled with 0x"zfs badd bloc" */
|
||||
abuf = arc_buf_alloc(spa, blksz, &abuf,
|
||||
abuf = arc_alloc_buf(spa, blksz, &abuf,
|
||||
ARC_BUFC_DATA);
|
||||
for (ptr = abuf->b_data;
|
||||
(char *)ptr < (char *)abuf->b_data + blksz;
|
||||
@@ -713,7 +713,7 @@ do_dump(dmu_sendarg_t *dsa, struct send_block_record *data)
|
||||
err = dump_write(dsa, type, zb->zb_object,
|
||||
offset, blksz, bp, abuf->b_data);
|
||||
}
|
||||
(void) arc_buf_remove_ref(abuf, &abuf);
|
||||
arc_buf_destroy(abuf, &abuf);
|
||||
}
|
||||
|
||||
ASSERT(err == 0 || err == EINTR);
|
||||
|
||||
@@ -386,7 +386,7 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
|
||||
}
|
||||
|
||||
if (buf)
|
||||
(void) arc_buf_remove_ref(buf, &buf);
|
||||
arc_buf_destroy(buf, &buf);
|
||||
|
||||
post:
|
||||
if (err == 0 && (td->td_flags & TRAVERSE_POST))
|
||||
@@ -610,7 +610,7 @@ traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp,
|
||||
|
||||
osp = buf->b_data;
|
||||
traverse_zil(td, &osp->os_zil_header);
|
||||
(void) arc_buf_remove_ref(buf, &buf);
|
||||
arc_buf_destroy(buf, &buf);
|
||||
}
|
||||
|
||||
if (!(flags & TRAVERSE_PREFETCH_DATA) ||
|
||||
|
||||
+1
-1
@@ -502,7 +502,7 @@ dnode_destroy(dnode_t *dn)
|
||||
}
|
||||
if (dn->dn_bonus != NULL) {
|
||||
mutex_enter(&dn->dn_bonus->db_mtx);
|
||||
dbuf_evict(dn->dn_bonus);
|
||||
dbuf_destroy(dn->dn_bonus);
|
||||
dn->dn_bonus = NULL;
|
||||
}
|
||||
dn->dn_zio = NULL;
|
||||
|
||||
@@ -421,7 +421,7 @@ dnode_evict_dbufs(dnode_t *dn)
|
||||
avl_insert_here(&dn->dn_dbufs, db_marker, db,
|
||||
AVL_BEFORE);
|
||||
|
||||
dbuf_clear(db);
|
||||
dbuf_destroy(db);
|
||||
|
||||
db_next = AVL_NEXT(&dn->dn_dbufs, db_marker);
|
||||
avl_remove(&dn->dn_dbufs, db_marker);
|
||||
@@ -445,7 +445,7 @@ dnode_evict_bonus(dnode_t *dn)
|
||||
if (dn->dn_bonus != NULL) {
|
||||
if (refcount_is_zero(&dn->dn_bonus->db_holds)) {
|
||||
mutex_enter(&dn->dn_bonus->db_mtx);
|
||||
dbuf_evict(dn->dn_bonus);
|
||||
dbuf_destroy(dn->dn_bonus);
|
||||
dn->dn_bonus = NULL;
|
||||
} else {
|
||||
dn->dn_bonus->db_pending_evict = TRUE;
|
||||
|
||||
@@ -692,7 +692,7 @@ dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype,
|
||||
dsl_scan_visitbp(cbp, &czb, dnp,
|
||||
ds, scn, ostype, tx);
|
||||
}
|
||||
(void) arc_buf_remove_ref(buf, &buf);
|
||||
arc_buf_destroy(buf, &buf);
|
||||
} else if (BP_GET_TYPE(bp) == DMU_OT_DNODE) {
|
||||
arc_flags_t flags = ARC_FLAG_WAIT;
|
||||
dnode_phys_t *cdnp;
|
||||
@@ -722,7 +722,7 @@ dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype,
|
||||
cdnp, zb->zb_blkid * epb + i, tx);
|
||||
}
|
||||
|
||||
(void) arc_buf_remove_ref(buf, &buf);
|
||||
arc_buf_destroy(buf, &buf);
|
||||
} else if (BP_GET_TYPE(bp) == DMU_OT_OBJSET) {
|
||||
arc_flags_t flags = ARC_FLAG_WAIT;
|
||||
objset_phys_t *osp;
|
||||
@@ -754,7 +754,7 @@ dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype,
|
||||
&osp->os_userused_dnode,
|
||||
DMU_USERUSED_OBJECT, tx);
|
||||
}
|
||||
(void) arc_buf_remove_ref(buf, &buf);
|
||||
arc_buf_destroy(buf, &buf);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
@@ -227,4 +227,28 @@ refcount_transfer(refcount_t *dst, refcount_t *src)
|
||||
list_destroy(&removed);
|
||||
}
|
||||
|
||||
void
|
||||
refcount_transfer_ownership(refcount_t *rc, void *current_holder,
|
||||
void *new_holder)
|
||||
{
|
||||
reference_t *ref;
|
||||
boolean_t found = B_FALSE;
|
||||
|
||||
mutex_enter(&rc->rc_mtx);
|
||||
if (!rc->rc_tracked) {
|
||||
mutex_exit(&rc->rc_mtx);
|
||||
return;
|
||||
}
|
||||
|
||||
for (ref = list_head(&rc->rc_list); ref;
|
||||
ref = list_next(&rc->rc_list, ref)) {
|
||||
if (ref->ref_holder == current_holder) {
|
||||
ref->ref_holder = new_holder;
|
||||
found = B_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT(found);
|
||||
mutex_exit(&rc->rc_mtx);
|
||||
}
|
||||
#endif /* ZFS_DEBUG */
|
||||
|
||||
+3
-3
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/* Portions Copyright 2010 Robert Milkowski */
|
||||
@@ -260,7 +260,7 @@ zil_read_log_block(zilog_t *zilog, const blkptr_t *bp, blkptr_t *nbp, void *dst,
|
||||
}
|
||||
}
|
||||
|
||||
VERIFY(arc_buf_remove_ref(abuf, &abuf));
|
||||
arc_buf_destroy(abuf, &abuf);
|
||||
}
|
||||
|
||||
return (error);
|
||||
@@ -297,7 +297,7 @@ zil_read_log_data(zilog_t *zilog, const lr_write_t *lr, void *wbuf)
|
||||
if (error == 0) {
|
||||
if (wbuf != NULL)
|
||||
bcopy(abuf->b_data, wbuf, arc_buf_size(abuf));
|
||||
(void) arc_buf_remove_ref(abuf, &abuf);
|
||||
arc_buf_destroy(abuf, &abuf);
|
||||
}
|
||||
|
||||
return (error);
|
||||
|
||||
+3
-3
@@ -301,7 +301,7 @@ zio_data_buf_free(void *buf, size_t size)
|
||||
* Push and pop I/O transform buffers
|
||||
* ==========================================================================
|
||||
*/
|
||||
static void
|
||||
void
|
||||
zio_push_transform(zio_t *zio, void *data, uint64_t size, uint64_t bufsize,
|
||||
zio_transform_func_t *transform)
|
||||
{
|
||||
@@ -319,7 +319,7 @@ zio_push_transform(zio_t *zio, void *data, uint64_t size, uint64_t bufsize,
|
||||
zio->io_size = size;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
zio_pop_transforms(zio_t *zio)
|
||||
{
|
||||
zio_transform_t *zt;
|
||||
@@ -2390,7 +2390,7 @@ zio_ddt_collision(zio_t *zio, ddt_t *ddt, ddt_entry_t *dde)
|
||||
bcmp(abuf->b_data, zio->io_orig_data,
|
||||
zio->io_orig_size) != 0)
|
||||
error = SET_ERROR(EEXIST);
|
||||
VERIFY(arc_buf_remove_ref(abuf, &abuf));
|
||||
arc_buf_destroy(abuf, &abuf);
|
||||
}
|
||||
|
||||
ddt_enter(ddt);
|
||||
|
||||
+35
-22
@@ -187,25 +187,19 @@ zio_checksum_compute(zio_t *zio, enum zio_checksum checksum,
|
||||
}
|
||||
|
||||
int
|
||||
zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info)
|
||||
zio_checksum_error_impl(spa_t *spa, blkptr_t *bp, enum zio_checksum checksum,
|
||||
void *data, uint64_t size, uint64_t offset, zio_bad_cksum_t *info)
|
||||
{
|
||||
blkptr_t *bp = zio->io_bp;
|
||||
uint_t checksum = (bp == NULL ? zio->io_prop.zp_checksum :
|
||||
(BP_IS_GANG(bp) ? ZIO_CHECKSUM_GANG_HEADER : BP_GET_CHECKSUM(bp)));
|
||||
int byteswap;
|
||||
int error;
|
||||
uint64_t size = (bp == NULL ? zio->io_size :
|
||||
(BP_IS_GANG(bp) ? SPA_GANGBLOCKSIZE : BP_GET_PSIZE(bp)));
|
||||
uint64_t offset = zio->io_offset;
|
||||
void *data = zio->io_data;
|
||||
zio_checksum_info_t *ci = &zio_checksum_table[checksum];
|
||||
zio_cksum_t actual_cksum, expected_cksum, verifier;
|
||||
zio_cksum_t actual_cksum, expected_cksum;
|
||||
int byteswap;
|
||||
|
||||
if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func[0] == NULL)
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
if (ci->ci_eck) {
|
||||
zio_eck_t *eck;
|
||||
zio_cksum_t verifier;
|
||||
|
||||
if (checksum == ZIO_CHECKSUM_ZILOG2) {
|
||||
zil_chain_t *zilc = data;
|
||||
@@ -244,32 +238,51 @@ zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info)
|
||||
ci->ci_func[byteswap](data, size, &actual_cksum);
|
||||
eck->zec_cksum = expected_cksum;
|
||||
|
||||
if (byteswap)
|
||||
if (byteswap) {
|
||||
byteswap_uint64_array(&expected_cksum,
|
||||
sizeof (zio_cksum_t));
|
||||
}
|
||||
} else {
|
||||
ASSERT(!BP_IS_GANG(bp));
|
||||
byteswap = BP_SHOULD_BYTESWAP(bp);
|
||||
expected_cksum = bp->blk_cksum;
|
||||
ci->ci_func[byteswap](data, size, &actual_cksum);
|
||||
}
|
||||
|
||||
info->zbc_expected = expected_cksum;
|
||||
info->zbc_actual = actual_cksum;
|
||||
info->zbc_checksum_name = ci->ci_name;
|
||||
info->zbc_byteswapped = byteswap;
|
||||
info->zbc_injected = 0;
|
||||
info->zbc_has_cksum = 1;
|
||||
if (info != NULL) {
|
||||
info->zbc_expected = expected_cksum;
|
||||
info->zbc_actual = actual_cksum;
|
||||
info->zbc_checksum_name = ci->ci_name;
|
||||
info->zbc_byteswapped = byteswap;
|
||||
info->zbc_injected = 0;
|
||||
info->zbc_has_cksum = 1;
|
||||
}
|
||||
|
||||
if (!ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum))
|
||||
return (SET_ERROR(ECKSUM));
|
||||
|
||||
if (zio_injection_enabled && !zio->io_error &&
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info)
|
||||
{
|
||||
blkptr_t *bp = zio->io_bp;
|
||||
uint_t checksum = (bp == NULL ? zio->io_prop.zp_checksum :
|
||||
(BP_IS_GANG(bp) ? ZIO_CHECKSUM_GANG_HEADER : BP_GET_CHECKSUM(bp)));
|
||||
int error;
|
||||
uint64_t size = (bp == NULL ? zio->io_size :
|
||||
(BP_IS_GANG(bp) ? SPA_GANGBLOCKSIZE : BP_GET_PSIZE(bp)));
|
||||
uint64_t offset = zio->io_offset;
|
||||
void *data = zio->io_data;
|
||||
spa_t *spa = zio->io_spa;
|
||||
|
||||
error = zio_checksum_error_impl(spa, bp, checksum, data, size,
|
||||
offset, info);
|
||||
if (error != 0 && zio_injection_enabled && !zio->io_error &&
|
||||
(error = zio_handle_fault_injection(zio, ECKSUM)) != 0) {
|
||||
|
||||
info->zbc_injected = 1;
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (0);
|
||||
return (error);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user