DF-5847 / diag5847.py
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 112 113 114 115 116 117 118 119 | #!/usr/bin/env python3 """DF-5847 diagnostic patcher -- edits /usr/src/sys/netinet6/nd6.c in place. DIAGNOSTIC ONLY: never for upstream, never part of fix.diff.""" import sys path = sys.argv[1] if len(sys.argv) > 1 else "/usr/src/sys/netinet6/nd6.c" src = open(path).read() DIAG = r''' /* DF-5847 DIAGNOSTIC ONLY -- never for upstream */ struct nd6dbg { int op; /* 1=add 2=del 3=resolve 4=nd6free */ int cpu; void *ln; void *rt; void *rt_llinfo; long t; void *ln_prev; void *ln_next; }; static struct nd6dbg nd6dbg_ring[64]; static volatile int nd6dbg_idx; static void nd6dbg_log(int op, void *lnp, void *rtp) { struct nd6dbg *d; struct llinfo_nd6 *ln = lnp; int i = atomic_fetchadd_int(&nd6dbg_idx, 1); d = &nd6dbg_ring[i & 63]; d->op = op; d->cpu = mycpuid; d->ln = lnp; d->rt = rtp; d->rt_llinfo = rtp ? ((struct rtentry *)rtp)->rt_llinfo : NULL; d->t = ticks; d->ln_prev = ln ? ln->ln_prev : NULL; d->ln_next = ln ? ln->ln_next : NULL; } static void nd6dbg_dump(void) { int i, n; kprintf("DF5847: ring dump (idx=%d):\n", nd6dbg_idx); n = nd6dbg_idx; for (i = n - 16; i < n; i++) { struct nd6dbg *d = &nd6dbg_ring[i & 63]; kprintf("DF5847: [%d] op=%d cpu=%d ln=%p rt=%p rt_llinfo=%p " "ln_prev=%p ln_next=%p t=%ld\n", i, d->op, d->cpu, d->ln, d->rt, d->rt_llinfo, d->ln_prev, d->ln_next, d->t); } } /* END DF-5847 DIAGNOSTIC */ ''' subs = [ # 1. infra block after nd6_mtx ("struct mtx nd6_mtx = MTX_INITIALIZER(\"nd6\");\n", "struct mtx nd6_mtx = MTX_INITIALIZER(\"nd6\");\n" + DIAG), # 2. timer: tombstone catch + context dump on invariant trip (""" if (rt->rt_llinfo && (struct llinfo_nd6 *)rt->rt_llinfo != ln) panic("rt_llinfo(%p) is not equal to ln(%p)", rt->rt_llinfo, ln); if (!dst) panic("dst=0 in nd6_timer(ln=%p)", ln);""", """ /* DF-5847 DIAGNOSTIC: ln_prev==NULL is the RTM_DELETE * tombstone -- walking an unlinked (freed) ln. */ if (ln->ln_prev == NULL) { kprintf("DF5847: timer walked unlinked ln=%p rt=%p " "cpu=%d\\n", ln, rt, mycpuid); nd6dbg_dump(); panic("DF5847 walk-over-unlinked ln=%p", ln); } if (rt->rt_llinfo && (struct llinfo_nd6 *)rt->rt_llinfo != ln) { kprintf("DF5847: invariant trip ln=%p rt_llinfo=%p " "cpu=%d\\n", ln, rt->rt_llinfo, mycpuid); nd6dbg_dump(); panic("rt_llinfo(%p) is not equal to ln(%p)", rt->rt_llinfo, ln); } if (!dst) panic("dst=0 in nd6_timer(ln=%p)", ln);"""), # 3. nd6_free entry log (""" struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; struct nd_defrouter *dr;""", """ struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; struct nd_defrouter *dr; nd6dbg_log(4, (void *)ln, (void *)rt);"""), # 4. RTM_ADD/RESOLVE alloc log (""" nd6_inuse++; nd6_allocated++; bzero(ln, sizeof(*ln)); ln->ln_rt = rt;""", """ nd6_inuse++; nd6_allocated++; bzero(ln, sizeof(*ln)); nd6dbg_log(req == RTM_ADD ? 1 : 3, (void *)ln, (void *)rt); ln->ln_rt = rt;"""), # 5. RTM_DELETE unlink log (""" nd6_inuse--; ln->ln_next->ln_prev = ln->ln_prev;""", """ nd6dbg_log(2, (void *)ln, (void *)rt); nd6_inuse--; ln->ln_next->ln_prev = ln->ln_prev;"""), ] for old, new in subs: if src.count(old) != 1: print("ANCHOR FAIL (%d hits): %.60r" % (src.count(old), old)) sys.exit(1) src = src.replace(old, new) open(path, "w").write(src) print("diag5847: patched OK") |