Commit ec5b6fed authored by GangCao's avatar GangCao Committed by Jim Harris
Browse files

nvme: add ref to track the shared usage of ctrlr among processes



Considering the process can be terminated in the cases like ctrl+c,
kill command or memory fault, the ref is tracked in the per process
structure spdk_nvme_controller_process and whenever there is other
process attaches or detaches the controller, a scan will be issued
to cleanup those unexpectedly exited processes.

Change-Id: Ib4f974f567a865748d42da4ead49edd383dfc752
Signed-off-by: default avatarGangCao <gang.cao@intel.com>
parent 124abbc0
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -62,8 +62,12 @@ spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr)
{
	pthread_mutex_lock(&g_spdk_nvme_driver->lock);

	nvme_ctrlr_proc_put_ref(ctrlr);

	if (nvme_ctrlr_get_ref_count(ctrlr) == 0) {
		TAILQ_REMOVE(&g_spdk_nvme_driver->attached_ctrlrs, ctrlr, tailq);
		nvme_ctrlr_destruct(ctrlr);
	}

	pthread_mutex_unlock(&g_spdk_nvme_driver->lock);
	return 0;
@@ -326,6 +330,12 @@ spdk_nvme_probe(void *cb_ctx, spdk_nvme_probe_cb probe_cb, spdk_nvme_attach_cb a
				TAILQ_REMOVE(&g_spdk_nvme_driver->init_ctrlrs, ctrlr, tailq);
				TAILQ_INSERT_TAIL(&g_spdk_nvme_driver->attached_ctrlrs, ctrlr, tailq);

				/*
				 * Increase the ref count before calling attach_cb() as the user may
				 * call nvme_detach() immediately.
				 */
				nvme_ctrlr_proc_get_ref(ctrlr);

				/*
				 * Unlock while calling attach_cb() so the user can call other functions
				 *  that may take the driver lock, like nvme_detach().
+105 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@

#include "nvme_internal.h"
#include "spdk/env.h"
#include <signal.h>

static int nvme_ctrlr_construct_and_submit_aer(struct spdk_nvme_ctrlr *ctrlr,
		struct nvme_async_event_request *aer);
@@ -822,12 +823,34 @@ nvme_ctrlr_add_process(struct spdk_nvme_ctrlr *ctrlr, void *devhandle)
	ctrlr_proc->pid = getpid();
	STAILQ_INIT(&ctrlr_proc->active_reqs);
	ctrlr_proc->devhandle = devhandle;
	ctrlr_proc->ref = 0;

	TAILQ_INSERT_TAIL(&ctrlr->active_procs, ctrlr_proc, tailq);

	return 0;
}

/**
 * This function will be called when the process exited unexpectedly
 *  in order to free any incomplete nvme request and allocated memory.
 * Note: the ctrl_lock must be held when calling this function.
 */
static void
nvme_ctrlr_cleanup_process(struct spdk_nvme_controller_process *proc)
{
	struct nvme_request	*req, *tmp_req;

	STAILQ_FOREACH_SAFE(req, &proc->active_reqs, stailq, tmp_req) {
		STAILQ_REMOVE(&proc->active_reqs, req, nvme_request, stailq);

		assert(req->pid == proc->pid);

		nvme_free_request(req);
	}

	spdk_free(proc);
}

/**
 * This function will be called when destructing the controller.
 *  1. There is no more admin request on this controller.
@@ -848,6 +871,88 @@ nvme_ctrlr_free_processes(struct spdk_nvme_ctrlr *ctrlr)
	}
}

/**
 * This function will be called when any other process attaches or
 *  detaches the controller in order to cleanup those unexpectedly
 *  terminated processes.
 * Note: the ctrl_lock must be held when calling this function.
 */
static void
nvme_ctrlr_remove_inactive_proc(struct spdk_nvme_ctrlr *ctrlr)
{
	struct spdk_nvme_controller_process	*active_proc, *tmp;

	TAILQ_FOREACH_SAFE(active_proc, &ctrlr->active_procs, tailq, tmp) {
		if ((kill(active_proc->pid, 0) == -1) && (errno == ESRCH)) {
			SPDK_ERRLOG("process %d terminated unexpected\n", active_proc->pid);

			TAILQ_REMOVE(&ctrlr->active_procs, active_proc, tailq);

			nvme_ctrlr_cleanup_process(active_proc);
		}
	}
}

void
nvme_ctrlr_proc_get_ref(struct spdk_nvme_ctrlr *ctrlr)
{
	struct spdk_nvme_controller_process	*active_proc;
	pid_t					pid = getpid();

	pthread_mutex_lock(&ctrlr->ctrlr_lock);

	nvme_ctrlr_remove_inactive_proc(ctrlr);

	TAILQ_FOREACH(active_proc, &ctrlr->active_procs, tailq) {
		if (active_proc->pid == pid) {
			active_proc->ref++;
			break;
		}
	}

	pthread_mutex_unlock(&ctrlr->ctrlr_lock);
}

void
nvme_ctrlr_proc_put_ref(struct spdk_nvme_ctrlr *ctrlr)
{
	struct spdk_nvme_controller_process	*active_proc;
	pid_t					pid = getpid();

	pthread_mutex_lock(&ctrlr->ctrlr_lock);

	nvme_ctrlr_remove_inactive_proc(ctrlr);

	TAILQ_FOREACH(active_proc, &ctrlr->active_procs, tailq) {
		if (active_proc->pid == pid) {
			active_proc->ref--;
			assert(active_proc->ref >= 0);
			break;
		}
	}

	pthread_mutex_unlock(&ctrlr->ctrlr_lock);
}

int
nvme_ctrlr_get_ref_count(struct spdk_nvme_ctrlr *ctrlr)
{
	struct spdk_nvme_controller_process	*active_proc;
	int					ref = 0;

	pthread_mutex_lock(&ctrlr->ctrlr_lock);

	nvme_ctrlr_remove_inactive_proc(ctrlr);

	TAILQ_FOREACH(active_proc, &ctrlr->active_procs, tailq) {
		ref += active_proc->ref;
	}

	pthread_mutex_unlock(&ctrlr->ctrlr_lock);

	return ref;
}

/**
 * This function will be called repeatedly during initialization until the controller is ready.
 */
+13 −0
Original line number Diff line number Diff line
@@ -310,6 +310,9 @@ struct spdk_nvme_controller_process {

	/** Per process PCI device handle */
	struct spdk_pci_device				*devhandle;

	/** Reference to track the number of attachment to this controller. */
	int						ref;
};

/*
@@ -548,4 +551,14 @@ DECLARE_TRANSPORT(pcie)

#undef DECLARE_TRANSPORT

/*
 * Below ref related functions must be called with the global
 *  driver lock held for the multi-process condition.
 *  Within these functions, the per ctrlr ctrlr_lock is also
 *  acquired for the multi-thread condition.
 */
void	nvme_ctrlr_proc_get_ref(struct spdk_nvme_ctrlr *ctrlr);
void	nvme_ctrlr_proc_put_ref(struct spdk_nvme_ctrlr *ctrlr);
int	nvme_ctrlr_get_ref_count(struct spdk_nvme_ctrlr *ctrlr);

#endif /* __NVME_INTERNAL_H__ */
+18 −0
Original line number Diff line number Diff line
@@ -107,6 +107,24 @@ spdk_pci_addr_compare(const struct spdk_pci_addr *a1, const struct spdk_pci_addr
	return true;
}

void
nvme_ctrlr_proc_get_ref(struct spdk_nvme_ctrlr *ctrlr)
{
	return;
}

void
nvme_ctrlr_proc_put_ref(struct spdk_nvme_ctrlr *ctrlr)
{
	return;
}

int
nvme_ctrlr_get_ref_count(struct spdk_nvme_ctrlr *ctrlr)
{
	return 0;
}

static void
test_opc_data_transfer(void)
{
+6 −0
Original line number Diff line number Diff line
@@ -388,6 +388,12 @@ nvme_allocate_request_null(spdk_nvme_cmd_cb cb_fn, void *cb_arg)
	return nvme_allocate_request_contig(NULL, 0, cb_fn, cb_arg);
}

void
nvme_free_request(struct nvme_request *req)
{
	spdk_mempool_put(_g_nvme_driver.request_mempool, req);
}

static void
test_nvme_ctrlr_init_en_1_rdy_0(void)
{
Loading