On Wed, Nov 23, 2016 at 21:52 +0100, Stefan Fritsch wrote:
> On Wed, 23 Nov 2016, Mike Belopuhov wrote:
> > This fixes up tsleep priorities in vio(4) and makes sleeps
> > interruptable so that ifconfig can be killed with ^C.  Tested
> > on qemu with a previous diff that makes vio(4) hang there.
> > 
> > OK?
> 
> I think the tsleep stuff is ok, but the vio_iff() changes are not.
>

The vio_iff changes are needed to get the interruptable sleep
working.  I've rewritten that part of the diff.

> > -   if (rxfilter) {
> > +   if (rxfilter)
> >             sc->sc_ctrl_mac_tbl_mc->nentries = nentries;
> > -           r = vio_set_rx_filter(sc);
> > -           if (r != 0) {
> > -                   rxfilter = 0;
> > -                   allmulti = 1; /* fallback */
> > -           }
> > -   } else {
> > -           sc->sc_ctrl_mac_tbl_mc->nentries = 0;
> 
> You must not remove this this in the !rxfilter case, or an old value of 
> nentries may be kept.
>

Ack.

> > -           vio_set_rx_filter(sc);
> > -   }
> >  
> > -   if (allmulti) {
> > -           r = vio_ctrl_rx(sc, VIRTIO_NET_CTRL_RX_ALLMULTI, 1);
> > -           if (r != 0) {
> > -                   allmulti = 0;
> > -                   promisc = 1; /* fallback */
> > -           }
> > -   } else {
> > -           vio_ctrl_rx(sc, VIRTIO_NET_CTRL_RX_ALLMULTI, 0);
> > -   }
> > +   r = vio_set_rx_filter(sc);
> > +   if (r && r != ENOTSUP)
> > +           return;
> 
> That's wrong. If the host's filter table is not large enough, 
> vio_set_rx_filter() will return EIO. In this case we should re-try with 
> promisc.
>

This wasn't documented and EIO wasn't explicitely handled which
made this code look strange.  This is a good reason to clean it up.

> > +   else if (r == ENOTSUP && rxfilter)
> > +           allmulti = 1; /* fallback */
> > +
> > +   r = vio_ctrl_rx(sc, VIRTIO_NET_CTRL_RX_ALLMULTI, allmulti);
> > +   if (r && r != ENOTSUP)
> > +           return;
> > +   else if (r == ENOTSUP && allmulti)
> > +           promisc = 1; /* fallback */
> 
> In the ENOTSUP case, vio_ctrl_rx() will always fail, too. There is no use 
> for a retry, then.
>

I think we can move the "vsc->sc_nvqs < 3" check out of those
functions to make it even more simpler.

> Maybe leave the logic unchanged, and just add a few checks to return in 
> case of EINTR?
> 

I propose less checks (or better ones if you will) since it's
a forest of if's as it is.

diff --git sys/dev/pci/if_vio.c sys/dev/pci/if_vio.c
index d2a56a3..3926edf 100644
--- sys/dev/pci/if_vio.c
+++ sys/dev/pci/if_vio.c
@@ -281,11 +281,11 @@ int       vio_ctrl_rx(struct vio_softc *, int, int);
 int    vio_set_rx_filter(struct vio_softc *);
 void   vio_iff(struct vio_softc *);
 int    vio_media_change(struct ifnet *);
 void   vio_media_status(struct ifnet *, struct ifmediareq *);
 int    vio_ctrleof(struct virtqueue *);
-void   vio_wait_ctrl(struct vio_softc *sc);
+int    vio_wait_ctrl(struct vio_softc *sc);
 int    vio_wait_ctrl_done(struct vio_softc *sc);
 void   vio_ctrl_wakeup(struct vio_softc *, enum vio_ctrl_state);
 int    vio_alloc_mem(struct vio_softc *);
 int    vio_alloc_dmamem(struct vio_softc *);
 void   vio_free_dmamem(struct vio_softc *);
@@ -1216,15 +1216,14 @@ vio_ctrl_rx(struct vio_softc *sc, int cmd, int onoff)
 {
        struct virtio_softc *vsc = sc->sc_virtio;
        struct virtqueue *vq = &sc->sc_vq[VQCTL];
        int r, slot;
 
-       if (vsc->sc_nvqs < 3)
-               return ENOTSUP;
-
        splassert(IPL_NET);
-       vio_wait_ctrl(sc);
+
+       if ((r = vio_wait_ctrl(sc)) != 0)
+               return r;
 
        sc->sc_ctrl_cmd->class = VIRTIO_NET_CTRL_RX;
        sc->sc_ctrl_cmd->command = cmd;
        sc->sc_ctrl_rx->onoff = onoff;
 
@@ -1247,14 +1246,12 @@ vio_ctrl_rx(struct vio_softc *sc, int cmd, int onoff)
            sizeof(*sc->sc_ctrl_rx), 1);
        VIO_DMAMEM_ENQUEUE(sc, vq, slot, sc->sc_ctrl_status,
            sizeof(*sc->sc_ctrl_status), 0);
        virtio_enqueue_commit(vsc, vq, slot, 1);
 
-       if (vio_wait_ctrl_done(sc)) {
-               r = EIO;
+       if ((r = vio_wait_ctrl_done(sc)) != 0)
                goto out;
-       }
 
        VIO_DMAMEM_SYNC(vsc, sc, sc->sc_ctrl_cmd,
            sizeof(*sc->sc_ctrl_cmd), BUS_DMASYNC_POSTWRITE);
        VIO_DMAMEM_SYNC(vsc, sc, sc->sc_ctrl_rx,
            sizeof(*sc->sc_ctrl_rx), BUS_DMASYNC_POSTWRITE);
