DF-3850 / dc_callout_replica_fixed.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | /* * dc_callout_replica_fixed.c - protocol replica of the FIXED if_dc.c * callout protocol (the fix proposed for DF-3850's fix.diff): * * dc_tick() becomes non-blocking: * if (!lwkt_serialize_try(ifp->if_serializer)) { * callout_reset(&sc->dc_stat_timer, 1, dc_tick, sc); * return; * } * * With this shape the callback is never INPROG-parked on the serializer, * so dc_stop()'s synchronous callout_stop() (if_dc.c:3489) returns, and * the STOP post-processing unloads the pending 1-tick retry (verified as * pending==0), so the timer is really dead afterwards. * * sysctl kern.dcreplica_armfx=1 arm the fixed-shape tick * sysctl kern.dcreplica_stopfx=1 hold the serializer 3s (tick retries * several times), then callout_stop() * under it -> MUST return, pending==0. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/systm.h> #include <sys/sysctl.h> #include <sys/serialize.h> #include <sys/callout.h> static struct lwkt_serialize ser; static struct callout tick_c; /* NON-MPSAFE, like if_dc.c:1847 */ static volatile int tick_fired, tick_ran, tick_retried; static void dc_tick_fixed(void *arg) { tick_fired++; /* FIXED if_dc.c:2725 - try acquire, never block softclock */ if (!lwkt_serialize_try(&ser)) { tick_retried++; callout_reset(&tick_c, 1, dc_tick_fixed, NULL); return; } tick_ran++; callout_reset(&tick_c, hz / 10, dc_tick_fixed, NULL); lwkt_serialize_exit(&ser); } static int arm_sysctl(SYSCTL_HANDLER_ARGS) { int error, v = 0; error = sysctl_handle_int(oidp, &v, 0, req); if (error || req->newptr == NULL || v == 0) return (error); callout_reset(&tick_c, 1, dc_tick_fixed, NULL); kprintf("dcreplica-fx[arm]: fixed-shape dc_stat_timer armed\n"); return (0); } static int stop_sysctl(SYSCTL_HANDLER_ARGS) { int error, v = 0; int i, pending; error = sysctl_handle_int(oidp, &v, 0, req); if (error || req->newptr == NULL || v == 0) return (error); /* dc_stop context: serializer held across callout_stop(). */ lwkt_serialize_enter(&ser); for (i = 0; i < 3000; i++) /* hold 3s: tick must retry, not park */ DELAY(1000); callout_stop(&tick_c); /* if_dc.c:3489 with the fix applied */ pending = !!callout_pending(&tick_c); kprintf("dcreplica-fx[stop]: FIXED shape: callout_stop RETURNED, " "pending=%d fired=%d retried=%d ran=%d\n", pending, tick_fired, tick_retried, tick_ran); lwkt_serialize_exit(&ser); return (0); } static int fx_load(module_t mod, int what, void *arg) { switch (what) { case MOD_LOAD: lwkt_serialize_init(&ser); callout_init(&tick_c); tick_fired = tick_ran = tick_retried = 0; sysctl_add_oid(NULL, SYSCTL_STATIC_CHILDREN(_kern), OID_AUTO, "dcreplica_armfx", CTLTYPE_INT|CTLFLAG_RW, NULL, 0, arm_sysctl, "I", "arm fixed-shape tick"); sysctl_add_oid(NULL, SYSCTL_STATIC_CHILDREN(_kern), OID_AUTO, "dcreplica_stopfx", CTLTYPE_INT|CTLFLAG_RW, NULL, 0, stop_sysctl, "I", "dc_stop under serializer (fixed)"); kprintf("dcreplica-fx: loaded (FIXED if_dc.c protocol replica)\n"); return (0); case MOD_UNLOAD: return (EBUSY); } return (EOPNOTSUPP); } static moduledata_t fx_mod = { "dcreplica_fx", fx_load, NULL }; DECLARE_MODULE(dcreplica_fx, fx_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); |