Skip to content

Commit

Permalink
Illumos openzfs#3498 panic in arc_read()
Browse files Browse the repository at this point in the history
3498 panic in arc_read(): !refcount_is_zero(&pbuf->b_hdr->b_refcnt)
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Approved by: Richard Lowe <richlowe@richlowe.net>

References:
  illumos/illumos-gate@1b912ec
  https://www.illumos.org/issues/3498

Ported-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes openzfs#1249
  • Loading branch information
grwilson authored and behlendorf committed Jul 2, 2013
1 parent 96b8934 commit 294f680
Show file tree
Hide file tree
Showing 16 changed files with 75 additions and 196 deletions.
7 changes: 3 additions & 4 deletions cmd/zdb/zdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,7 @@ visit_indirect(spa_t *spa, const dnode_phys_t *dnp,
arc_buf_t *buf;
uint64_t fill = 0;

err = arc_read_nolock(NULL, spa, bp, arc_getbuf_func, &buf,
err = arc_read(NULL, spa, bp, arc_getbuf_func, &buf,
ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb);
if (err)
return (err);
Expand Down Expand Up @@ -2048,9 +2048,8 @@ zdb_blkptr_done(zio_t *zio)
mutex_exit(&spa->spa_scrub_lock);
}

/* ARGSUSED */
static int
zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, arc_buf_t *pbuf,
zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg)
{
zdb_cb_t *zcb = arg;
Expand Down Expand Up @@ -2457,7 +2456,7 @@ typedef struct zdb_ddt_entry {
/* ARGSUSED */
static int
zdb_ddt_add_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
arc_buf_t *pbuf, const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg)
const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg)
{
avl_tree_t *t = arg;
avl_index_t where;
Expand Down
8 changes: 1 addition & 7 deletions include/sys/arc.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ struct arc_buf {
arc_buf_hdr_t *b_hdr;
arc_buf_t *b_next;
kmutex_t b_evict_lock;
krwlock_t b_data_lock;
void *b_data;
arc_evict_func_t *b_efunc;
void *b_private;
Expand Down Expand Up @@ -104,8 +103,6 @@ void arc_buf_add_ref(arc_buf_t *buf, void *tag);
int arc_buf_remove_ref(arc_buf_t *buf, void *tag);
int arc_buf_size(arc_buf_t *buf);
void arc_release(arc_buf_t *buf, void *tag);
int arc_release_bp(arc_buf_t *buf, void *tag, blkptr_t *bp, spa_t *spa,
zbookmark_t *zb);
int arc_released(arc_buf_t *buf);
int arc_has_callback(arc_buf_t *buf);
void arc_buf_freeze(arc_buf_t *buf);
Expand All @@ -115,10 +112,7 @@ boolean_t arc_buf_eviction_needed(arc_buf_t *buf);
int arc_referenced(arc_buf_t *buf);
#endif

int arc_read(zio_t *pio, spa_t *spa, const blkptr_t *bp, arc_buf_t *pbuf,
arc_done_func_t *done, void *private, int priority, int zio_flags,
uint32_t *arc_flags, const zbookmark_t *zb);
int arc_read_nolock(zio_t *pio, spa_t *spa, const blkptr_t *bp,
int arc_read(zio_t *pio, spa_t *spa, const blkptr_t *bp,
arc_done_func_t *done, void *private, int priority, int flags,
uint32_t *arc_flags, const zbookmark_t *zb);
zio_t *arc_write(zio_t *pio, spa_t *spa, uint64_t txg,
Expand Down
3 changes: 1 addition & 2 deletions include/sys/dmu_traverse.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ struct zilog;
struct arc_buf;

typedef int (blkptr_cb_t)(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
struct arc_buf *pbuf, const zbookmark_t *zb, const struct dnode_phys *dnp,
void *arg);
const zbookmark_t *zb, const struct dnode_phys *dnp, void *arg);

#define TRAVERSE_PRE (1<<0)
#define TRAVERSE_POST (1<<1)
Expand Down
6 changes: 0 additions & 6 deletions include/sys/dsl_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,6 @@ void dsl_pool_willuse_space(dsl_pool_t *dp, int64_t space, dmu_tx_t *tx);
void dsl_free(dsl_pool_t *dp, uint64_t txg, const blkptr_t *bpp);
void dsl_free_sync(zio_t *pio, dsl_pool_t *dp, uint64_t txg,
const blkptr_t *bpp);
int dsl_read(zio_t *pio, spa_t *spa, const blkptr_t *bpp, arc_buf_t *pbuf,
arc_done_func_t *done, void *private, int priority, int zio_flags,
uint32_t *arc_flags, const zbookmark_t *zb);
int dsl_read_nolock(zio_t *pio, spa_t *spa, const blkptr_t *bpp,
arc_done_func_t *done, void *private, int priority, int zio_flags,
uint32_t *arc_flags, const zbookmark_t *zb);
void dsl_pool_create_origin(dsl_pool_t *dp, dmu_tx_t *tx);
void dsl_pool_upgrade_clones(dsl_pool_t *dp, dmu_tx_t *tx);
void dsl_pool_upgrade_dir_clones(dsl_pool_t *dp, dmu_tx_t *tx);
Expand Down
52 changes: 3 additions & 49 deletions module/zfs/arc.c
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,6 @@ buf_cons(void *vbuf, void *unused, int kmflag)

bzero(buf, sizeof (arc_buf_t));
mutex_init(&buf->b_evict_lock, NULL, MUTEX_DEFAULT, NULL);
rw_init(&buf->b_data_lock, NULL, RW_DEFAULT, NULL);
arc_space_consume(sizeof (arc_buf_t), ARC_SPACE_HDRS);

return (0);
Expand Down Expand Up @@ -914,7 +913,6 @@ buf_dest(void *vbuf, void *unused)
arc_buf_t *buf = vbuf;

mutex_destroy(&buf->b_evict_lock);
rw_destroy(&buf->b_data_lock);
arc_space_return(sizeof (arc_buf_t), ARC_SPACE_HDRS);
}

Expand Down Expand Up @@ -2907,42 +2905,11 @@ arc_read_done(zio_t *zio)
*
* arc_read_done() will invoke all the requested "done" functions
* for readers of this block.
*
* Normal callers should use arc_read and pass the arc buffer and offset
* for the bp. But if you know you don't need locking, you can use
* arc_read_bp.
*/
int
arc_read(zio_t *pio, spa_t *spa, const blkptr_t *bp, arc_buf_t *pbuf,
arc_done_func_t *done, void *private, int priority, int zio_flags,
uint32_t *arc_flags, const zbookmark_t *zb)
{
int err;

if (pbuf == NULL) {
/*
* XXX This happens from traverse callback funcs, for
* the objset_phys_t block.
*/
return (arc_read_nolock(pio, spa, bp, done, private, priority,
zio_flags, arc_flags, zb));
}

ASSERT(!refcount_is_zero(&pbuf->b_hdr->b_refcnt));
ASSERT3U((char *)bp - (char *)pbuf->b_data, <, pbuf->b_hdr->b_size);
rw_enter(&pbuf->b_data_lock, RW_READER);

err = arc_read_nolock(pio, spa, bp, done, private, priority,
zio_flags, arc_flags, zb);
rw_exit(&pbuf->b_data_lock);

return (err);
}

int
arc_read_nolock(zio_t *pio, spa_t *spa, const blkptr_t *bp,
arc_done_func_t *done, void *private, int priority, int zio_flags,
uint32_t *arc_flags, const zbookmark_t *zb)
arc_read(zio_t *pio, spa_t *spa, const blkptr_t *bp, arc_done_func_t *done,
void *private, int priority, int zio_flags, uint32_t *arc_flags,
const zbookmark_t *zb)
{
arc_buf_hdr_t *hdr;
arc_buf_t *buf = NULL;
Expand Down Expand Up @@ -3480,19 +3447,6 @@ arc_release(arc_buf_t *buf, void *tag)
}
}

/*
* Release this buffer. If it does not match the provided BP, fill it
* with that block's contents.
*/
/* ARGSUSED */
int
arc_release_bp(arc_buf_t *buf, void *tag, blkptr_t *bp, spa_t *spa,
zbookmark_t *zb)
{
arc_release(buf, tag);
return (0);
}

int
arc_released(arc_buf_t *buf)
{
Expand Down
2 changes: 1 addition & 1 deletion module/zfs/bptree.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ bptree_add(objset_t *os, uint64_t obj, blkptr_t *bp, uint64_t birth_txg,

/* ARGSUSED */
static int
bptree_visit_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, arc_buf_t *pbuf,
bptree_visit_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg)
{
int err;
Expand Down
28 changes: 4 additions & 24 deletions module/zfs/dbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,6 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags)
spa_t *spa;
zbookmark_t zb;
uint32_t aflags = ARC_NOWAIT;
arc_buf_t *pbuf;

DB_DNODE_ENTER(db);
dn = DB_DNODE(db);
Expand Down Expand Up @@ -621,14 +620,8 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags)
db->db.db_object, db->db_level, db->db_blkid);

