Author: mav
Date: Wed Aug 21 02:17:39 2019
New Revision: 351320
URL: https://svnweb.freebsd.org/changeset/base/351320

Log:
  Formalize NVMe controller consumer life cycle.
  
  This fixes possible double call of fail_fn, for example on hot removal.
  It also allows ctrlr_fn to safely return NULL cookie in case of failure
  and not get useless ns_fn or fail_fn call with NULL cookie later.
  
  MFC after:    2 weeks

Modified:
  head/sys/dev/nvme/nvme.c

Modified: head/sys/dev/nvme/nvme.c
==============================================================================
--- head/sys/dev/nvme/nvme.c    Wed Aug 21 01:45:29 2019        (r351319)
+++ head/sys/dev/nvme/nvme.c    Wed Aug 21 02:17:39 2019        (r351320)
@@ -330,16 +330,21 @@ nvme_notify(struct nvme_consumer *cons,
                return;
 
        cmpset = atomic_cmpset_32(&ctrlr->notification_sent, 0, 1);
-
        if (cmpset == 0)
                return;
 
        if (cons->ctrlr_fn != NULL)
                ctrlr_cookie = (*cons->ctrlr_fn)(ctrlr);
        else
-               ctrlr_cookie = NULL;
+               ctrlr_cookie = (void *)(uintptr_t)0xdeadc0dedeadc0de;
        ctrlr->cons_cookie[cons->id] = ctrlr_cookie;
+
+       /* ctrlr_fn has failed.  Nothing to notify here any more. */
+       if (ctrlr_cookie == NULL)
+               return;
+
        if (ctrlr->is_failed) {
+               ctrlr->cons_cookie[cons->id] = NULL;
                if (cons->fail_fn != NULL)
                        (*cons->fail_fn)(ctrlr_cookie);
                /*
@@ -395,13 +400,16 @@ nvme_notify_async_consumers(struct nvme_controller *ct
                            uint32_t log_page_size)
 {
        struct nvme_consumer    *cons;
+       void                    *ctrlr_cookie;
        uint32_t                i;
 
        for (i = 0; i < NVME_MAX_CONSUMERS; i++) {
                cons = &nvme_consumer[i];
-               if (cons->id != INVALID_CONSUMER_ID && cons->async_fn != NULL)
-                       (*cons->async_fn)(ctrlr->cons_cookie[i], async_cpl,
+               if (cons->id != INVALID_CONSUMER_ID && cons->async_fn != NULL &&
+                   (ctrlr_cookie = ctrlr->cons_cookie[i]) != NULL) {
+                       (*cons->async_fn)(ctrlr_cookie, async_cpl,
                            log_page_id, log_page_buffer, log_page_size);
+               }
        }
 }
 
@@ -409,6 +417,7 @@ void
 nvme_notify_fail_consumers(struct nvme_controller *ctrlr)
 {
        struct nvme_consumer    *cons;
+       void                    *ctrlr_cookie;
        uint32_t                i;
 
        /*
@@ -422,8 +431,12 @@ nvme_notify_fail_consumers(struct nvme_controller *ctr
 
        for (i = 0; i < NVME_MAX_CONSUMERS; i++) {
                cons = &nvme_consumer[i];
-               if (cons->id != INVALID_CONSUMER_ID && cons->fail_fn != NULL)
-                       cons->fail_fn(ctrlr->cons_cookie[i]);
+               if (cons->id != INVALID_CONSUMER_ID &&
+                   (ctrlr_cookie = ctrlr->cons_cookie[i]) != NULL) {
+                       ctrlr->cons_cookie[i] = NULL;
+                       if (cons->fail_fn != NULL)
+                               cons->fail_fn(ctrlr_cookie);
+               }
        }
 }
 
@@ -432,6 +445,7 @@ nvme_notify_ns(struct nvme_controller *ctrlr, int nsid
 {
        struct nvme_consumer    *cons;
        struct nvme_namespace   *ns = &ctrlr->ns[nsid - 1];
+       void                    *ctrlr_cookie;
        uint32_t                i;
 
        if (!ctrlr->is_initialized)
@@ -439,9 +453,9 @@ nvme_notify_ns(struct nvme_controller *ctrlr, int nsid
 
        for (i = 0; i < NVME_MAX_CONSUMERS; i++) {
                cons = &nvme_consumer[i];
-               if (cons->id != INVALID_CONSUMER_ID && cons->ns_fn != NULL)
-                       ns->cons_cookie[cons->id] =
-                           (*cons->ns_fn)(ns, ctrlr->cons_cookie[cons->id]);
+               if (cons->id != INVALID_CONSUMER_ID && cons->ns_fn != NULL &&
+                   (ctrlr_cookie = ctrlr->cons_cookie[i]) != NULL)
+                       ns->cons_cookie[i] = (*cons->ns_fn)(ns, ctrlr_cookie);
        }
 }
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to