bdev: unregister bdevs top-down during shutdown.

There are some use cases such as multipath and RAID expansion where a
vbdev could have been registered before one of its base bdevs.

Currently we unregister bdevs at shutdown in reverse order of their
registration.  Continue to do that in general, but skip any bdev that
is still claimed.  Any bdevs skipped in this way will eventually be
unregistered once any bdevs that have claimed it have completed
unregistration.

Change-Id: Iafde9558430bc5ce56e8608ef50bcb2b5fbfbf71
Signed-off-by: Andrey Kuzmin <akuzmin@jetstreamsoft.com>
Reviewed-on: https://review.gerrithub.io/432136 (master)
Reviewed-on: https://review.gerrithub.io/435688
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Andrey Kuzmin 2018-11-30 14:13:18 -05:00 committed by Jim Harris
parent 126c22020a
commit 77f89cbc31
2 changed files with 41 additions and 6 deletions

View File

@ -2,6 +2,15 @@
## v18.10.1: (Upcoming Release)
### bdev
On shutdown, bdev unregister now proceeds in top-down fashion, with
claimed bdevs skipped (these will be unregistered later, when virtual
bdev built on top of the respective base bdev unclaims it). This
allows virtual bdevs to be shut down cleanly as opposed to the
previous behavior that didn't differentiate between hotremove and
planned shutdown.
## v18.10:
### nvme

View File

@ -966,7 +966,7 @@ _spdk_bdev_finish_unregister_bdevs_iter(void *cb_arg, int bdeverrno)
if (TAILQ_EMPTY(&g_bdev_mgr.bdevs)) {
SPDK_DEBUGLOG(SPDK_LOG_BDEV, "Done unregistering bdevs\n");
/*
* Bdev module finish need to be deffered as we might be in the middle of some context
* Bdev module finish need to be deferred as we might be in the middle of some context
* (like bdev part free) that will use this bdev (or private bdev driver ctx data)
* after returning.
*/
@ -975,12 +975,38 @@ _spdk_bdev_finish_unregister_bdevs_iter(void *cb_arg, int bdeverrno)
}
/*
* Unregister the last bdev in the list. The last bdev in the list should be a bdev
* that has no bdevs that depend on it.
* Unregister last unclaimed bdev in the list, to ensure that bdev subsystem
* shutdown proceeds top-down. The goal is to give virtual bdevs an opportunity
* to detect clean shutdown as opposed to run-time hot removal of the underlying
* base bdevs.
*
* Also, walk the list in the reverse order.
*/
bdev = TAILQ_LAST(&g_bdev_mgr.bdevs, spdk_bdev_list);
SPDK_DEBUGLOG(SPDK_LOG_BDEV, "Unregistering bdev '%s'\n", bdev->name);
spdk_bdev_unregister(bdev, _spdk_bdev_finish_unregister_bdevs_iter, bdev);
for (bdev = TAILQ_LAST(&g_bdev_mgr.bdevs, spdk_bdev_list);
bdev; bdev = TAILQ_PREV(bdev, spdk_bdev_list, internal.link)) {
if (bdev->internal.claim_module != NULL) {
SPDK_DEBUGLOG(SPDK_LOG_BDEV, "Skipping claimed bdev '%s'(<-'%s').\n",
bdev->name, bdev->internal.claim_module->name);
continue;
}
SPDK_DEBUGLOG(SPDK_LOG_BDEV, "Unregistering bdev '%s'\n", bdev->name);
spdk_bdev_unregister(bdev, _spdk_bdev_finish_unregister_bdevs_iter, bdev);
return;
}
/*
* If any bdev fails to unclaim underlying bdev properly, we may face the
* case of bdev list consisting of claimed bdevs only (if claims are managed
* correctly, this would mean there's a loop in the claims graph which is
* clearly impossible). Warn and unregister last bdev on the list then.
*/
for (bdev = TAILQ_LAST(&g_bdev_mgr.bdevs, spdk_bdev_list);
bdev; bdev = TAILQ_PREV(bdev, spdk_bdev_list, internal.link)) {
SPDK_ERRLOG("Unregistering claimed bdev '%s'!\n", bdev->name);
spdk_bdev_unregister(bdev, _spdk_bdev_finish_unregister_bdevs_iter, bdev);
return;
}
}
void