dbuf_add_ref(db, NULL);
/* ZIO_FLAG_CANFAIL callers have to check the parent zio's error */

if (db->db_parent)
pbuf = db->db_parent->db_buf;
else
pbuf = db->db_objset->os_phys_buf;

(void) dsl_read(zio, spa, db->db_blkptr, pbuf,
(void) arc_read(zio, spa, db->db_blkptr,
dbuf_read_done, db, ZIO_PRIORITY_SYNC_READ,
(*flags & DB_RF_CANFAIL) ? ZIO_FLAG_CANFAIL : ZIO_FLAG_MUSTSUCCEED,
&aflags, &zb);
Expand Down Expand Up @@ -1026,21 +1019,14 @@ void
dbuf_release_bp(dmu_buf_impl_t *db)
{
objset_t *os;
zbookmark_t zb;

DB_GET_OBJSET(&os, db);
ASSERT(dsl_pool_sync_context(dmu_objset_pool(os)));
ASSERT(arc_released(os->os_phys_buf) ||
list_link_active(&os->os_dsl_dataset->ds_synced_link));
ASSERT(db->db_parent == NULL || arc_released(db->db_parent->db_buf));

zb.zb_objset = os->os_dsl_dataset ?
os->os_dsl_dataset->ds_object : 0;
zb.zb_object = db->db.db_object;
zb.zb_level = db->db_level;
zb.zb_blkid = db->db_blkid;
(void) arc_release_bp(db->db_buf, db,
db->db_blkptr, os->os_spa, &zb);
(void) arc_release(db->db_buf, db);
}

dbuf_dirty_record_t *
Expand Down Expand Up @@ -1886,21 +1872,15 @@ dbuf_prefetch(dnode_t *dn, uint64_t blkid)
if (bp && !BP_IS_HOLE(bp)) {
int priority = dn->dn_type == DMU_OT_DDT_ZAP ?
ZIO_PRIORITY_DDT_PREFETCH : ZIO_PRIORITY_ASYNC_READ;
arc_buf_t *pbuf;
dsl_dataset_t *ds = dn->dn_objset->os_dsl_dataset;
uint32_t aflags = ARC_NOWAIT | ARC_PREFETCH;
zbookmark_t zb;

SET_BOOKMARK(&zb, ds ? ds->ds_object : DMU_META_OBJSET,
dn->dn_object, 0, blkid);

if (db)
pbuf = db->db_buf;
else
pbuf = dn->dn_objset->os_phys_buf;

(void) dsl_read(NULL, dn->dn_objset->os_spa,
bp, pbuf, NULL, NULL, priority,
(void) arc_read(NULL, dn->dn_objset->os_spa,
bp, NULL, NULL, priority,
ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE,
&aflags, &zb);
}
Expand Down
8 changes: 4 additions & 4 deletions module/zfs/dmu_diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ report_dnode(struct diffarg *da, uint64_t object, dnode_phys_t *dnp)

/* ARGSUSED */
static int
diff_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, arc_buf_t *pbuf,
diff_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg)
{
struct diffarg *da = arg;
Expand All @@ -132,9 +132,9 @@ diff_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, arc_buf_t *pbuf,
int blksz = BP_GET_LSIZE(bp);
int i;

if (dsl_read(NULL, spa, bp, pbuf,
arc_getbuf_func, &abuf, ZIO_PRIORITY_ASYNC_READ,
ZIO_FLAG_CANFAIL, &aflags, zb) != 0)
if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf,
ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL,
&aflags, zb) != 0)
return (EIO);

