The branch stable/14 has been updated by kbowling:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=794a87c37e05c2d8d8207c3a087a0f21d86a3d46

commit 794a87c37e05c2d8d8207c3a087a0f21d86a3d46
Author:     Kevin Bowling <[email protected]>
AuthorDate: 2026-08-08 04:33:25 +0000
Commit:     Kevin Bowling <[email protected]>
CommitDate: 2026-08-28 02:20:56 +0000

    iflib: Add registration failure injection points
    
    Add six device-scoped fail(9) points at the registration milestones
    needed to exercise each unwind path. An exact, runtime-only device
    selector prevents unrelated iflib devices from consuming an armed point.
    
    Mark the points non-sleepable because registration holds the ifnet and
    context locks. Document one-shot operation and bus-address reprobe so a
    failed attach can be recovered without another kernel build.
    
    Reviewed by:    gallatin
    Sponsored by:   BBOX.io
    Differential Revision:  https://reviews.freebsd.org/D58722
    
    (cherry picked from commit 90e7dbe5e2ca47baff4e4c6d9e892a0554eec4db)
---
 share/man/man4/iflib.4 | 40 ++++++++++++++++++++++++++++++++++++++++
 sys/net/iflib.c        | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+)

diff --git a/share/man/man4/iflib.4 b/share/man/man4/iflib.4
index 4fad38d2c01f..94502f3c49b3 100644
--- a/share/man/man4/iflib.4
+++ b/share/man/man4/iflib.4
@@ -206,7 +206,47 @@ Current receive ring producer index.
 .Pp
 Additional OIDs useful for driver and iflib development are exposed when the
 INVARIANTS and/or WITNESS options are enabled in the kernel.
+.Ss FAILURE INJECTION
+Registration failures can be injected for one selected device through the
+.Xr fail 9
+framework.
+Set
+.Va debug.fail_point.iflib.register_device
+to the exact device name and configure one of these fail points:
+.Bl -tag -width "register_before_attach_pre"
+.It Va register_before_attach_pre
+Before the driver's pre-attach method.
+.It Va register_after_attach_pre
+After the driver's pre-attach method succeeds.
+.It Va register_after_taskqueue
+After the private taskqueue is started.
+.It Va register_after_interrupts
+After interrupt resources are allocated.
+.It Va register_after_queues
+After queue setup and core-offset allocation.
+.It Va register_after_attach_post
+After the interface is attached and the driver's post-attach method succeeds.
+.El
+.Pp
+The fail points are under
+.Va debug.fail_point.iflib
+and accept the syntax described by
+.Xr fail 9 .
+A one-shot failure is safest because it permits the next probe to recover the
+device:
+.Bd -literal -offset indent
+sysctl debug.fail_point.iflib.register_device=igc1
+sysctl debug.fail_point.iflib.register_after_attach_pre='1*return(5)'
+devctl detach igc1
+devctl attach pci0:4:0:0       # returns EIO
+devctl attach pci0:4:0:0       # succeeds
+.Ed
+.Pp
+After detach, a device may no longer have its former name.
+Use a bus-specific address, as shown in the PCI example above, to reprobe it.
 .Sh SEE ALSO
+.Xr devctl 8 ,
+.Xr fail 9 ,
 .Xr iflib 9
 .Sh HISTORY
 This framework was introduced in
diff --git a/sys/net/iflib.c b/sys/net/iflib.c
index 2d7f5f49555b..6889c91f3669 100644
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -35,6 +35,7 @@
 #include <sys/types.h>
 #include <sys/bus.h>
 #include <sys/eventhandler.h>
+#include <sys/fail.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
@@ -527,6 +528,15 @@ TASKQGROUP_DEFINE(if_config_tqg, 1, 1);
 static SYSCTL_NODE(_net, OID_AUTO, iflib, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
     "iflib driver parameters");
 
+static SYSCTL_NODE(_debug_fail_point, OID_AUTO, iflib,
+    CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "iflib fail points");
+
+static char iflib_register_fail_device[32];
+SYSCTL_STRING(_debug_fail_point_iflib, OID_AUTO, register_device,
+    CTLFLAG_RW | CTLFLAG_MPSAFE,
+    iflib_register_fail_device, sizeof(iflib_register_fail_device),
+    "device name eligible for registration fail points");
+
 /*
  * XXX need to ensure that this can't accidentally cause the head to be moved 
backwards
  */
