From 388a557813328063495979c64301c8a92bb249a2 Mon Sep 17 00:00:00 2001 From: Andy Fiddaman Date: Fri, 18 Dec 2020 10:27:04 +0000 Subject: [PATCH] Dangling reference from dmu_objset_upgrade After porting the fix for https://github.com/openzfs/zfs/issues/5295 over to illumos, we started hitting an assertion failure when running the testsuite: assertion failed: rc->rc_count == number, file: .../refcount.c and the unexpected hold has this stack: dsl_dataset_long_hold+0x59 dmu_objset_upgrade+0x73 dmu_objset_id_quota_upgrade+0x15 dmu_objset_own+0x14f The simplest reproducer for this in illumos is zpool create -f -O version=1 testpool c3t0d0; zpool destroy testpool which is run as part of the zpool_create_tempname test, but I can't get this to trigger on FreeBSD. This appears to be because of the call to txg_wait_synced() in dmu_objset_upgrade_stop() (which was missing in illumos), slows down dmu_objset_disown() enough to avoid the condition. Signed-off-by: Andy Fiddaman --- module/zfs/dmu_objset.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c index 6c1d23f2bc72..5efe06551ff7 100644 --- a/module/zfs/dmu_objset.c +++ b/module/zfs/dmu_objset.c @@ -1428,10 +1428,15 @@ dmu_objset_upgrade_task_cb(void *data) mutex_enter(&os->os_upgrade_lock); os->os_upgrade_status = EINTR; if (!os->os_upgrade_exit) { + int status; + mutex_exit(&os->os_upgrade_lock); - os->os_upgrade_status = os->os_upgrade_cb(os); + status = os->os_upgrade_cb(os); + mutex_enter(&os->os_upgrade_lock); + + os->os_upgrade_status = status; } os->os_upgrade_exit = B_TRUE; os->os_upgrade_id = 0; @@ -1459,6 +1464,8 @@ dmu_objset_upgrade(objset_t *os, dmu_objset_upgrade_cb_t cb) dsl_dataset_long_rele(dmu_objset_ds(os), upgrade_tag); os->os_upgrade_status = ENOMEM; } + } else { + dsl_dataset_long_rele(dmu_objset_ds(os), upgrade_tag); } mutex_exit(&os->os_upgrade_lock); }