blk = abuf->b_data;
Expand Down
12 changes: 3 additions & 9 deletions module/zfs/dmu_objset.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,12 +276,7 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
aflags |= ARC_L2CACHE;

dprintf_bp(os->os_rootbp, "reading %s", "");
/*
* XXX when bprewrite scrub can change the bp,
* and this is called from dmu_objset_open_ds_os, the bp
* could change, and we'll need a lock.
*/
err = dsl_read_nolock(NULL, spa, os->os_rootbp,
err = arc_read(NULL, spa, os->os_rootbp,
arc_getbuf_func, &os->os_phys_buf,
ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &aflags, &zb);
if (err) {
Expand Down Expand Up @@ -1119,8 +1114,7 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx)
SET_BOOKMARK(&zb, os->os_dsl_dataset ?
os->os_dsl_dataset->ds_object : DMU_META_OBJSET,
ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID);
VERIFY3U(0, ==, arc_release_bp(os->os_phys_buf, &os->os_phys_buf,
os->os_rootbp, os->os_spa, &zb));
arc_release(os->os_phys_buf, &os->os_phys_buf);

dmu_write_policy(os, NULL, 0, 0, &zp);

Expand Down Expand Up @@ -1765,7 +1759,7 @@ dmu_objset_prefetch(const char *name, void *arg)
SET_BOOKMARK(&zb, ds->ds_object, ZB_ROOT_OBJECT,
ZB_ROOT_LEVEL, ZB_ROOT_BLKID);

(void) dsl_read_nolock(NULL, dsl_dataset_get_spa(ds),
(void) arc_read(NULL, dsl_dataset_get_spa(ds),
&ds->ds_phys->ds_bp, NULL, NULL,
ZIO_PRIORITY_ASYNC_READ,
ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE,
Expand Down
20 changes: 10 additions & 10 deletions module/zfs/dmu_send.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ dump_dnode(dmu_sendarg_t *dsp, uint64_t object, dnode_phys_t *dnp)

/* ARGSUSED */
static int
backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, arc_buf_t *pbuf,
backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg)
{
dmu_sendarg_t *dsp = arg;
Expand Down Expand Up @@ -359,9 +359,9 @@ backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, arc_buf_t *pbuf,
uint32_t aflags = ARC_WAIT;
arc_buf_t *abuf;

if (dsl_read(NULL, spa, bp, pbuf,
arc_getbuf_func, &abuf, ZIO_PRIORITY_ASYNC_READ,
ZIO_FLAG_CANFAIL, &aflags, zb) != 0)
if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf,
ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL,
&aflags, zb) != 0)
return (EIO);

blk = abuf->b_data;
Expand All @@ -378,9 +378,9 @@ backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, arc_buf_t *pbuf,
arc_buf_t *abuf;
int blksz = BP_GET_LSIZE(bp);

if (arc_read_nolock(NULL, spa, bp,
arc_getbuf_func, &abuf, ZIO_PRIORITY_ASYNC_READ,
ZIO_FLAG_CANFAIL, &aflags, zb) != 0)
if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf,
ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL,
&aflags, zb) != 0)
return (EIO);

err = dump_spill(dsp, zb->zb_object, blksz, abuf->b_data);
Expand All @@ -390,9 +390,9 @@ backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, arc_buf_t *pbuf,
arc_buf_t *abuf;
int blksz = BP_GET_LSIZE(bp);

if (dsl_read(NULL, spa, bp, pbuf,
arc_getbuf_func, &abuf, ZIO_PRIORITY_ASYNC_READ,
ZIO_FLAG_CANFAIL, &aflags, zb) != 0) {
if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf,
ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL,
&aflags, zb) != 0) {
if (zfs_send_corrupt_data) {
uint64_t *ptr;
/* Send a block filled with 0x"zfs badd bloc" */
Expand Down
Loading

0 comments on commit 294f680

Please sign in to comment.