@@ -5192,6 +5202,30 @@ unref_ctx_core_offset(if_ctx_t ctx)
        MPASS(!ctx->ifc_core_offset_ref);
 }
 
+static bool
+iflib_register_fail_device_matches(device_t dev)
+{
+       const char *nameunit;
+
+       nameunit = device_get_nameunit(dev);
+       return (iflib_register_fail_device[0] != '\0' && nameunit != NULL &&
+           strcmp(nameunit, iflib_register_fail_device) == 0);
+}
+
+#define        IFLIB_REGISTER_FAIL_POINT(_dev, _name, _error, _label) do { \
+       KFAIL_POINT_CODE_COND(_debug_fail_point_iflib, _name, \
+           iflib_register_fail_device_matches((_dev)), \
+           FAIL_POINT_NONSLEEPABLE, { \
+               (_error) = RETURN_VALUE; \
+               if ((_error) <= 0) \
+                       (_error) = EIO; \
+               device_printf((_dev), \
+                   "injecting iflib registration failure at %s: %d\n", \
+                   #_name, (_error)); \
+               goto _label; \
+       }); \
+} while (0)
+
 int
 iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t 
*ctxp)
 {
@@ -5232,11 +5266,15 @@ iflib_device_register(device_t dev, void *sc, 
if_shared_ctx_t sctx, if_ctx_t *ct
        iflib_reset_qvalues(ctx);
        IFNET_WLOCK();
        CTX_LOCK(ctx);
+       IFLIB_REGISTER_FAIL_POINT(dev, register_before_attach_pre, err,
+           fail_cleanup);
        if ((err = IFDI_ATTACH_PRE(ctx)) != 0) {
                device_printf(dev, "IFDI_ATTACH_PRE failed %d\n", err);
                goto fail_cleanup;
        }
        attach_pre_succeeded = true;
+       IFLIB_REGISTER_FAIL_POINT(dev, register_after_attach_pre, err,
+           fail_cleanup);
        _iflib_pre_assert(scctx);
        ctx->ifc_txrx = *scctx->isc_txrx;
 
@@ -5320,6 +5358,8 @@ iflib_device_register(device_t dev, void *sc, 
if_shared_ctx_t sctx, if_ctx_t *ct
 
        TASK_INIT(&ctx->ifc_admin_task, 0, _task_fn_admin, ctx);
        TASK_INIT(&ctx->ifc_led_task, 0, _task_fn_led, ctx);
+       IFLIB_REGISTER_FAIL_POINT(dev, register_after_taskqueue, err,
+           fail_cleanup);
 
        /* Set up cpu set.  If it fails, use the set of all CPUs. */
        if (bus_get_cpus(dev, INTR_CPUS, sizeof(ctx->ifc_cpus), &ctx->ifc_cpus) 
!= 0) {
@@ -5350,6 +5390,8 @@ iflib_device_register(device_t dev, void *sc, 
if_shared_ctx_t sctx, if_ctx_t *ct
                msix = 0;
        }
        intr_allocated = true;
+       IFLIB_REGISTER_FAIL_POINT(dev, register_after_interrupts, err,
+           fail_cleanup);
        /* Get memory for the station queues */
        if ((err = iflib_queues_alloc(ctx))) {
                device_printf(dev, "Unable to allocate queue memory\n");
@@ -5364,6 +5406,8 @@ iflib_device_register(device_t dev, void *sc, 
if_shared_ctx_t sctx, if_ctx_t *ct
         * Now that we know how many queues there are, get the core offset.
         */
        ctx->ifc_sysctl_core_offset = get_ctx_core_offset(ctx);
+       IFLIB_REGISTER_FAIL_POINT(dev, register_after_queues, err,
+           fail_cleanup);
 
        if (msix > 1) {
                /*
@@ -5429,6 +5473,8 @@ iflib_device_register(device_t dev, void *sc, 
if_shared_ctx_t sctx, if_ctx_t *ct
                device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err);
                goto fail_detach;
        }
+       IFLIB_REGISTER_FAIL_POINT(dev, register_after_attach_post, err,
+           fail_detach);
 
        /*
         * Tell the upper layer(s) if IFCAP_VLAN_MTU is supported.

Reply via email to