diff options
author | glebius <glebius@FreeBSD.org> | 2005-07-05 17:35:20 +0000 |
---|---|---|
committer | glebius <glebius@FreeBSD.org> | 2005-07-05 17:35:20 +0000 |
commit | fcbdfd0eb4f509af7f2a382daaf2c52ce49704c8 (patch) | |
tree | 7c65a2a332dab7cec59b3eb4bdcbf403ceaac133 /sys/netgraph/ng_socket.c | |
parent | 9c552f7c01059c885fb0604e8fc082ce51f3228a (diff) | |
download | FreeBSD-src-fcbdfd0eb4f509af7f2a382daaf2c52ce49704c8.zip FreeBSD-src-fcbdfd0eb4f509af7f2a382daaf2c52ce49704c8.tar.gz |
In the splnet times, netgraph was functional and synchronous. Nowadays,
an item may be queued and processed later. While this is OK for mbufs,
this is a problem for control messages.
In the framework:
- Add optional callback function pointer to an item. When item gets
applied the callback is executed from ng_apply_item().
- Add new flag NG_PROGRESS. If this flag is supplied, then return
EINPROGRESS instead of 0 in case if item failed to deliver
synchronously and was queued.
- Honor NG_PROGRESS in ng_snd_item().
In ng_socket:
- When userland sends control message add callback to the item.
- If ng_snd_item() returns EINPROGRESS, then sleep.
This change fixes possible races in ngctl(8) scripts.
Reviewed by: julian
Approved by: re (scottl)
Diffstat (limited to 'sys/netgraph/ng_socket.c')
-rw-r--r-- | sys/netgraph/ng_socket.c | 45 |
1 files changed, 44 insertions, 1 deletions
diff --git a/sys/netgraph/ng_socket.c b/sys/netgraph/ng_socket.c index c016955..63be343 100644 --- a/sys/netgraph/ng_socket.c +++ b/sys/netgraph/ng_socket.c @@ -131,6 +131,7 @@ static int ng_bind(struct sockaddr *nam, struct ngpcb *pcbp); static int ngs_mod_event(module_t mod, int event, void *data); static int ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr); +static void ng_socket_item_applied(void *context, int error); /* Netgraph type descriptor */ static struct ng_type typestruct = { @@ -208,6 +209,7 @@ ngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, struct mbuf *control, struct thread *td) { struct ngpcb *const pcbp = sotongpcb(so); + struct ngsock *const priv = NG_NODE_PRIVATE(pcbp->sockdata->node); struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; struct ng_mesg *msg; struct mbuf *m0; @@ -332,7 +334,29 @@ ngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, item->el_dest->nd_type->name); #endif SAVE_LINE(item); - error = ng_snd_item(item, NG_NOFLAGS); + /* + * We do not want to return from syscall until the item + * is processed by destination node. We register callback + * on the item, which will update priv->error when item + * was applied. + * If ng_snd_item() has queued item, we sleep until + * callback wakes us up. + */ + item->apply = ng_socket_item_applied; + item->context = priv; + priv->error = -1; + + error = ng_snd_item(item, NG_PROGRESS); + + if (error == EINPROGRESS) { + mtx_lock(&priv->mtx); + if (priv->error == -1) + msleep(priv, &priv->mtx, 0, "ngsock", 0); + mtx_unlock(&priv->mtx); + KASSERT(priv->error != -1, + ("ng_socket: priv->error wasn't updated")); + error = priv->error; + } release: if (path != NULL) @@ -553,6 +577,8 @@ ng_attach_cntl(struct socket *so) } NG_NODE_SET_PRIVATE(privdata->node, privdata); + mtx_init(&privdata->mtx, "ng_socket", NULL, MTX_DEF); + /* Link the pcb and the node private data */ privdata->ctlsock = pcbp; pcbp->sockdata = privdata; @@ -813,6 +839,10 @@ ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr) return (0); } +/*************************************************************** + Netgraph node +***************************************************************/ + /* * You can only create new nodes from the socket end of things. */ @@ -1020,10 +1050,23 @@ ngs_shutdown(node_p node) } NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(node); + mtx_destroy(&priv->mtx); FREE(priv, M_NETGRAPH_SOCK); return (0); } +static void +ng_socket_item_applied(void *context, int error) +{ + struct ngsock *const priv = (struct ngsock *)context; + + mtx_lock(&priv->mtx); + priv->error = error; + wakeup(priv); + mtx_unlock(&priv->mtx); + +} + static int dummy_disconnect(struct socket *so) { |