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: GangCao <gang.cao@intel.com>
This commit is contained in:
parent
124abbc045
commit
ec5b6fed61
@ -62,8 +62,12 @@ spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr)
|
|||||||
{
|
{
|
||||||
pthread_mutex_lock(&g_spdk_nvme_driver->lock);
|
pthread_mutex_lock(&g_spdk_nvme_driver->lock);
|
||||||
|
|
||||||
TAILQ_REMOVE(&g_spdk_nvme_driver->attached_ctrlrs, ctrlr, tailq);
|
nvme_ctrlr_proc_put_ref(ctrlr);
|
||||||
nvme_ctrlr_destruct(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);
|
pthread_mutex_unlock(&g_spdk_nvme_driver->lock);
|
||||||
return 0;
|
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_REMOVE(&g_spdk_nvme_driver->init_ctrlrs, ctrlr, tailq);
|
||||||
TAILQ_INSERT_TAIL(&g_spdk_nvme_driver->attached_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
|
* Unlock while calling attach_cb() so the user can call other functions
|
||||||
* that may take the driver lock, like nvme_detach().
|
* that may take the driver lock, like nvme_detach().
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include "nvme_internal.h"
|
#include "nvme_internal.h"
|
||||||
#include "spdk/env.h"
|
#include "spdk/env.h"
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
static int nvme_ctrlr_construct_and_submit_aer(struct spdk_nvme_ctrlr *ctrlr,
|
static int nvme_ctrlr_construct_and_submit_aer(struct spdk_nvme_ctrlr *ctrlr,
|
||||||
struct nvme_async_event_request *aer);
|
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();
|
ctrlr_proc->pid = getpid();
|
||||||
STAILQ_INIT(&ctrlr_proc->active_reqs);
|
STAILQ_INIT(&ctrlr_proc->active_reqs);
|
||||||
ctrlr_proc->devhandle = devhandle;
|
ctrlr_proc->devhandle = devhandle;
|
||||||
|
ctrlr_proc->ref = 0;
|
||||||
|
|
||||||
TAILQ_INSERT_TAIL(&ctrlr->active_procs, ctrlr_proc, tailq);
|
TAILQ_INSERT_TAIL(&ctrlr->active_procs, ctrlr_proc, tailq);
|
||||||
|
|
||||||
return 0;
|
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.
|
* This function will be called when destructing the controller.
|
||||||
* 1. There is no more admin request on this 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.
|
* This function will be called repeatedly during initialization until the controller is ready.
|
||||||
*/
|
*/
|
||||||
|
@ -310,6 +310,9 @@ struct spdk_nvme_controller_process {
|
|||||||
|
|
||||||
/** Per process PCI device handle */
|
/** Per process PCI device handle */
|
||||||
struct spdk_pci_device *devhandle;
|
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
|
#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__ */
|
#endif /* __NVME_INTERNAL_H__ */
|
||||||
|
@ -107,6 +107,24 @@ spdk_pci_addr_compare(const struct spdk_pci_addr *a1, const struct spdk_pci_addr
|
|||||||
return true;
|
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
|
static void
|
||||||
test_opc_data_transfer(void)
|
test_opc_data_transfer(void)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
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
|
static void
|
||||||
test_nvme_ctrlr_init_en_1_rdy_0(void)
|
test_nvme_ctrlr_init_en_1_rdy_0(void)
|
||||||
{
|
{
|
||||||
|
@ -136,6 +136,24 @@ nvme_qpair_submit_request(struct spdk_nvme_qpair *qpair, struct nvme_request *re
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static void
|
||||||
prepare_for_test(struct spdk_nvme_ns *ns, struct spdk_nvme_ctrlr *ctrlr,
|
prepare_for_test(struct spdk_nvme_ns *ns, struct spdk_nvme_ctrlr *ctrlr,
|
||||||
struct spdk_nvme_qpair *qpair,
|
struct spdk_nvme_qpair *qpair,
|
||||||
|
Loading…
Reference in New Issue
Block a user