diff --git a/sys/netgraph/ng_device.c b/sys/netgraph/ng_device.c --- a/sys/netgraph/ng_device.c +++ b/sys/netgraph/ng_device.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -94,6 +95,7 @@ /* global data */ struct ngd_softc { SLIST_HEAD(, ngd_connection) head; + struct spinlock ngd_lock; /* protects the connection list */ node_p node; char nodename[NG_NODESIZ]; @@ -180,6 +182,7 @@ #endif /* NGD_DEBUG */ SLIST_INIT(&sc->head); + spin_lock_init(&sc->ngd_lock); if (ng_make_node_common(&typestruct, &sc->node) != 0) { kprintf("%s(): ng_make_node_common failed\n", __func__); @@ -233,8 +236,10 @@ kprintf("%s()\n", __func__); #endif /* NGD_DEBUG */ + spin_lock(&sc->ngd_lock); /* When there is no list yet, the first device unit is always 0. */ if (SLIST_EMPTY(&sc->head)) { + spin_unlock(&sc->ngd_lock); unit = 0; return(unit); } @@ -253,6 +258,7 @@ unit = n; } } + spin_unlock(&sc->ngd_lock); return(unit); } @@ -306,7 +312,9 @@ new_connection->loc = 0; new_connection->active_hook = hook; + spin_lock(&sc->ngd_lock); SLIST_INSERT_HEAD(&sc->head, new_connection, links); + spin_unlock(&sc->ngd_lock); return(0); } @@ -342,11 +350,13 @@ kprintf("%s()\n", __func__); #endif /* NGD_DEBUG */ + spin_lock(&sc->ngd_lock); SLIST_FOREACH(tmp, &sc->head, links) { if(tmp->active_hook == hook) { connection = tmp; } } + spin_unlock(&sc->ngd_lock); if(connection == NULL) { kprintf("%s(): connection still NULL, no hook found\n", __func__); return(-1); @@ -393,22 +403,26 @@ kprintf("%s()\n", __func__); #endif /* NGD_DEBUG */ + spin_lock(&sc->ngd_lock); SLIST_FOREACH(tmp, &sc->head, links) { if(tmp->active_hook == hook) { connection = tmp; } } if(connection == NULL) { + spin_unlock(&sc->ngd_lock); kprintf("%s(): connection still NULL, no hook found\n", __func__); return(-1); } + SLIST_REMOVE(&sc->head, connection, ngd_connection, links); + spin_unlock(&sc->ngd_lock); - kfree(connection->readq, M_DEVBUF); - + /* disconnect no longer touches the list; drain cdev readers BEFORE + * freeing readq so in-flight ngdread/ngdwrite observe a live object. */ destroy_dev(connection->ngddev); - - SLIST_REMOVE(&sc->head, connection, ngd_connection, links); + kfree(connection->readq, M_DEVBUF); + kfree(connection, M_DEVBUF); return(0); } @@ -461,11 +475,13 @@ kprintf("%s()\n", __func__); #endif /* NGD_DEBUG */ + spin_lock(&sc->ngd_lock); SLIST_FOREACH(tmp, &sc->head, links) { if(tmp->ngddev == dev) { connection = tmp; } } + spin_unlock(&sc->ngd_lock); if(connection == NULL) { kprintf("%s(): connection still NULL, no dev found\n", __func__); @@ -515,11 +531,13 @@ kprintf("%s()\n", __func__); #endif /* NGD_DEBUG */ + spin_lock(&sc->ngd_lock); SLIST_FOREACH(tmp, &sc->head, links) { if(tmp->ngddev == dev) { connection = tmp; } } + spin_unlock(&sc->ngd_lock); if(connection == NULL) { kprintf("%s(): connection still NULL, no dev found\n", __func__); return(-1); @@ -569,11 +587,13 @@ kprintf("%s()\n", __func__); #endif /* NGD_DEBUG */ + spin_lock(&sc->ngd_lock); SLIST_FOREACH(tmp, &sc->head, links) { if(tmp->ngddev == dev) { connection = tmp; } } + spin_unlock(&sc->ngd_lock); if(connection == NULL) { kprintf("%s(): connection still NULL, no dev found\n", __func__); @@ -614,11 +634,13 @@ if (events & (POLLIN | POLLRDNORM)) { /* get the connection we have to know the loc from */ + spin_lock(&sc->ngd_lock); SLIST_FOREACH(tmp, &sc->head, links) { if(tmp->ngddev == dev) { connection = tmp; } } + spin_unlock(&sc->ngd_lock); if(connection == NULL) { kprintf("%s(): ERROR: connection still NULL, " "no dev found\n", __func__);