Author: np
Date: Mon Aug  4 22:32:16 2014
New Revision: 269537
URL: http://svnweb.freebsd.org/changeset/base/269537

Log:
  cxgbe(4): Do not run any sleepable code in the SIOCSIFFLAGS handler when
  IFF_PROMISC or IFF_ALLMULTI is being flipped.  bpf(4) holds its global
  mutex around ifpromisc in at least the bpf_dtor path.
  
  MFC after:    3 days

Modified:
  head/sys/dev/cxgbe/t4_main.c

Modified: head/sys/dev/cxgbe/t4_main.c
==============================================================================
--- head/sys/dev/cxgbe/t4_main.c        Mon Aug  4 22:31:09 2014        
(r269536)
+++ head/sys/dev/cxgbe/t4_main.c        Mon Aug  4 22:32:16 2014        
(r269537)
@@ -1178,7 +1178,7 @@ cxgbe_init(void *arg)
 static int
 cxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
 {
-       int rc = 0, mtu, flags;
+       int rc = 0, mtu, flags, can_sleep;
        struct port_info *pi = ifp->if_softc;
        struct adapter *sc = pi->adapter;
        struct ifreq *ifr = (struct ifreq *)data;
@@ -1203,7 +1203,10 @@ cxgbe_ioctl(struct ifnet *ifp, unsigned 
                break;
 
        case SIOCSIFFLAGS:
-               rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4flg");
+               can_sleep = 0;
+redo_sifflags:
+               rc = begin_synchronized_op(sc, pi,
+                   can_sleep ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4flg");
                if (rc)
                        return (rc);
 
@@ -1212,15 +1215,32 @@ cxgbe_ioctl(struct ifnet *ifp, unsigned 
                                flags = pi->if_flags;
                                if ((ifp->if_flags ^ flags) &
                                    (IFF_PROMISC | IFF_ALLMULTI)) {
+                                       if (can_sleep == 1) {
+                                               end_synchronized_op(sc, 0);
+                                               can_sleep = 0;
+                                               goto redo_sifflags;
+                                       }
                                        rc = update_mac_settings(ifp,
                                            XGMAC_PROMISC | XGMAC_ALLMULTI);
                                }
-                       } else
+                       } else {
+                               if (can_sleep == 0) {
+                                       end_synchronized_op(sc, LOCK_HELD);
+                                       can_sleep = 1;
+                                       goto redo_sifflags;
+                               }
                                rc = cxgbe_init_synchronized(pi);
+                       }
                        pi->if_flags = ifp->if_flags;
-               } else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+               } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+                       if (can_sleep == 0) {
+                               end_synchronized_op(sc, LOCK_HELD);
+                               can_sleep = 1;
+                               goto redo_sifflags;
+                       }
                        rc = cxgbe_uninit_synchronized(pi);
-               end_synchronized_op(sc, 0);
+               }
+               end_synchronized_op(sc, can_sleep ? 0 : LOCK_HELD);
                break;
 
        case SIOCADDMULTI:
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to