MFV r329313: 8857 zio_remove_child() panic due to already destroyed parent zio
illumos/illumos-gate@d6e1c446d7
d6e1c446d7
https://www.illumos.org/issues/8857
I had an OS panic on one of our servers:
ffffff01809128c0 vpanic()
ffffff01809128e0 mutex_panic+0x58(fffffffffb94c904, ffffff597dde7f80)
ffffff0180912950 mutex_vector_enter+0x347(ffffff597dde7f80)
ffffff01809129b0 zio_remove_child+0x50(ffffff597dde7c58, ffffff32bd901ac0,
ffffff3373370908)
ffffff0180912a40 zio_done+0x390(ffffff32bd901ac0)
ffffff0180912a70 zio_execute+0x78(ffffff32bd901ac0)
ffffff0180912b30 taskq_thread+0x2d0(ffffff33bae44140)
ffffff0180912b40 thread_start+8()
It panicked here:
http://src.illumos.org/source/xref/illumos-gate/usr/src/uts/common/fs/zfs/
zio.c#430
pio->io_lock is DEAD, thus a panic. Further analysis shows the "pio"
(parent zio of "cio") has already been destroyed.
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Andriy Gapon <avg@FreeBSD.org>
Reviewed by: Youzhong Yang <youzhong@gmail.com>
Approved by: Dan McDonald <danmcd@omniti.com>
Author: George Wilson <george.wilson@delphix.com>
PR: 223803
Tested by: shiva.bhanujan@quorum.com
MFC after: 2 weeks
This commit is contained in:
commit
113ce413ba
@ -201,6 +201,9 @@ enum zio_flag {
|
||||
(((zio)->io_flags & ZIO_FLAG_VDEV_INHERIT) | \
|
||||
ZIO_FLAG_CANFAIL)
|
||||
|
||||
#define ZIO_CHILD_BIT(x) (1 << (x))
|
||||
#define ZIO_CHILD_BIT_IS_SET(val, x) ((val) & (1 << (x)))
|
||||
|
||||
enum zio_child {
|
||||
ZIO_CHILD_VDEV = 0,
|
||||
ZIO_CHILD_GANG,
|
||||
@ -209,6 +212,14 @@ enum zio_child {
|
||||
ZIO_CHILD_TYPES
|
||||
};
|
||||
|
||||
#define ZIO_CHILD_VDEV_BIT ZIO_CHILD_BIT(ZIO_CHILD_VDEV)
|
||||
#define ZIO_CHILD_GANG_BIT ZIO_CHILD_BIT(ZIO_CHILD_GANG)
|
||||
#define ZIO_CHILD_DDT_BIT ZIO_CHILD_BIT(ZIO_CHILD_DDT)
|
||||
#define ZIO_CHILD_LOGICAL_BIT ZIO_CHILD_BIT(ZIO_CHILD_LOGICAL)
|
||||
#define ZIO_CHILD_ALL_BITS \
|
||||
(ZIO_CHILD_VDEV_BIT | ZIO_CHILD_GANG_BIT | \
|
||||
ZIO_CHILD_DDT_BIT | ZIO_CHILD_LOGICAL_BIT)
|
||||
|
||||
enum zio_wait_type {
|
||||
ZIO_WAIT_READY = 0,
|
||||
ZIO_WAIT_DONE,
|
||||
|
@ -512,21 +512,26 @@ zio_remove_child(zio_t *pio, zio_t *cio, zio_link_t *zl)
|
||||
}
|
||||
|
||||
static boolean_t
|
||||
zio_wait_for_children(zio_t *zio, enum zio_child child, enum zio_wait_type wait)
|
||||
zio_wait_for_children(zio_t *zio, uint8_t childbits, enum zio_wait_type wait)
|
||||
{
|
||||
uint64_t *countp = &zio->io_children[child][wait];
|
||||
boolean_t waiting = B_FALSE;
|
||||
|
||||
mutex_enter(&zio->io_lock);
|
||||
ASSERT(zio->io_stall == NULL);
|
||||
if (*countp != 0) {
|
||||
zio->io_stage >>= 1;
|
||||
ASSERT3U(zio->io_stage, !=, ZIO_STAGE_OPEN);
|
||||
zio->io_stall = countp;
|
||||
waiting = B_TRUE;
|
||||
for (int c = 0; c < ZIO_CHILD_TYPES; c++) {
|
||||
if (!(ZIO_CHILD_BIT_IS_SET(childbits, c)))
|
||||
continue;
|
||||
|
||||
uint64_t *countp = &zio->io_children[c][wait];
|
||||
if (*countp != 0) {
|
||||
zio->io_stage >>= 1;
|
||||
ASSERT3U(zio->io_stage, !=, ZIO_STAGE_OPEN);
|
||||
zio->io_stall = countp;
|
||||
waiting = B_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_exit(&zio->io_lock);
|
||||
|
||||
return (waiting);
|
||||
}
|
||||
|
||||
@ -1330,9 +1335,10 @@ zio_write_compress(zio_t *zio)
|
||||
* If our children haven't all reached the ready stage,
|
||||
* wait for them and then repeat this pipeline stage.
|
||||
*/
|
||||
if (zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_READY) ||
|
||||
zio_wait_for_children(zio, ZIO_CHILD_LOGICAL, ZIO_WAIT_READY))
|
||||
if (zio_wait_for_children(zio, ZIO_CHILD_LOGICAL_BIT |
|
||||
ZIO_CHILD_GANG_BIT, ZIO_WAIT_READY)) {
|
||||
return (ZIO_PIPELINE_STOP);
|
||||
}
|
||||
|
||||
if (!IO_IS_ALLOCATING(zio))
|
||||
return (ZIO_PIPELINE_CONTINUE);
|
||||
@ -2180,8 +2186,9 @@ zio_gang_issue(zio_t *zio)
|
||||
{
|
||||
blkptr_t *bp = zio->io_bp;
|
||||
|
||||
if (zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_DONE))
|
||||
if (zio_wait_for_children(zio, ZIO_CHILD_GANG_BIT, ZIO_WAIT_DONE)) {
|
||||
return (ZIO_PIPELINE_STOP);
|
||||
}
|
||||
|
||||
ASSERT(BP_IS_GANG(bp) && zio->io_gang_leader == zio);
|
||||
ASSERT(zio->io_child_type > ZIO_CHILD_GANG);
|
||||
@ -2502,8 +2509,9 @@ zio_ddt_read_done(zio_t *zio)
|
||||
{
|
||||
blkptr_t *bp = zio->io_bp;
|
||||
|
||||
if (zio_wait_for_children(zio, ZIO_CHILD_DDT, ZIO_WAIT_DONE))
|
||||
if (zio_wait_for_children(zio, ZIO_CHILD_DDT_BIT, ZIO_WAIT_DONE)) {
|
||||
return (ZIO_PIPELINE_STOP);
|
||||
}
|
||||
|
||||
ASSERT(BP_GET_DEDUP(bp));
|
||||
ASSERT(BP_GET_PSIZE(bp) == zio->io_size);
|
||||
@ -3235,8 +3243,9 @@ zio_vdev_io_done(zio_t *zio)
|
||||
vdev_ops_t *ops = vd ? vd->vdev_ops : &vdev_mirror_ops;
|
||||
boolean_t unexpected_error = B_FALSE;
|
||||
|
||||
if (zio_wait_for_children(zio, ZIO_CHILD_VDEV, ZIO_WAIT_DONE))
|
||||
if (zio_wait_for_children(zio, ZIO_CHILD_VDEV_BIT, ZIO_WAIT_DONE)) {
|
||||
return (ZIO_PIPELINE_STOP);
|
||||
}
|
||||
|
||||
ASSERT(zio->io_type == ZIO_TYPE_READ ||
|
||||
zio->io_type == ZIO_TYPE_WRITE || zio->io_type == ZIO_TYPE_FREE);
|
||||
@ -3312,8 +3321,9 @@ zio_vdev_io_assess(zio_t *zio)
|
||||
{
|
||||
vdev_t *vd = zio->io_vd;
|
||||
|
||||
if (zio_wait_for_children(zio, ZIO_CHILD_VDEV, ZIO_WAIT_DONE))
|
||||
if (zio_wait_for_children(zio, ZIO_CHILD_VDEV_BIT, ZIO_WAIT_DONE)) {
|
||||
return (ZIO_PIPELINE_STOP);
|
||||
}
|
||||
|
||||
if (vd == NULL && !(zio->io_flags & ZIO_FLAG_CONFIG_WRITER))
|
||||
spa_config_exit(zio->io_spa, SCL_ZIO, zio);
|
||||
@ -3544,9 +3554,10 @@ zio_ready(zio_t *zio)
|
||||
zio_t *pio, *pio_next;
|
||||
zio_link_t *zl = NULL;
|
||||
|
||||
if (zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_READY) ||
|
||||
zio_wait_for_children(zio, ZIO_CHILD_DDT, ZIO_WAIT_READY))
|
||||
if (zio_wait_for_children(zio, ZIO_CHILD_GANG_BIT | ZIO_CHILD_DDT_BIT,
|
||||
ZIO_WAIT_READY)) {
|
||||
return (ZIO_PIPELINE_STOP);
|
||||
}
|
||||
|
||||
if (zio->io_ready) {
|
||||
ASSERT(IO_IS_ALLOCATING(zio));
|
||||
@ -3686,11 +3697,9 @@ zio_done(zio_t *zio)
|
||||
* If our children haven't all completed,
|
||||
* wait for them and then repeat this pipeline stage.
|
||||
*/
|
||||
if (zio_wait_for_children(zio, ZIO_CHILD_VDEV, ZIO_WAIT_DONE) ||
|
||||
zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_DONE) ||
|
||||
zio_wait_for_children(zio, ZIO_CHILD_DDT, ZIO_WAIT_DONE) ||
|
||||
zio_wait_for_children(zio, ZIO_CHILD_LOGICAL, ZIO_WAIT_DONE))
|
||||
if (zio_wait_for_children(zio, ZIO_CHILD_ALL_BITS, ZIO_WAIT_DONE)) {
|
||||
return (ZIO_PIPELINE_STOP);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the allocation throttle is enabled, then update the accounting.
|
||||
|
Loading…
Reference in New Issue
Block a user