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.

> 
> diff --git sys/dev/pci/if_vio.c sys/dev/pci/if_vio.c
> index 97af2a2..d8c9798 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 *);
> @@ -1219,11 +1219,12 @@ vio_ctrl_rx(struct vio_softc *sc, int cmd, int onoff)
>  
>       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;
>  
> @@ -1246,14 +1247,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);
> @@ -1271,28 +1270,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;
> +                     r = EIO;
>                       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
> @@ -1334,11 +1343,12 @@ vio_set_rx_filter(struct vio_softc *sc)
>       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,
> @@ -1364,14 +1374,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);
> @@ -1436,29 +1444,22 @@ 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) {
> +     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.

> -             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.

> +     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.

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

>  
>       vio_ctrl_rx(sc, VIRTIO_NET_CTRL_RX_PROMISC, promisc);
>  }
> 
> 

Reply via email to