@@ -1272,28 +1269,38 @@ vio_ctrl_rx(struct vio_softc *sc, int cmd, int onoff)
 out:
        vio_ctrl_wakeup(sc, FREE);
        return r;
 }
 
-void
+int
 vio_wait_ctrl(struct vio_softc *sc)
 {
-       while (sc->sc_ctrl_inuse != FREE)
-               tsleep(&sc->sc_ctrl_inuse, IPL_NET, "vio_wait", 0);
+       int r = 0;
+
+       while (sc->sc_ctrl_inuse != FREE) {
+               r = tsleep(&sc->sc_ctrl_inuse, PRIBIO|PCATCH, "viowait", 0);
+               if (r == EINTR)
+                       return r;
+       }
        sc->sc_ctrl_inuse = INUSE;
+
+       return r;
 }
 
 int
 vio_wait_ctrl_done(struct vio_softc *sc)
 {
        int r = 0;
+
        while (sc->sc_ctrl_inuse != DONE && sc->sc_ctrl_inuse != RESET) {
                if (sc->sc_ctrl_inuse == RESET) {
                        r = 1;
                        break;
                }
-               tsleep(&sc->sc_ctrl_inuse, IPL_NET, "vio_wait", 0);
+               r = tsleep(&sc->sc_ctrl_inuse, PRIBIO|PCATCH, "viodone", 0);
+               if (r == EINTR)
+                       break;
        }
        return r;
 }
 
 void
@@ -1332,14 +1339,12 @@ vio_set_rx_filter(struct vio_softc *sc)
        struct virtqueue *vq = &sc->sc_vq[VQCTL];
        int r, slot;
 
        splassert(IPL_NET);
 
-       if (vsc->sc_nvqs < 3)
-               return ENOTSUP;
-
-       vio_wait_ctrl(sc);
+       if ((r = vio_wait_ctrl(sc)) != 0)
+               return r;
 
        sc->sc_ctrl_cmd->class = VIRTIO_NET_CTRL_MAC;
        sc->sc_ctrl_cmd->command = VIRTIO_NET_CTRL_MAC_TABLE_SET;
 
        VIO_DMAMEM_SYNC(vsc, sc, sc->sc_ctrl_cmd,
@@ -1365,14 +1370,12 @@ vio_set_rx_filter(struct vio_softc *sc)
            sc->sc_ctrl_mac_tbl_mc->nentries * ETHER_ADDR_LEN, 1);
        VIO_DMAMEM_ENQUEUE(sc, vq, slot, sc->sc_ctrl_status,
            sizeof(*sc->sc_ctrl_status), 0);
        virtio_enqueue_commit(vsc, vq, slot, 1);
 
-       if (vio_wait_ctrl_done(sc)) {
-               r = EIO;
+       if ((r = vio_wait_ctrl_done(sc)) != 0)
                goto out;
-       }
 
        VIO_DMAMEM_SYNC(vsc, sc, sc->sc_ctrl_cmd,
            sizeof(*sc->sc_ctrl_cmd), BUS_DMASYNC_POSTWRITE);
        VIO_DMAMEM_SYNC(vsc, sc, sc->sc_ctrl_mac_info,
            VIO_CTRL_MAC_INFO_SIZE, BUS_DMASYNC_POSTWRITE);
@@ -1380,10 +1383,11 @@ vio_set_rx_filter(struct vio_softc *sc)
            sizeof(*sc->sc_ctrl_status), BUS_DMASYNC_POSTREAD);
 
        if (sc->sc_ctrl_status->ack == VIRTIO_NET_OK) {
                r = 0;
        } else {
+               /* The host's filter table is not large enough */
                printf("%s: failed setting rx filter\n", sc->sc_dev.dv_xname);
                r = EIO;
        }
 
 out:
@@ -1437,29 +1441,24 @@ vio_iff(struct vio_softc *sc)
 
        /* set unicast address, VirtualBox wants that */
        memcpy(sc->sc_ctrl_mac_tbl_uc->macs[0], ac->ac_enaddr, ETHER_ADDR_LEN);
        sc->sc_ctrl_mac_tbl_uc->nentries = 1;
 
-       if (rxfilter) {
-               sc->sc_ctrl_mac_tbl_mc->nentries = nentries;
-               r = vio_set_rx_filter(sc);
-               if (r != 0) {
-                       rxfilter = 0;
-                       allmulti = 1; /* fallback */
-               }
-       } else {
-               sc->sc_ctrl_mac_tbl_mc->nentries = 0;
-               vio_set_rx_filter(sc);
-       }
+       sc->sc_ctrl_mac_tbl_mc->nentries = rxfilter ? nentries : 0;
 
-       if (allmulti) {
-               r = vio_ctrl_rx(sc, VIRTIO_NET_CTRL_RX_ALLMULTI, 1);
-               if (r != 0) {
-                       allmulti = 0;
-                       promisc = 1; /* fallback */
-               }
-       } else {
-               vio_ctrl_rx(sc, VIRTIO_NET_CTRL_RX_ALLMULTI, 0);
-       }
+       if (vsc->sc_nvqs < 3)
+               return;
+
+       r = vio_set_rx_filter(sc);
+       if (r == EIO)
+               allmulti = 1; /* fallback */
+       else if (r != 0)
+               return;
+
+       r = vio_ctrl_rx(sc, VIRTIO_NET_CTRL_RX_ALLMULTI, allmulti);
+       if (r == EIO)
+               promisc = 1; /* fallback */
+       else if (r != 0)
+               return;
 
        vio_ctrl_rx(sc, VIRTIO_NET_CTRL_RX_PROMISC, promisc);
 }

Reply via email to