DF-4907 / fix.diff
--- a/sys/dev/disk/dm/delay/dm_target_delay.c +++ b/sys/dev/disk/dm/delay/dm_target_delay.c @@ -303,7 +303,26 @@ while ((dp = TAILQ_FIRST(&tmp_list)) != NULL) { TAILQ_REMOVE(&tmp_list, dp, entry); - _submit(di, dp->bp); + if (submit_all) { + /* + * Target teardown (dm_target_delay_destroy): do NOT + * submit these bios to the pdev. vn_strategy() is + * asynchronous, so the bios would still be in flight + * after _destroy() returns and after the enclosing + * dm device may have been freed by dm_dev_destroy(). + * Their completion path (nestiobuf_iodone -> + * nestiobuf_done -> devstat_end_transaction_buf) + * then writes through the captured &dmv->stats into + * freed (and typically reallocated) kernel memory. + * Fail the queued bios instead; erroring I/O on a + * device being removed is the expected semantic. + */ + dp->bp->b_error = ENXIO; + dp->bp->b_resid = dp->bp->b_bcount; + biodone(&dp->bp->b_bio1); + } else { + _submit(di, dp->bp); + } objcache_put(obj_cache, dp); } } |