Skip to content

Commit

Permalink
Correct zfs_ereport_post_checksum to take abds
Browse files Browse the repository at this point in the history
Which updates the checksum calls in vdev_raidz to be closer to that of
ZOL.
Eventually, the ZOL commit 84c07ad
"Remove dependency on linear ABD" will complete the change.
  • Loading branch information
lundman committed Aug 23, 2017
1 parent 1a5461d commit 1b0174c
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 58 deletions.
23 changes: 21 additions & 2 deletions usr/src/uts/common/fs/zfs/abd.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,8 @@ abd_alloc_for_io(size_t size, boolean_t is_metadata)
* buffer data with sabd. Use abd_put() to free. sabd must not be freed while
* any derived ABDs exist.
*/
abd_t *
abd_get_offset(abd_t *sabd, size_t off)
static inline abd_t *
abd_get_offset_impl(abd_t *sabd, size_t off, size_t size)
{
abd_t *abd;

Expand Down Expand Up @@ -473,6 +473,25 @@ abd_get_offset(abd_t *sabd, size_t off)
return (abd);
}

abd_t *
abd_get_offset(abd_t *sabd, size_t off)
{
size_t size = sabd->abd_size > off ? sabd->abd_size - off : 0;

VERIFY3U(size, >, 0);

return (abd_get_offset_impl(sabd, off, size));
}

abd_t *
abd_get_offset_size(abd_t *sabd, size_t off, size_t size)
{
ASSERT3U(off + size, <=, sabd->abd_size);

return (abd_get_offset_impl(sabd, off, size));
}


/*
* Allocate a linear ABD structure for buf. You must free this with abd_put()
* since the resulting ABD doesn't own its own buffer.
Expand Down
1 change: 1 addition & 0 deletions usr/src/uts/common/fs/zfs/sys/abd.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ abd_t *abd_alloc_for_io(size_t, boolean_t);
abd_t *abd_alloc_sametype(abd_t *, size_t);
void abd_free(abd_t *);
abd_t *abd_get_offset(abd_t *, size_t);
abd_t *abd_get_offset_size(abd_t *, size_t, size_t);
abd_t *abd_get_from_buf(void *, size_t);
void abd_put(abd_t *);

Expand Down
4 changes: 2 additions & 2 deletions usr/src/uts/common/fs/zfs/sys/zio.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ typedef struct zio_prop {
typedef struct zio_cksum_report zio_cksum_report_t;

typedef void zio_cksum_finish_f(zio_cksum_report_t *rep,
const void *good_data);
const abd_t *good_data);
typedef void zio_cksum_free_f(void *cbdata, size_t size);

struct zio_bad_cksum; /* defined in zio_checksum.h */
Expand Down Expand Up @@ -620,7 +620,7 @@ 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);
extern void zfs_ereport_finish_checksum(zio_cksum_report_t *report,
const void *good_data, const void *bad_data, boolean_t drop_if_identical);
const abd_t *good_data, const abd_t *bad_data, boolean_t drop_if_identical);

extern void zfs_ereport_send_interim_checksum(zio_cksum_report_t *report);
extern void zfs_ereport_free_checksum(zio_cksum_report_t *report);
Expand Down
73 changes: 36 additions & 37 deletions usr/src/uts/common/fs/zfs/vdev_raidz.c
Original file line number Diff line number Diff line change
Expand Up @@ -310,14 +310,14 @@ vdev_raidz_cksum_free(void *arg, size_t ignored)
}

