diff options
author | jimharris <jimharris@FreeBSD.org> | 2013-03-26 21:58:38 +0000 |
---|---|---|
committer | jimharris <jimharris@FreeBSD.org> | 2013-03-26 21:58:38 +0000 |
commit | 69d2e138016916537645300c0cd8509dc6ced0eb (patch) | |
tree | db8e7e98a528b185943c39f106d44bc2c0f09197 /sys/dev/nvd/nvd.c | |
parent | de155eb698ae9554bd2c7bcd7e22a4287e71f640 (diff) | |
download | FreeBSD-src-69d2e138016916537645300c0cd8509dc6ced0eb.zip FreeBSD-src-69d2e138016916537645300c0cd8509dc6ced0eb.tar.gz |
Add the ability to internally mark a controller as failed, if it is unable to
start or reset. Also add a notifier for NVMe consumers for controller fail
conditions and plumb this notifier for nvd(4) to destroy the associated
GEOM disks when a failure occurs.
This requires a bit of work to cover the races when a consumer is sending
I/O requests to a controller that is transitioning to the failed state. To
help cover this condition, add a task to defer completion of I/Os submitted
to a failed controller, so that the consumer will still always receive its
completions in a different context than the submission.
Sponsored by: Intel
Reviewed by: carl
Diffstat (limited to 'sys/dev/nvd/nvd.c')
-rw-r--r-- | sys/dev/nvd/nvd.c | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/sys/dev/nvd/nvd.c b/sys/dev/nvd/nvd.c index 76ec5f7..09886b4 100644 --- a/sys/dev/nvd/nvd.c +++ b/sys/dev/nvd/nvd.c @@ -49,6 +49,7 @@ static void *nvd_new_disk(struct nvme_namespace *ns, void *ctrlr); static void destroy_geom_disk(struct nvd_disk *ndisk); static void *nvd_new_controller(struct nvme_controller *ctrlr); +static void nvd_controller_fail(void *ctrlr); static int nvd_load(void); static void nvd_unload(void); @@ -118,7 +119,7 @@ nvd_load() TAILQ_INIT(&disk_head); consumer_handle = nvme_register_consumer(nvd_new_disk, - nvd_new_controller, NULL); + nvd_new_controller, NULL, nvd_controller_fail); return (consumer_handle != NULL ? 0 : -1); } @@ -351,3 +352,22 @@ destroy_geom_disk(struct nvd_disk *ndisk) mtx_destroy(&ndisk->bioqlock); } + +static void +nvd_controller_fail(void *ctrlr_arg) +{ + struct nvd_controller *ctrlr = ctrlr_arg; + struct nvd_disk *disk; + + while (!TAILQ_EMPTY(&ctrlr->disk_head)) { + disk = TAILQ_FIRST(&ctrlr->disk_head); + TAILQ_REMOVE(&disk_head, disk, global_tailq); + TAILQ_REMOVE(&ctrlr->disk_head, disk, ctrlr_tailq); + destroy_geom_disk(disk); + free(disk, M_NVD); + } + + TAILQ_REMOVE(&ctrlr_head, ctrlr, tailq); + free(ctrlr, M_NVD); +} + |