Module Name: src
Committed By: pooka
Date: Wed Nov 17 17:51:22 UTC 2010
Modified Files:
src/sys/rump/net/lib/libshmif: if_shmem.c
Log Message:
Support destroy in shmif.
To generate a diff of this commit:
cvs rdiff -u -r1.31 -r1.32 src/sys/rump/net/lib/libshmif/if_shmem.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/rump/net/lib/libshmif/if_shmem.c
diff -u src/sys/rump/net/lib/libshmif/if_shmem.c:1.31 src/sys/rump/net/lib/libshmif/if_shmem.c:1.32
--- src/sys/rump/net/lib/libshmif/if_shmem.c:1.31 Tue Nov 16 20:08:24 2010
+++ src/sys/rump/net/lib/libshmif/if_shmem.c Wed Nov 17 17:51:22 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: if_shmem.c,v 1.31 2010/11/16 20:08:24 pooka Exp $ */
+/* $NetBSD: if_shmem.c,v 1.32 2010/11/17 17:51:22 pooka Exp $ */
/*
* Copyright (c) 2009 Antti Kantee. All Rights Reserved.
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_shmem.c,v 1.31 2010/11/16 20:08:24 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_shmem.c,v 1.32 2010/11/17 17:51:22 pooka Exp $");
#include <sys/param.h>
#include <sys/atomic.h>
@@ -81,12 +81,19 @@
struct shmif_mem *sc_busmem;
int sc_memfd;
int sc_kq;
+ int sc_unit;
char *sc_backfile;
size_t sc_backfilelen;
uint64_t sc_devgen;
uint32_t sc_nextpacket;
+
+ kmutex_t sc_mtx;
+ kcondvar_t sc_cv;
+
+ struct lwp *sc_rcvl;
+ bool sc_dying;
};
static const uint32_t busversion = SHMIF_VERSION;
@@ -142,18 +149,19 @@
struct shmif_sc *sc;
struct ifnet *ifp;
uint32_t randnum;
- unsigned mynum = unit;
+ int error;
randnum = arc4random();
memcpy(&enaddr[2], &randnum, sizeof(randnum));
sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
sc->sc_memfd = -1;
+ sc->sc_unit = unit;
ifp = &sc->sc_ec.ec_if;
memcpy(sc->sc_myaddr, enaddr, sizeof(enaddr));
- sprintf(ifp->if_xname, "shmif%d", mynum);
+ sprintf(ifp->if_xname, "shmif%d", unit);
ifp->if_softc = sc;
ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST;
ifp->if_init = shmif_init;
@@ -162,16 +170,32 @@
ifp->if_stop = shmif_stop;
ifp->if_mtu = ETHERMTU;
+ mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NONE);
+ cv_init(&sc->sc_cv, "shmifcv");
+
if_attach(ifp);
ether_ifattach(ifp, enaddr);
aprint_verbose("shmif%d: Ethernet address %s\n",
- mynum, ether_sprintf(enaddr));
+ unit, ether_sprintf(enaddr));
if (scp)
*scp = sc;
- return 0;
+ error = 0;
+ if (rump_threads) {
+ error = kthread_create(PRI_NONE,
+ KTHREAD_MPSAFE | KTHREAD_JOINABLE, NULL,
+ shmif_rcv, ifp, &sc->sc_rcvl, "shmif");
+ } else {
+ printf("WARNING: threads not enabled, shmif NOT working\n");
+ }
+
+ if (error) {
+ shmif_unclone(ifp);
+ }
+
+ return error;
}
static int
@@ -221,48 +245,56 @@
shmif_unlockbus(sc->sc_busmem);
sc->sc_kq = rumpuser_writewatchfile_setup(-1, memfd, 0, &error);
- if (sc->sc_kq == -1)
+ if (sc->sc_kq == -1) {
+ rumpuser_unmap(sc->sc_busmem, BUSMEM_SIZE);
return error;
+ }
sc->sc_memfd = memfd;
- return 0;
+
+ return error;
}
static void
finibackend(struct shmif_sc *sc)
{
- int dummy;
- kmem_free(sc->sc_backfile, sc->sc_backfilelen);
- sc->sc_backfile = NULL;
- sc->sc_backfilelen = 0;
+ if (sc->sc_backfile == NULL)
+ return;
+
+ if (sc->sc_backfile) {
+ kmem_free(sc->sc_backfile, sc->sc_backfilelen);
+ sc->sc_backfile = NULL;
+ sc->sc_backfilelen = 0;
+ }
rumpuser_unmap(sc->sc_busmem, BUSMEM_SIZE);
- rumpuser_close(sc->sc_memfd, &dummy);
- rumpuser_close(sc->sc_kq, &dummy);
+ rumpuser_close(sc->sc_memfd, NULL);
+ rumpuser_close(sc->sc_kq, NULL);
+
+ sc->sc_memfd = -1;
}
int
rump_shmif_create(const char *path, int *ifnum)
{
struct shmif_sc *sc;
- int mynum, error, memfd, dummy;
+ int unit, error, memfd;
memfd = rumpuser_open(path, O_RDWR | O_CREAT, &error);
if (memfd == -1)
return error;
- mynum = vmem_xalloc(shmif_units, 1, 0, 0, 0, 0, 0,
+ unit = vmem_xalloc(shmif_units, 1, 0, 0, 0, 0, 0,
VM_INSTANTFIT | VM_SLEEP) - 1;
- if ((error = allocif(mynum, &sc)) != 0) {
+ if ((error = allocif(unit, &sc)) != 0) {
rumpuser_close(memfd, NULL);
return error;
}
error = initbackend(sc, memfd);
if (error) {
- rumpuser_close(memfd, &dummy);
- /* XXX: free sc */
+ shmif_unclone(&sc->sc_ec.ec_if);
return error;
}
@@ -271,7 +303,7 @@
strcpy(sc->sc_backfile, path);
if (ifnum)
- *ifnum = mynum;
+ *ifnum = unit;
return 0;
}
@@ -300,8 +332,32 @@
static int
shmif_unclone(struct ifnet *ifp)
{
+ struct shmif_sc *sc = ifp->if_softc;
+
+ shmif_stop(ifp, 1);
+ if_down(ifp);
+ finibackend(sc);
+
+ mutex_enter(&sc->sc_mtx);
+ sc->sc_dying = true;
+ cv_broadcast(&sc->sc_cv);
+ mutex_exit(&sc->sc_mtx);
- return EOPNOTSUPP;
+ if (sc->sc_rcvl)
+ kthread_join(sc->sc_rcvl);
+ sc->sc_rcvl = NULL;
+
+ vmem_xfree(shmif_units, sc->sc_unit+1, 1);
+
+ ether_ifdetach(ifp);
+ if_detach(ifp);
+
+ cv_destroy(&sc->sc_cv);
+ mutex_destroy(&sc->sc_mtx);
+
+ kmem_free(sc, sizeof(*sc));
+
+ return 0;
}
static int
@@ -312,15 +368,17 @@
if (sc->sc_memfd == -1)
return ENXIO;
-
- if (rump_threads) {
- error = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
- shmif_rcv, ifp, NULL, "shmif");
- } else {
- printf("WARNING: threads not enabled, shmif NOT working\n");
- }
+ KASSERT(sc->sc_busmem);
ifp->if_flags |= IFF_RUNNING;
+
+ mutex_enter(&sc->sc_mtx);
+ sc->sc_nextpacket = sc->sc_busmem->shm_last;
+ sc->sc_devgen = sc->sc_busmem->shm_gen;
+
+ cv_broadcast(&sc->sc_cv);
+ mutex_exit(&sc->sc_mtx);
+
return error;
}
@@ -330,7 +388,7 @@
struct shmif_sc *sc = ifp->if_softc;
struct ifdrv *ifd;
char *path;
- int s, rv, memfd, dummy;
+ int s, rv, memfd;
s = splnet();
switch (cmd) {
@@ -397,7 +455,7 @@
rv = initbackend(sc, memfd);
if (rv) {
kmem_free(path, ifd->ifd_len);
- rumpuser_close(memfd, &dummy);
+ rumpuser_close(memfd, NULL);
break;
}
sc->sc_backfile = path;
@@ -415,7 +473,7 @@
return rv;
}
-/* send everything in-context */
+/* send everything in-context since it's just a matter of mem-to-mem copy */
static void
shmif_start(struct ifnet *ifp)
{
@@ -479,7 +537,7 @@
ifp->if_flags &= ~IFF_OACTIVE;
- /* wakeup */
+ /* wakeup? */
if (wrote)
rumpuser_pwrite(sc->sc_memfd,
&busversion, sizeof(busversion), IFMEM_WAKEUP, &error);
@@ -488,8 +546,18 @@
static void
shmif_stop(struct ifnet *ifp, int disable)
{
+ struct shmif_sc *sc = ifp->if_softc;
- panic("%s: unimpl", __func__);
+ ifp->if_flags &= ~IFF_RUNNING;
+ membar_producer();
+
+ /*
+ * wakeup thread. this will of course wake up all bus
+ * listeners, but that's life.
+ */
+ if (sc->sc_memfd != -1)
+ rumpuser_pwrite(sc->sc_memfd,
+ &busversion, sizeof(busversion), IFMEM_WAKEUP, NULL);
}
@@ -535,14 +603,22 @@
{
struct ifnet *ifp = arg;
struct shmif_sc *sc = ifp->if_softc;
- struct shmif_mem *busmem = sc->sc_busmem;
+ struct shmif_mem *busmem;
struct mbuf *m = NULL;
struct ether_header *eth;
uint32_t nextpkt;
bool wrap;
int error;
- for (;;) {
+ reup:
+ mutex_enter(&sc->sc_mtx);
+ while ((ifp->if_flags & IFF_RUNNING) == 0 && !sc->sc_dying)
+ cv_wait(&sc->sc_cv, &sc->sc_mtx);
+ mutex_exit(&sc->sc_mtx);
+
+ busmem = sc->sc_busmem;
+
+ while (ifp->if_flags & IFF_RUNNING) {
struct shmif_pkthdr sp;
if (m == NULL) {
@@ -566,6 +642,7 @@
rumpuser_writewatchfile_wait(sc->sc_kq, NULL, &error);
if (__predict_false(error))
printf("shmif_rcv: wait failed %d\n", error);
+ membar_consumer();
continue;
}
@@ -620,6 +697,11 @@
m = NULL;
}
}
+ m_freem(m);
+ m = NULL;
+
+ if (!sc->sc_dying)
+ goto reup;
- panic("shmif_worker is a lazy boy %d\n", error);
+ kthread_exit(0);
}