Commit 46bce34c authored by Dariusz Stojaczyk's avatar Dariusz Stojaczyk Committed by Jim Harris
Browse files

bdev/virtio: ensure thread safety for adding/removing devices



Also, device removal is now always deferred to simplify
the locking.

Change-Id: I6b994531630b64860da728a93a0f2d613d8aa5ba
Signed-off-by: default avatarDariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-on: https://review.gerrithub.io/405181


Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
parent 20acc18b
Loading
Loading
Loading
Loading
+36 −14
Original line number Diff line number Diff line
@@ -184,6 +184,8 @@ struct bdev_virtio_io_channel {
TAILQ_HEAD(, virtio_scsi_dev) g_virtio_scsi_devs =
	TAILQ_HEAD_INITIALIZER(g_virtio_scsi_devs);

pthread_mutex_t g_virtio_scsi_mutex = PTHREAD_MUTEX_INITIALIZER;

/** Module finish in progress */
static bool g_bdev_virtio_finish = false;

@@ -293,7 +295,9 @@ virtio_scsi_dev_init(struct virtio_scsi_dev *svdev, uint16_t max_queues)
				bdev_virtio_scsi_ch_destroy_cb,
				sizeof(struct bdev_virtio_io_channel));

	pthread_mutex_lock(&g_virtio_scsi_mutex);
	TAILQ_INSERT_TAIL(&g_virtio_scsi_devs, svdev, tailq);
	pthread_mutex_unlock(&g_virtio_scsi_mutex);
	return 0;
}

@@ -1687,13 +1691,16 @@ bdev_virtio_initial_scan_complete(void *ctx __attribute__((unused)),
{
	struct virtio_scsi_dev *svdev;

	pthread_mutex_lock(&g_virtio_scsi_mutex);
	TAILQ_FOREACH(svdev, &g_virtio_scsi_devs, tailq) {
		if (svdev->scan_ctx) {
			/* another device is still being scanned */
			pthread_mutex_unlock(&g_virtio_scsi_mutex);
			return;
		}
	}

	pthread_mutex_unlock(&g_virtio_scsi_mutex);
	spdk_bdev_module_init_done(&virtio_scsi_if);
}

@@ -1704,52 +1711,48 @@ bdev_virtio_initialize(void)
	int rc;

	rc = bdev_virtio_process_config();
	pthread_mutex_lock(&g_virtio_scsi_mutex);

	if (rc != 0) {
		goto out;
		goto err_unlock;
	}

	if (TAILQ_EMPTY(&g_virtio_scsi_devs)) {
		spdk_bdev_module_init_done(&virtio_scsi_if);
		return 0;
		goto out_unlock;
	}

	/* Initialize all created devices and scan available targets */
	TAILQ_FOREACH(svdev, &g_virtio_scsi_devs, tailq) {
		rc = virtio_scsi_dev_scan(svdev, bdev_virtio_initial_scan_complete, NULL);
		if (rc != 0) {
			goto out;
			goto err_unlock;
		}
	}

	pthread_mutex_unlock(&g_virtio_scsi_mutex);
	return 0;

out:
err_unlock:
	/* Remove any created devices */
	TAILQ_FOREACH_SAFE(svdev, &g_virtio_scsi_devs, tailq, next_svdev) {
		virtio_scsi_dev_remove(svdev, NULL, NULL);
	}

out_unlock:
	pthread_mutex_unlock(&g_virtio_scsi_mutex);
	spdk_bdev_module_init_done(&virtio_scsi_if);
	return rc;
}

static void
virtio_scsi_dev_unregister_cb(void *io_device)
_virtio_scsi_dev_unregister_cb(void *io_device)
{
	struct virtio_scsi_dev *svdev = io_device;
	struct virtio_dev *vdev = &svdev->vdev;
	struct spdk_thread *thread;
	bool finish_module;
	bdev_virtio_remove_cb remove_cb;
	void *remove_ctx;

	thread = virtio_dev_queue_get_thread(vdev, VIRTIO_SCSI_CONTROLQ);
	if (thread != spdk_get_thread()) {
		spdk_thread_send_msg(thread, virtio_scsi_dev_unregister_cb, io_device);
		return;
	}

	/* bdevs built on top of this vdev mustn't be destroyed with outstanding I/O. */
	assert(spdk_ring_count(svdev->ctrlq_ring) == 0);
	spdk_ring_free(svdev->ctrlq_ring);
	spdk_poller_unregister(&svdev->mgmt_poller);
@@ -1760,7 +1763,10 @@ virtio_scsi_dev_unregister_cb(void *io_device)
	virtio_dev_stop(vdev);
	virtio_dev_destruct(vdev);

	pthread_mutex_lock(&g_virtio_scsi_mutex);
	TAILQ_REMOVE(&g_virtio_scsi_devs, svdev, tailq);
	pthread_mutex_unlock(&g_virtio_scsi_mutex);

	remove_cb = svdev->remove_cb;
	remove_ctx = svdev->remove_ctx;
	spdk_dma_free(svdev->eventq_ios);
@@ -1777,6 +1783,16 @@ virtio_scsi_dev_unregister_cb(void *io_device)
	}
}

static void
virtio_scsi_dev_unregister_cb(void *io_device)
{
	struct virtio_scsi_dev *svdev = io_device;
	struct spdk_thread *thread;

	thread = virtio_dev_queue_get_thread(&svdev->vdev, VIRTIO_SCSI_CONTROLQ);
	spdk_thread_send_msg(thread, _virtio_scsi_dev_unregister_cb, io_device);
}

static void
virtio_scsi_dev_remove(struct virtio_scsi_dev *svdev,
		       bdev_virtio_remove_cb cb_fn, void *cb_arg)
@@ -1819,7 +1835,9 @@ bdev_virtio_finish(void)

	g_bdev_virtio_finish = true;

	pthread_mutex_lock(&g_virtio_scsi_mutex);
	if (TAILQ_EMPTY(&g_virtio_scsi_devs)) {
		pthread_mutex_unlock(&g_virtio_scsi_mutex);
		spdk_bdev_module_finish_done();
		return;
	}
@@ -1828,6 +1846,7 @@ bdev_virtio_finish(void)
	TAILQ_FOREACH_SAFE(svdev, &g_virtio_scsi_devs, tailq, next) {
		virtio_scsi_dev_remove(svdev, NULL, NULL);
	}
	pthread_mutex_unlock(&g_virtio_scsi_mutex);
}

int
@@ -1896,6 +1915,7 @@ bdev_virtio_scsi_dev_remove(const char *name, bdev_virtio_remove_cb cb_fn, void
{
	struct virtio_scsi_dev *svdev;

	pthread_mutex_lock(&g_virtio_scsi_mutex);
	TAILQ_FOREACH(svdev, &g_virtio_scsi_devs, tailq) {
		if (strcmp(svdev->vdev.name, name) == 0) {
			break;
@@ -1903,12 +1923,14 @@ bdev_virtio_scsi_dev_remove(const char *name, bdev_virtio_remove_cb cb_fn, void
	}

	if (svdev == NULL) {
		pthread_mutex_unlock(&g_virtio_scsi_mutex);
		SPDK_ERRLOG("Cannot find Virtio-SCSI device named '%s'\n", name);
		cb_fn(cb_arg, -ENODEV);
		return;
	}

	virtio_scsi_dev_remove(svdev, cb_fn, cb_arg);
	pthread_mutex_unlock(&g_virtio_scsi_mutex);
}

SPDK_LOG_REGISTER_COMPONENT("virtio", SPDK_LOG_VIRTIO)