Print this page
LOCAL: LDI -- make walks removal-safe

@@ -142,10 +142,13 @@
         { LDI_EV_DEGRADE, 0, CT_DEV_EV_DEGRADED},
         { LDI_EV_DEVICE_REMOVE, 0, 0},
         { NULL}                 /* must terminate list */
 };
 
+static ldi_ev_callback_impl_t *walker_next = NULL;
+static ldi_ev_callback_impl_t *walker_prev = NULL;
+
 void
 ldi_init(void)
 {
         int i;
 

@@ -3327,12 +3330,14 @@
         LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): entered: dip=%p, ev=%s",
             (void *)dip, event));
 
         ret = LDI_EV_NONE;
         ldi_ev_lock();
+        VERIFY(walker_next == NULL);
         listp = &ldi_ev_callback_list.le_head;
-        for (lecp = list_head(listp); lecp; lecp = list_next(listp, lecp)) {
+        for (lecp = list_head(listp); lecp; lecp = walker_next) {
+                walker_next = list_next(listp, lecp);
 
                 /* Check if matching device */
                 if (!ldi_ev_device_match(lecp, dip, dev, spec_type))
                         continue;
 

@@ -3384,11 +3389,13 @@
 
         /*
          * Undo notifies already sent
          */
         lecp = list_prev(listp, lecp);
-        for (; lecp; lecp = list_prev(listp, lecp)) {
+        VERIFY(walker_prev == NULL);
+        for (; lecp; lecp = walker_prev) {
+                walker_prev = list_prev(listp, lecp);
 
                 /*
                  * Check if matching device
                  */
                 if (!ldi_ev_device_match(lecp, dip, dev, spec_type))

@@ -3435,10 +3442,12 @@
                         lecp->lec_finalize = NULL;
                 }
         }
 
 out:
+        walker_next = NULL;
+        walker_prev = NULL;
         ldi_ev_unlock();
 
         if (ret == LDI_EV_NONE) {
                 LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): no matching "
                     "LDI callbacks"));

@@ -3550,12 +3559,14 @@
 
         LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): entered: dip=%p, result=%d"
             " event=%s", (void *)dip, ldi_result, event));
 
         ldi_ev_lock();
+        VERIFY(walker_next == NULL);
         listp = &ldi_ev_callback_list.le_head;
-        for (lecp = list_head(listp); lecp; lecp = list_next(listp, lecp)) {
+        for (lecp = list_head(listp); lecp; lecp = walker_next) {
+                walker_next = list_next(listp, lecp);
 
                 if (lecp->lec_finalize == NULL) {
                         LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): No "
                             "finalize. Skipping"));
                         continue;       /* Not interested in finalize */

@@ -3602,10 +3613,11 @@
                             "ldi_invoke_finalize(): NULLing finalize after "
                             "calling 1 finalize following ldi_close"));
                         lecp->lec_finalize = NULL;
                 }
         }
+        walker_next = NULL;
         ldi_ev_unlock();
 
         if (found)
                 return;
 

@@ -3683,10 +3695,17 @@
         next = found = NULL;
         for (lecp = list_head(listp); lecp; lecp = next) {
                 next = list_next(listp, lecp);
                 if (lecp->lec_id == id) {
                         ASSERT(found == NULL);
+
+                        /* If there is a walk in progress, move it along... */
+                        if (walker_next == lecp)
+                                walker_next = next;
+                        if (walker_prev == lecp)
+                                walker_prev = list_prev(listp, walker_prev);
+
                         list_remove(listp, lecp);
                         found = lecp;
                 }
         }
         ldi_ev_unlock();