DF-3481 / fix.diff
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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | @@ -203,6 +203,7 @@ struct ng_ppp_private { frags; int qlen; /* fraq queue length */ struct callout fragTimer; /* fraq queue check */ + struct lwkt_token token; /* serialize priv (SMP) */ }; typedef struct ng_ppp_private *priv_p; @@ -212,6 +213,10 @@ static ng_rcvmsg_t ng_ppp_rcvmsg; static ng_shutdown_t ng_ppp_rmnode; static ng_newhook_t ng_ppp_newhook; static ng_rcvdata_t ng_ppp_rcvdata; +static int ng_ppp_rcvdata_unlocked(hook_p hook, + struct mbuf *m, meta_p meta); +static int ng_ppp_newhook_unlocked(node_p node, hook_p hook, + const char *name); static ng_disconnect_t ng_ppp_disconnect; /* Helper functions */ @@ -400,6 +405,7 @@ ng_ppp_constructor(node_p *nodep) for (i = 0; i < NG_PPP_MAX_LINKS; i++) priv->links[i].seq = MP_NOSEQ; callout_init(&priv->fragTimer); + lwkt_token_init(&priv->token, "ng_ppp"); /* Done */ return (0); @@ -410,6 +416,18 @@ ng_ppp_constructor(node_p *nodep) */ static int ng_ppp_newhook(node_p node, hook_p hook, const char *name) +{ + const priv_p priv = node->private; + int ret; + + lwkt_gettoken(&priv->token); + ret = ng_ppp_newhook_unlocked(node, hook, name); + lwkt_reltoken(&priv->token); + return (ret); +} + +static int +ng_ppp_newhook_unlocked(node_p node, hook_p hook, const char *name) { const priv_p priv = node->private; int linkNum = -1; @@ -471,6 +489,7 @@ ng_ppp_rcvmsg(node_p node, struct ng_mesg *msg, struct ng_mesg *resp = NULL; int error = 0; + lwkt_gettoken(&priv->token); switch (msg->header.typecookie) { case NGM_PPP_COOKIE: switch (msg->header.cmd) { @@ -565,6 +584,7 @@ ng_ppp_rcvmsg(node_p node, struct ng_mesg *msg, ERROUT(error); ksnprintf(path, sizeof(path), "[%lx]:%s", (long)node, NG_PPP_HOOK_VJC_IP); + lwkt_reltoken(&priv->token); return ng_send_msg(origNode, msg, path, rptr); } default: @@ -578,6 +598,7 @@ ng_ppp_rcvmsg(node_p node, struct ng_mesg *msg, done: kfree(msg, M_NETGRAPH); + lwkt_reltoken(&priv->token); return (error); } @@ -586,6 +607,19 @@ ng_ppp_rcvmsg(node_p node, struct ng_mesg *msg, */ static int ng_ppp_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) +{ + const node_p node = hook->node; + const priv_p priv = node->private; + int ret; + + lwkt_gettoken(&priv->token); + ret = ng_ppp_rcvdata_unlocked(hook, m, meta); + lwkt_reltoken(&priv->token); + return (ret); +} + +static int +ng_ppp_rcvdata_unlocked(hook_p hook, struct mbuf *m, meta_p meta) { const node_p node = hook->node; const priv_p priv = node->private; @@ -793,6 +827,8 @@ ng_ppp_rmnode(node_p node) { const priv_p priv = node->private; + lwkt_gettoken(&priv->token); + /* Stop fragment queue timer */ ng_ppp_stop_frag_timer(node); @@ -801,6 +837,14 @@ ng_ppp_rmnode(node_p node) ng_cutlinks(node); ng_unname(node); ng_ppp_frag_reset(node); + /* + * All hooks are gone now, so no new rcvdata/rcvmsg can be + * dispatched. Drop the token before the private structure is + * freed so we never touch freed memory; any synchronous caller + * still spinning on the token sees valid (zeroed-by-bzero + * below) memory or an invalid hook and bails. + */ + lwkt_reltoken(&priv->token); bzero(priv, sizeof(*priv)); kfree(priv, M_NETGRAPH); node->private = NULL; @@ -818,6 +862,8 @@ ng_ppp_disconnect(hook_p hook) const priv_p priv = node->private; const int index = HOOK_INDEX(hook); + lwkt_gettoken(&priv->token); + /* Zero out hook pointer */ if (index < 0) priv->links[~index].hook = NULL; @@ -829,6 +875,7 @@ ng_ppp_disconnect(hook_p hook) ng_ppp_update(node, 0); else ng_rmnode(node); + lwkt_reltoken(&priv->token); return (0); } @@ -1457,6 +1504,7 @@ ng_ppp_frag_timeout(void *arg) crit_exit(); return; } + lwkt_gettoken(&priv->token); /* Reset timer state after timeout */ KASSERT(priv->timerActive, ("%s: !timerActive", __func__)); @@ -1469,6 +1517,7 @@ ng_ppp_frag_timeout(void *arg) /* Scan the fragment queue */ ng_ppp_frag_checkstale(node); + lwkt_reltoken(&priv->token); crit_exit(); } |