static void
vdev_raidz_cksum_finish(zio_cksum_report_t *zcr, const void *good_data)
vdev_raidz_cksum_finish(zio_cksum_report_t *zcr, const abd_t *good_data)
{
raidz_map_t *rm = zcr->zcr_cbdata;
size_t c = zcr->zcr_cbinfo;
size_t x;
size_t x, offset;

const char *good = NULL;
char *bad;
const abd_t *good = NULL;
const abd_t *bad = rm->rm_col[c].rc_abd;

if (good_data == NULL) {
zfs_ereport_finish_checksum(zcr, NULL, NULL, B_FALSE);
Expand All @@ -332,8 +332,6 @@ vdev_raidz_cksum_finish(zio_cksum_report_t *zcr, const void *good_data)
*/
if (rm->rm_col[0].rc_gdata == NULL) {
abd_t *bad_parity[VDEV_RAIDZ_MAXPARITY];
char *buf;
int offset;

/*
* Set up the rm_col[]s to generate the parity for
Expand All @@ -342,20 +340,21 @@ vdev_raidz_cksum_finish(zio_cksum_report_t *zcr, const void *good_data)
*/
for (x = 0; x < rm->rm_firstdatacol; x++) {
bad_parity[x] = rm->rm_col[x].rc_abd;
rm->rm_col[x].rc_gdata =
zio_buf_alloc(rm->rm_col[x].rc_size);
rm->rm_col[x].rc_abd =
abd_get_from_buf(rm->rm_col[x].rc_gdata,
rm->rm_col[x].rc_gdata =
abd_alloc_sametype(rm->rm_col[x].rc_abd,
rm->rm_col[x].rc_size);
}

/* fill in the data columns from good_data */
buf = (char *)good_data;
offset = 0;
for (; x < rm->rm_cols; x++) {
abd_put(rm->rm_col[x].rc_abd);
rm->rm_col[x].rc_abd = abd_get_from_buf(buf,
rm->rm_col[x].rc_size);
buf += rm->rm_col[x].rc_size;

rm->rm_col[x].rc_abd =
abd_get_offset_size((abd_t *)good_data,
offset, rm->rm_col[x].rc_size);
offset += rm->rm_col[x].rc_size;
}

/*
Expand All @@ -364,34 +363,35 @@ vdev_raidz_cksum_finish(zio_cksum_report_t *zcr, const void *good_data)
vdev_raidz_generate_parity(rm);

/* restore everything back to its original state */
for (x = 0; x < rm->rm_firstdatacol; x++) {
abd_put(rm->rm_col[x].rc_abd);
for (x = 0; x < rm->rm_firstdatacol; x++)
rm->rm_col[x].rc_abd = bad_parity[x];
}

offset = 0;
for (x = rm->rm_firstdatacol; x < rm->rm_cols; x++) {
abd_put(rm->rm_col[x].rc_abd);
rm->rm_col[x].rc_abd = abd_get_offset(
rm->rm_abd_copy, offset);
rm->rm_col[x].rc_abd = abd_get_offset_size(
rm->rm_abd_copy, offset,
rm->rm_col[x].rc_size);
offset += rm->rm_col[x].rc_size;
}
}

ASSERT3P(rm->rm_col[c].rc_gdata, !=, NULL);
good = rm->rm_col[c].rc_gdata;
good = abd_get_offset_size(rm->rm_col[c].rc_gdata, 0,
rm->rm_col[c].rc_size);
} else {
/* adjust good_data to point at the start of our column */
good = good_data;

offset = 0;
for (x = rm->rm_firstdatacol; x < c; x++)
good += rm->rm_col[x].rc_size;
offset += rm->rm_col[x].rc_size;

good = abd_get_offset_size((abd_t *)good_data, offset,
rm->rm_col[c].rc_size);
}

bad = abd_borrow_buf_copy(rm->rm_col[c].rc_abd, rm->rm_col[c].rc_size);
/* we drop the ereport if it ends up that the data was good */
zfs_ereport_finish_checksum(zcr, good, bad, B_TRUE);
abd_return_buf(rm->rm_col[c].rc_abd, bad, rm->rm_col[c].rc_size);
abd_put((abd_t *)good);
}

/*
Expand Down Expand Up @@ -1998,7 +1998,7 @@ vdev_raidz_io_start(zio_t *zio)
* Report a checksum error for a child of a RAID-Z device.
*/
static void
raidz_checksum_error(zio_t *zio, raidz_col_t *rc, void *bad_data)
raidz_checksum_error(zio_t *zio, raidz_col_t *rc, abd_t *bad_data)
{
void *buf;
vdev_t *vd = zio->io_vd->vdev_child[rc->rc_devidx];
Expand Down Expand Up @@ -2048,7 +2048,7 @@ raidz_checksum_verify(zio_t *zio)
static int
raidz_parity_verify(zio_t *zio, raidz_map_t *rm)
{
void *orig[VDEV_RAIDZ_MAXPARITY];
abd_t *orig[VDEV_RAIDZ_MAXPARITY];
int c, ret = 0;
raidz_col_t *rc;

Expand All @@ -2063,8 +2063,8 @@ raidz_parity_verify(zio_t *zio, raidz_map_t *rm)
rc = &rm->rm_col[c];
if (!rc->rc_tried || rc->rc_error != 0)
continue;
orig[c] = zio_buf_alloc(rc->rc_size);
abd_copy_to_buf(orig[c], rc->rc_abd, rc->rc_size);
orig[c] = abd_alloc_sametype(rc->rc_abd, rc->rc_size);
abd_copy(orig[c], rc->rc_abd, rc->rc_size);
}

vdev_raidz_generate_parity(rm);
Expand All @@ -2073,12 +2073,12 @@ raidz_parity_verify(zio_t *zio, raidz_map_t *rm)
rc = &rm->rm_col[c];
if (!rc->rc_tried || rc->rc_error != 0)
continue;
if (abd_cmp_buf(rc->rc_abd, orig[c], rc->rc_size) != 0) {
if (abd_cmp(orig[c], rc->rc_abd, rc->rc_abd->abd_size) != 0) {
raidz_checksum_error(zio, rc, orig[c]);
rc->rc_error = SET_ERROR(ECKSUM);
ret++;
}
zio_buf_free(orig[c], rc->rc_size);
abd_free(orig[c]);
}

return (ret);
Expand Down Expand Up @@ -2113,7 +2113,7 @@ vdev_raidz_combrec(zio_t *zio, int total_errors, int data_errors)
{
raidz_map_t *rm = zio->io_vsd;
raidz_col_t *rc;
void *orig[VDEV_RAIDZ_MAXPARITY];
abd_t *orig[VDEV_RAIDZ_MAXPARITY];
int tstore[VDEV_RAIDZ_MAXPARITY + 2];
int *tgts = &tstore[1];
int current, next, i, c, n;
Expand Down Expand Up @@ -2162,7 +2162,8 @@ vdev_raidz_combrec(zio_t *zio, int total_errors, int data_errors)
ASSERT(orig[i] != NULL);
}

orig[n - 1] = zio_buf_alloc(rm->rm_col[0].rc_size);
orig[n - 1] = abd_alloc_sametype(rm->rm_col[0].rc_abd,
rm->rm_col[0].rc_size);

current = 0;
next = tgts[current];
Expand All @@ -2181,8 +2182,7 @@ vdev_raidz_combrec(zio_t *zio, int total_errors, int data_errors)
ASSERT3S(c, >=, 0);
ASSERT3S(c, <, rm->rm_cols);
rc = &rm->rm_col[c];
abd_copy_to_buf(orig[i], rc->rc_abd,
rc->rc_size);
abd_copy(orig[i], rc->rc_abd, rc->rc_size);
}

/*
Expand Down Expand Up @@ -2251,9 +2251,8 @@ vdev_raidz_combrec(zio_t *zio, int total_errors, int data_errors)
}
n--;
done:
for (i = 0; i < n; i++) {
zio_buf_free(orig[i], rm->rm_col[0].rc_size);
}
for (i = 0; i < n; i++)
abd_free(orig[i]);

return (ret);
}
Expand Down
22 changes: 15 additions & 7 deletions usr/src/uts/common/fs/zfs/zfs_fm.c
Original file line number Diff line number Diff line change
Expand Up @@ -497,11 +497,11 @@ range_total_size(zfs_ecksum_info_t *eip)

static zfs_ecksum_info_t *
annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info,
const uint8_t *goodbuf, const uint8_t *badbuf, size_t size,
const abd_t *goodabd, const abd_t *badabd, size_t size,
boolean_t drop_if_identical)
{
const uint64_t *good = (const uint64_t *)goodbuf;
const uint64_t *bad = (const uint64_t *)badbuf;
const uint64_t *good;
const uint64_t *bad;

uint64_t allset = 0;
uint64_t allcleared = 0;
Expand Down Expand Up @@ -545,14 +545,16 @@ annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info,
}
}

if (badbuf == NULL || goodbuf == NULL)
if (badabd == NULL || goodabd == NULL)
return (eip);

ASSERT3U(nui64s, <=, UINT16_MAX);
ASSERT3U(size, ==, nui64s * sizeof (uint64_t));
ASSERT3U(size, <=, SPA_MAXBLOCKSIZE);
ASSERT3U(size, <=, UINT32_MAX);

good = (const uint64_t *) abd_borrow_buf_copy((abd_t *)goodabd, size);
bad = (const uint64_t *) abd_borrow_buf_copy((abd_t *)badabd, size);

/* build up the range list by comparing the two buffers. */
for (idx = 0; idx < nui64s; idx++) {
if (good[idx] == bad[idx]) {
Expand Down Expand Up @@ -582,6 +584,8 @@ annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info,
*/
if (inline_size == 0 && drop_if_identical) {
kmem_free(eip, sizeof (*eip));
abd_return_buf((abd_t *)goodabd, (void *)good, size);
abd_return_buf((abd_t *)badabd, (void *)bad, size);
return (NULL);
}

Expand Down Expand Up @@ -622,6 +626,10 @@ annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info,
eip->zei_ranges[range].zr_start *= sizeof (uint64_t);
eip->zei_ranges[range].zr_end *= sizeof (uint64_t);
}

abd_return_buf((abd_t *)goodabd, (void *)good, size);
abd_return_buf((abd_t *)badabd, (void *)bad, size);

eip->zei_allowed_mingap *= sizeof (uint64_t);
inline_size *= sizeof (uint64_t);

Expand Down Expand Up @@ -726,8 +734,8 @@ zfs_ereport_start_checksum(spa_t *spa, vdev_t *vd, zbookmark_phys_t *zb,
}

void
zfs_ereport_finish_checksum(zio_cksum_report_t *report,
const void *good_data, const void *bad_data, boolean_t drop_if_identical)
zfs_ereport_finish_checksum(zio_cksum_report_t *report, const abd_t *good_data,
const abd_t *bad_data, boolean_t drop_if_identical)
{
#ifdef _KERNEL
zfs_ecksum_info_t *info = NULL;
Expand Down
13 changes: 3 additions & 10 deletions usr/src/uts/common/fs/zfs/zio.c
Original file line number Diff line number Diff line change
Expand Up @@ -3312,7 +3312,7 @@ zio_vdev_io_done(zio_t *zio)
*/
static void
zio_vsd_default_cksum_finish(zio_cksum_report_t *zcr,
const void *good_buf)
const abd_t *good_buf)
{
/* no processing needed */
zfs_ereport_finish_checksum(zcr, good_buf, zcr->zcr_cbdata, B_FALSE);
Expand Down Expand Up @@ -3903,26 +3903,19 @@ zio_done(zio_t *zio)
zio_cksum_report_t *zcr = zio->io_cksum_report;
uint64_t align = zcr->zcr_align;
uint64_t asize = P2ROUNDUP(psize, align);
char *abuf = NULL;
abd_t *adata = zio->io_abd;

if (asize != psize) {
adata = abd_alloc_linear(asize, B_TRUE);
adata = abd_alloc(asize, B_TRUE);
abd_copy(adata, zio->io_abd, psize);
abd_zero_off(adata, psize, asize - psize);
}

if (adata != NULL)
abuf = abd_borrow_buf_copy(adata, asize);

zio->io_cksum_report = zcr->zcr_next;
zcr->zcr_next = NULL;
zcr->zcr_finish(zcr, abuf);
zcr->zcr_finish(zcr, adata);
zfs_ereport_free_checksum(zcr);

if (adata != NULL)
abd_return_buf(adata, abuf, asize);

if (asize != psize)
abd_free(adata);
}
Expand Down

0 comments on commit 1b0174c

Please sign in to comment.