OpenZFS 7580 - ztest failure in dbuf_read_impl

Authored by: George Wilson <george.wilson@delphix.com>
Reviewed by: Pavel Zakharov <pavel.zakharov@delphix.com>
Reviewed by: Steve Gonczi <steve.gonczi@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Ported-by: George Melikov <mail@gmelikov.ru>

OpenZFS-issue: https://www.illumos.org/issues/7580
OpenZFS-commit: https://github.com/openzfs/openzfs/commit/3105d95
Closes #5678
This commit is contained in:
George Melikov 2017-01-28 23:11:09 +03:00 committed by Brian Behlendorf
parent 160af77108
commit 721ed0ee86
2 changed files with 22 additions and 8 deletions

View File

@ -3537,13 +3537,13 @@ dbuf_write_children_ready(zio_t *zio, arc_buf_t *buf, void *vdb)
dmu_buf_impl_t *db = vdb; dmu_buf_impl_t *db = vdb;
dnode_t *dn; dnode_t *dn;
blkptr_t *bp; blkptr_t *bp;
uint64_t i; unsigned int epbs, i;
int epbs;
ASSERT3U(db->db_level, >, 0); ASSERT3U(db->db_level, >, 0);
DB_DNODE_ENTER(db); DB_DNODE_ENTER(db);
dn = DB_DNODE(db); dn = DB_DNODE(db);
epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT; epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT;
ASSERT3U(epbs, <, 31);
/* Determine if all our children are holes */ /* Determine if all our children are holes */
for (i = 0, bp = db->db.db_data; i < 1ULL << epbs; i++, bp++) { for (i = 0, bp = db->db.db_data; i < 1ULL << epbs; i++, bp++) {
@ -3556,8 +3556,14 @@ dbuf_write_children_ready(zio_t *zio, arc_buf_t *buf, void *vdb)
* we may get compressed away. * we may get compressed away.
*/ */
if (i == 1ULL << epbs) { if (i == 1ULL << epbs) {
/* didn't find any non-holes */ /*
* We only found holes. Grab the rwlock to prevent
* anybody from reading the blocks we're about to
* zero out.
*/
rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
bzero(db->db.db_data, db->db.db_size); bzero(db->db.db_data, db->db.db_size);
rw_exit(&dn->dn_struct_rwlock);
} }
DB_DNODE_EXIT(db); DB_DNODE_EXIT(db);
} }

View File

@ -240,8 +240,9 @@ free_children(dmu_buf_impl_t *db, uint64_t blkid, uint64_t nblks,
dnode_t *dn; dnode_t *dn;
blkptr_t *bp; blkptr_t *bp;
dmu_buf_impl_t *subdb; dmu_buf_impl_t *subdb;
uint64_t start, end, dbstart, dbend, i; uint64_t start, end, dbstart, dbend;
int epbs, shift; unsigned int epbs, shift, i;
uint64_t id;
/* /*
* There is a small possibility that this block will not be cached: * There is a small possibility that this block will not be cached:
@ -258,6 +259,7 @@ free_children(dmu_buf_impl_t *db, uint64_t blkid, uint64_t nblks,
DB_DNODE_ENTER(db); DB_DNODE_ENTER(db);
dn = DB_DNODE(db); dn = DB_DNODE(db);
epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT; epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT;
ASSERT3U(epbs, <, 31);
shift = (db->db_level - 1) * epbs; shift = (db->db_level - 1) * epbs;
dbstart = db->db_blkid << epbs; dbstart = db->db_blkid << epbs;
start = blkid >> shift; start = blkid >> shift;
@ -277,12 +279,12 @@ free_children(dmu_buf_impl_t *db, uint64_t blkid, uint64_t nblks,
FREE_VERIFY(db, start, end, tx); FREE_VERIFY(db, start, end, tx);
free_blocks(dn, bp, end-start+1, tx); free_blocks(dn, bp, end-start+1, tx);
} else { } else {
for (i = start; i <= end; i++, bp++) { for (id = start; id <= end; id++, bp++) {
if (BP_IS_HOLE(bp)) if (BP_IS_HOLE(bp))
continue; continue;
rw_enter(&dn->dn_struct_rwlock, RW_READER); rw_enter(&dn->dn_struct_rwlock, RW_READER);
VERIFY0(dbuf_hold_impl(dn, db->db_level - 1, VERIFY0(dbuf_hold_impl(dn, db->db_level - 1,
i, TRUE, FALSE, FTAG, &subdb)); id, TRUE, FALSE, FTAG, &subdb));
rw_exit(&dn->dn_struct_rwlock); rw_exit(&dn->dn_struct_rwlock);
ASSERT3P(bp, ==, subdb->db_blkptr); ASSERT3P(bp, ==, subdb->db_blkptr);
@ -297,8 +299,14 @@ free_children(dmu_buf_impl_t *db, uint64_t blkid, uint64_t nblks,
break; break;
} }
if (i == 1 << epbs) { if (i == 1 << epbs) {
/* didn't find any non-holes */ /*
* We only found holes. Grab the rwlock to prevent
* anybody from reading the blocks we're about to
* zero out.
*/
rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
bzero(db->db.db_data, db->db.db_size); bzero(db->db.db_data, db->db.db_size);
rw_exit(&dn->dn_struct_rwlock);
free_blocks(dn, db->db_blkptr, 1, tx); free_blocks(dn, db->db_blkptr, 1, tx);
} else { } else {
/* /*