From 02dc43bc4615537e8e198170a0711e317c8e6dda Mon Sep 17 00:00:00 2001 From: Matthew Ahrens Date: Fri, 14 Apr 2017 12:59:18 -0700 Subject: OpenZFS 8378 - crash due to bp in-memory modification of nopwrite block Authored by: Matthew Ahrens Reviewed by: Prakash Surya Reviewed by: George Wilson Approved by: Robert Mustacchi Reviewed-by: Brian Behlendorf Ported-by: Giuseppe Di Natale The problem is that zfs_get_data() supplies a stale zgd_bp to dmu_sync(), which we then nopwrite against. zfs_get_data() doesn't hold any DMU-related locks, so after it copies db_blkptr to zgd_bp, dbuf_write_ready() could change db_blkptr, and dbuf_write_done() could remove the dirty record. dmu_sync() then sees the stale BP and that the dbuf it not dirty, so it is eligible for nop-writing. The fix is for dmu_sync() to copy db_blkptr to zgd_bp after acquiring the db_mtx. We could still see a stale db_blkptr, but if it is stale then the dirty record will still exist and thus we won't attempt to nopwrite. OpenZFS-issue: https://www.illumos.org/issues/8378 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/3127742 Closes #6293 --- cmd/ztest/ztest.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'cmd') diff --git a/cmd/ztest/ztest.c b/cmd/ztest/ztest.c index b9eef07e1..d698628de 100644 --- a/cmd/ztest/ztest.c +++ b/cmd/ztest/ztest.c @@ -2099,7 +2099,6 @@ ztest_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio) uint64_t object = lr->lr_foid; uint64_t offset = lr->lr_offset; uint64_t size = lr->lr_length; - blkptr_t *bp = &lr->lr_blkptr; uint64_t txg = lr->lr_common.lrc_txg; uint64_t crtxg; dmu_object_info_t doi; @@ -2157,11 +2156,7 @@ ztest_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio) DMU_READ_NO_PREFETCH); if (error == 0) { - blkptr_t *obp = dmu_buf_get_blkptr(db); - if (obp) { - ASSERT(BP_IS_HOLE(bp)); - *bp = *obp; - } + blkptr_t *bp = &lr->lr_blkptr; zgd->zgd_db = db; zgd->zgd_bp = bp; -- cgit v1.2.3