Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F173787266
D58721.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D58721.diff
View Options
diff --git a/sys/dev/bnxt/bnxt_en/if_bnxt.c b/sys/dev/bnxt/bnxt_en/if_bnxt.c
--- a/sys/dev/bnxt/bnxt_en/if_bnxt.c
+++ b/sys/dev/bnxt/bnxt_en/if_bnxt.c
@@ -5492,12 +5492,17 @@
/* Handle completions on the default completion ring */
struct cmpl_base *cmpl;
- uint32_t cons = cpr->cons;
- bool v_bit = cpr->v_bit;
+ uint32_t cons;
+ bool v_bit;
bool last_v_bit;
uint32_t last_cons;
uint16_t type;
+ if (iflib_in_detach(ctx))
+ return;
+ cons = cpr->cons;
+ v_bit = cpr->v_bit;
+
for (;;) {
last_cons = cons;
last_v_bit = v_bit;
diff --git a/sys/dev/enetc/if_enetc.c b/sys/dev/enetc/if_enetc.c
--- a/sys/dev/enetc/if_enetc.c
+++ b/sys/dev/enetc/if_enetc.c
@@ -456,14 +456,18 @@
sc = iflib_get_softc(ctx);
- for (i = 0; i < sc->rx_num_queues; i++)
- iflib_irq_free(ctx, &sc->rx_queues[i].irq);
+ if (sc->rx_queues != NULL) {
+ for (i = 0; i < sc->rx_num_queues; i++)
+ iflib_irq_free(ctx, &sc->rx_queues[i].irq);
+ }
bus_generic_detach(sc->dev);
- if (sc->regs != NULL)
+ if (sc->regs != NULL) {
error = bus_release_resource(sc->dev, SYS_RES_MEMORY,
rman_get_rid(sc->regs), sc->regs);
+ sc->regs = NULL;
+ }
if (sc->ctrl_queue.dma.idi_size != 0)
iflib_dma_free(&sc->ctrl_queue.dma);
diff --git a/sys/dev/igc/if_igc.c b/sys/dev/igc/if_igc.c
--- a/sys/dev/igc/if_igc.c
+++ b/sys/dev/igc/if_igc.c
@@ -1988,8 +1988,9 @@
if (sc->intr_type == IFLIB_INTR_MSIX)
iflib_irq_free(ctx, &sc->irq);
- for (int i = 0; i < sc->rx_num_queues; i++, que++) {
- iflib_irq_free(ctx, &que->que_irq);
+ if (que != NULL) {
+ for (int i = 0; i < sc->rx_num_queues; i++, que++)
+ iflib_irq_free(ctx, &que->que_irq);
}
if (sc->memory != NULL) {
diff --git a/sys/dev/ixgbe/if_sriov.c b/sys/dev/ixgbe/if_sriov.c
--- a/sys/dev/ixgbe/if_sriov.c
+++ b/sys/dev/ixgbe/if_sriov.c
@@ -775,6 +775,8 @@
int i, iov_pos, n, num_vfs = 0, recovery_vf;
ctx = context;
+ if (iflib_in_detach(ctx))
+ return;
sc = iflib_get_softc(ctx);
ctx_lock = iflib_ctx_lock_get(ctx);
diff --git a/sys/dev/vmware/vmxnet3/if_vmx.c b/sys/dev/vmware/vmxnet3/if_vmx.c
--- a/sys/dev/vmware/vmxnet3/if_vmx.c
+++ b/sys/dev/vmware/vmxnet3/if_vmx.c
@@ -527,9 +527,11 @@
scctx = sc->vmx_scctx;
- for (i = 0; i < scctx->isc_nrxqsets; i++) {
- rxq = &sc->vmx_rxq[i];
- iflib_irq_free(sc->vmx_ctx, &rxq->vxrxq_irq);
+ if (sc->vmx_rxq != NULL) {
+ for (i = 0; i < scctx->isc_nrxqsets; i++) {
+ rxq = &sc->vmx_rxq[i];
+ iflib_irq_free(sc->vmx_ctx, &rxq->vxrxq_irq);
+ }
}
iflib_irq_free(sc->vmx_ctx, &sc->vmx_event_intr_irq);
diff --git a/sys/net/iflib.h b/sys/net/iflib.h
--- a/sys/net/iflib.h
+++ b/sys/net/iflib.h
@@ -481,6 +481,7 @@
void iflib_io_tqg_attach(struct grouptask *gt, void *uniq, int cpu,
const char *name);
+/* Configuration task callbacks must return when iflib_in_detach() is true. */
void iflib_config_task_init(if_ctx_t ctx, struct task *config_task,
task_fn_t *fn);
void iflib_config_task_enqueue(if_ctx_t ctx, struct task *config_task);
diff --git a/sys/net/iflib.c b/sys/net/iflib.c
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -205,6 +205,7 @@
uint8_t ifc_sysctl_use_logical_cores;
uint16_t ifc_sysctl_extra_msix_vectors;
bool ifc_cpus_are_physical_cores;
+ bool ifc_core_offset_ref;
bool ifc_sysctl_simple_tx;
bool ifc_sysctl_tx_defer_mfree;
uint16_t ifc_sysctl_tx_reclaim_thresh;
@@ -4259,6 +4260,8 @@
{
if_ctx_t ctx = context;
+ if (iflib_in_detach(ctx))
+ return;
if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING) &&
!(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN))
return;
@@ -5071,6 +5074,7 @@
unsigned int last_valid;
unsigned int i;
+ MPASS(!ctx->ifc_core_offset_ref);
first_valid = CPU_FFS(&ctx->ifc_cpus) - 1;
last_valid = CPU_FLS(&ctx->ifc_cpus) - 1;
@@ -5144,6 +5148,7 @@
cores_consumed);
MPASS(op->refcount < UINT_MAX);
op->refcount++;
+ ctx->ifc_core_offset_ref = true;
break;
}
}
@@ -5160,6 +5165,7 @@
op->refcount = 1;
CPU_COPY(&ctx->ifc_cpus, &op->set);
SLIST_INSERT_HEAD(&cpu_offsets, op, entries);
+ ctx->ifc_core_offset_ref = true;
}
}
mtx_unlock(&cpu_offset_mtx);
@@ -5172,6 +5178,9 @@
{
struct cpu_offset *op, *top;
+ if (!ctx->ifc_core_offset_ref)
+ return;
+
mtx_lock(&cpu_offset_mtx);
SLIST_FOREACH_SAFE(op, &cpu_offsets, entries, top) {
if (CPU_CMP(&ctx->ifc_cpus, &op->set) == 0) {
@@ -5181,10 +5190,12 @@
SLIST_REMOVE(&cpu_offsets, op, cpu_offset, entries);
free(op, M_IFLIB);
}
+ ctx->ifc_core_offset_ref = false;
break;
}
}
mtx_unlock(&cpu_offset_mtx);
+ MPASS(!ctx->ifc_core_offset_ref);
}
int
@@ -5195,10 +5206,17 @@
if_softc_ctx_t scctx;
kobjop_desc_t kobj_desc;
kobj_method_t *kobj_method;
+ bool attach_pre_succeeded, intr_allocated, queues_allocated;
int err, msix, rid;
+#ifdef PCI_IOV
+ int iov_error;
+#endif
int num_txd, num_rxd;
char namebuf[TASKQUEUE_NAMELEN];
+ attach_pre_succeeded = false;
+ intr_allocated = false;
+ queues_allocated = false;
ctx = malloc(sizeof(*ctx), M_IFLIB, M_WAITOK | M_ZERO);
if (sc == NULL) {
@@ -5229,8 +5247,9 @@
CTX_LOCK(ctx);
if ((err = IFDI_ATTACH_PRE(ctx)) != 0) {
device_printf(dev, "IFDI_ATTACH_PRE failed %d\n", err);
- goto fail_unlock;
+ goto fail_cleanup;
}
+ attach_pre_succeeded = true;
_iflib_pre_assert(scctx);
ctx->ifc_txrx = *scctx->isc_txrx;
@@ -5298,7 +5317,8 @@
taskqueue_thread_enqueue, &ctx->ifc_tq);
if (ctx->ifc_tq == NULL) {
device_printf(dev, "Unable to create admin taskqueue\n");
- return (ENOMEM);
+ err = ENOMEM;
+ goto fail_cleanup;
}
err = taskqueue_start_threads(&ctx->ifc_tq, 1, PI_NET, "%s", namebuf);
@@ -5307,7 +5327,8 @@
"Unable to start admin taskqueue threads error: %d\n",
err);
taskqueue_free(ctx->ifc_tq);
- return (err);
+ ctx->ifc_tq = NULL;
+ goto fail_cleanup;
}
TASK_INIT(&ctx->ifc_admin_task, 0, _task_fn_admin, ctx);
@@ -5341,14 +5362,16 @@
scctx->isc_intr = IFLIB_INTR_LEGACY;
msix = 0;
}
+ intr_allocated = true;
/* Get memory for the station queues */
if ((err = iflib_queues_alloc(ctx))) {
device_printf(dev, "Unable to allocate queue memory\n");
- goto fail_intr_free;
+ goto fail_cleanup;
}
+ queues_allocated = true;
if ((err = iflib_qset_structures_setup(ctx)))
- goto fail_queues;
+ goto fail_cleanup;
/*
* Now that we know how many queues there are, get the core offset.
@@ -5367,7 +5390,7 @@
device_printf(dev,
"MSI-X requires ifdi_rx_queue_intr_enable method");
err = EOPNOTSUPP;
- goto fail_queues;
+ goto fail_cleanup;
}
kobj_desc = &ifdi_tx_queue_intr_enable_desc;
kobj_method = kobj_lookup_method(((kobj_t)ctx)->ops->cls, NULL,
@@ -5376,7 +5399,7 @@
device_printf(dev,
"MSI-X requires ifdi_tx_queue_intr_enable method");
err = EOPNOTSUPP;
- goto fail_queues;
+ goto fail_cleanup;
}
/*
@@ -5388,7 +5411,7 @@
if (err != 0) {
device_printf(dev, "IFDI_MSIX_INTR_ASSIGN failed %d\n",
err);
- goto fail_queues;
+ goto fail_cleanup;
}
} else if (scctx->isc_intr != IFLIB_INTR_MSIX) {
rid = 0;
@@ -5398,13 +5421,13 @@
}
if ((err = iflib_legacy_setup(ctx, ctx->isc_legacy_intr, ctx->ifc_softc, &rid, "irq0")) != 0) {
device_printf(dev, "iflib_legacy_setup failed %d\n", err);
- goto fail_queues;
+ goto fail_cleanup;
}
} else {
device_printf(dev,
"Cannot use iflib with only 1 MSI-X interrupt!\n");
err = ENODEV;
- goto fail_queues;
+ goto fail_cleanup;
}
/*
@@ -5452,42 +5475,96 @@
return (0);
fail_detach:
+ STATE_LOCK(ctx);
+ ctx->ifc_flags |= IFC_IN_DETACH;
+ STATE_UNLOCK(ctx);
+ /* Tasks may need either lock; ether_ifdetach() takes ifnet_detach_sx. */
CTX_UNLOCK(ctx);
- taskqueue_drain(ctx->ifc_tq, &ctx->ifc_admin_task);
+ IFNET_WUNLOCK();
+ taskqueue_drain_all(ctx->ifc_tq);
+#ifdef PCI_IOV
+ /*
+ * IFDI_ATTACH_POST may have registered an SR-IOV schema. Match the
+ * normal deregistration order so a failed attach cannot leave a stale
+ * /dev/iov node behind. device_attach() holds Giant throughout this
+ * path, so an IOV configuration cannot race the detach.
+ */
+ if (!CTX_IS_VF(ctx)) {
+ iov_error = pci_iov_detach(dev);
+ if (iov_error != 0)
+ device_printf(dev, "Could not detach SR-IOV after "
+ "attach failure: %d\n", iov_error);
+ }
+#endif
ether_ifdetach(ctx->ifc_ifp);
+ IFNET_WLOCK();
CTX_LOCK(ctx);
-fail_queues:
- sysctl_ctx_free(&ctx->ifc_sysctl_ctx);
- ctx->ifc_sysctl_node = NULL;
+ goto fail_cleanup_detaching;
+
+fail_cleanup:
+ STATE_LOCK(ctx);
+ ctx->ifc_flags |= IFC_IN_DETACH;
+ STATE_UNLOCK(ctx);
+
+fail_cleanup_detaching:
/*
- * Drain without holding CTX_LOCK so _task_fn_admin can run to
- * completion if it needs the context lock. On fail_detach we already
- * drained above; a second drain is a no-op when the queue is empty.
+ * The pre-attach sysctls contain pointers into ctx. Remove them on
+ * every registration failure before iflib_deregister() frees ctx.
*/
- CTX_UNLOCK(ctx);
- taskqueue_drain(ctx->ifc_tq, &ctx->ifc_admin_task);
- CTX_LOCK(ctx);
- iflib_tqg_detach(ctx);
- iflib_tx_structures_free(ctx);
- iflib_rx_structures_free(ctx);
+ if (ctx->ifc_sysctl_node != NULL) {
+ sysctl_ctx_free(&ctx->ifc_sysctl_ctx);
+ ctx->ifc_sysctl_node = NULL;
+ }
+
+ if (ctx->ifc_tq != NULL) {
+ /*
+ * Drain without holding the ifnet or context locks so configuration
+ * tasks can run to completion. On fail_detach a second drain also
+ * catches tasks queued during the first drain.
+ */
+ CTX_UNLOCK(ctx);
+ IFNET_WUNLOCK();
+ taskqueue_drain_all(ctx->ifc_tq);
+ IFNET_WLOCK();
+ CTX_LOCK(ctx);
+ }
+
+ if (queues_allocated) {
+ iflib_tqg_detach(ctx);
+ iflib_tx_structures_free(ctx);
+ iflib_rx_structures_free(ctx);
+ }
+
/*
- * Match iflib_device_deregister: IFDI_DETACH before taskqueue_free.
- * Avoid IFNET_WLOCK across driver detach (LinuxKPI workqueue drain).
+ * A successful IFDI_ATTACH_PRE must be matched by IFDI_DETACH, even
+ * when registration fails before queue allocation. Match
+ * iflib_device_deregister by detaching before taskqueue_free, and avoid
+ * holding IFNET_WLOCK across driver detach (LinuxKPI workqueue drain).
*/
- IFNET_WUNLOCK();
- IFDI_DETACH(ctx);
- IFDI_QUEUES_FREE(ctx);
- IFNET_WLOCK();
- taskqueue_free(ctx->ifc_tq);
-fail_intr_free:
- iflib_free_intr_mem(ctx);
-fail_unlock:
+ if (attach_pre_succeeded) {
+ IFNET_WUNLOCK();
+ IFDI_DETACH(ctx);
+ if (queues_allocated)
+ IFDI_QUEUES_FREE(ctx);
+ /* Reacquire the global lock before the context lock. */
+ CTX_UNLOCK(ctx);
+ IFNET_WLOCK();
+ CTX_LOCK(ctx);
+ }
+ if (ctx->ifc_tq != NULL) {
+ taskqueue_free(ctx->ifc_tq);
+ ctx->ifc_tq = NULL;
+ }
+ if (intr_allocated)
+ iflib_free_intr_mem(ctx);
+
CTX_UNLOCK(ctx);
IFNET_WUNLOCK();
iflib_deregister(ctx);
device_set_softc(ctx->ifc_dev, NULL);
if (ctx->ifc_flags & IFC_SC_ALLOCATED)
free(ctx->ifc_softc, M_IFLIB);
+ unref_ctx_core_offset(ctx);
free(ctx, M_IFLIB);
return (err);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Sep 29, 10:17 AM (1 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39871357
Default Alt Text
D58721.diff (10 KB)
Attached To
Mode
D58721: iflib: Complete registration failure cleanup
Attached
Detach File
Event Timeline
Log In to Comment