summaryrefslogtreecommitdiffstats
path: root/sys/netgraph/ng_socket.c
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2005-07-05 17:35:20 +0000
committerglebius <glebius@FreeBSD.org>2005-07-05 17:35:20 +0000
commitfcbdfd0eb4f509af7f2a382daaf2c52ce49704c8 (patch)
tree7c65a2a332dab7cec59b3eb4bdcbf403ceaac133 /sys/netgraph/ng_socket.c
parent9c552f7c01059c885fb0604e8fc082ce51f3228a (diff)
downloadFreeBSD-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.c45
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)
{
OpenPOWER on IntegriCloud