On Thursday, December 29, 2011 3:27:26 pm John Baldwin wrote:
> On Thursday, December 22, 2011 11:30:01 am John Baldwin wrote:
> > Another bit of lock contention I ran into between a device driver doing 
> > slow 
> > MAC filter updates and the receive path is IF_ADDR_LOCK().  NIC device 
> > drivers 
> > typically hold this lock while iterating the list of multicast addresses to 
> > program their MAC filter.  OTOH, ip_input() uses this lock to check to see 
> > if 
> > an incoming packet is a broadcast packet or not.  So even with the pcbinfo
> > contention from my previous patch addressed, I still ran into a problem 
> > with 
> > IF_ADDR_LOCK().  We already have some partial support for making this lock 
> > be 
> > an rwlock (the APIs that drivers now use implies an rlock), so I finished 
> > the 
> > transition and checked various non-driver users to see which ones could use 
> > a 
> > read lock (most uses can).  The current patch I have for this is on 8, but 
> > if 
> > folks think this is a good idea I can work on porting it to HEAD.  For HEAD 
> > the strategy I would use would be to split this up into 2 phases:
> > 
> > 1) Add IF_ADDR locking macros to differentiate read locks vs write locks 
> > along
> >    with appropriate assertion macros.  Update current users of the locking
> >    macros to use either read or write locks explicitly.  To preserve KPI,
> >    the existing LOCK/UNLOCK macros would map to write lock operations.  In
> >    the initial patch, the locking would still be implemented via a mtx.
> > 
> > 2) Replace the mutex with an rwlock and update the locking macros as
> >    appropriate.
> > 
> > Phase 1 should definitely be MFC'able.  Phase 2 may or may not be.  Robert 
> > had 
> > the foresight to change drivers to use explicit function wrappers around 
> > IF_ADDR_LOCK, and sizeof(struct mtx) == sizeof(struct rwlock), so if we 
> > changed the lock type the KBI for existing device drivers would all be 
> > fine.  
> > Most of the remaining uses of the locking macros are in parts of the kernel 
> > that aren't loadable (such as inet and inet6).  We can look at the places 
> > that 
> > to do change and if any of them are in kld's then it would be up to re@ to 
> > decide if 2) was actually safe to merge.  However, even if Phase 2 cannot 
> > be 
> > MFC'd, having phase 1 makes it easier for downstream consumers to apply 
> > Phase 
> > 2 locally if they need it.
> 
> I've gone ahead with this approach.  I have three separate patches that should
> implement Phase 1.  All of them can be found at
> http://www.FreeBSD.org/~jhb/patches/
> 
> - if_addr_dev.patch      This fixes a few new device drivers that were using
>                          the locking macros directly rather than the wrapper
>                          functions Robert added.  I've already sent this
>                          directly to the relevant driver maintainers for their
>                          review.
> - if_addr_macros.patch   This adds new locking macros to support read locks vs
>                          write locks.  However, they all still map to mutex
>                          operations.
> - if_addr_uses.patch     This changes callers of the existing macros to use
>                          either read or write locks.  This is the patch that
>                          could use the most review.

Now that all of this is in the tree, here is the small patch to cut the locks
over to rwlocks rather than mutexes:

Index: kern/subr_witness.c
===================================================================
--- kern/subr_witness.c (revision 229726)
+++ kern/subr_witness.c (working copy)
@@ -520,7 +520,7 @@
        { "udpinp", &lock_class_rw },
        { "in_multi_mtx", &lock_class_mtx_sleep },
        { "igmp_mtx", &lock_class_mtx_sleep },
-       { "if_addr_mtx", &lock_class_mtx_sleep },
+       { "if_addr_lock", &lock_class_rw },
        { NULL, NULL },
        /*
         * IPv6 multicast:
@@ -529,7 +529,7 @@
        { "udpinp", &lock_class_rw },
        { "in6_multi_mtx", &lock_class_mtx_sleep },
        { "mld_mtx", &lock_class_mtx_sleep },
-       { "if_addr_mtx", &lock_class_mtx_sleep },
+       { "if_addr_lock", &lock_class_rw },
        { NULL, NULL },
        /*
         * UNIX Domain Sockets
Index: net/if_var.h
===================================================================
--- net/if_var.h        (revision 229726)
+++ net/if_var.h        (working copy)
@@ -189,7 +189,7 @@
        int     if_afdata_initialized;
        struct  rwlock if_afdata_lock;
        struct  task if_linktask;       /* task for link change events */
-       struct  mtx if_addr_mtx;        /* mutex to protect address lists */
+       struct  rwlock if_addr_lock;    /* lock to protect address lists */
 
        LIST_ENTRY(ifnet) if_clones;    /* interfaces of a cloner */
        TAILQ_HEAD(, ifg_list) if_groups; /* linked list of groups per if */
@@ -246,15 +246,14 @@
 /*
  * Locks for address lists on the network interface.
  */
-#define        IF_ADDR_LOCK_INIT(if)   mtx_init(&(if)->if_addr_mtx,            
\
-                                   "if_addr_mtx", NULL, MTX_DEF)
-#define        IF_ADDR_LOCK_DESTROY(if)        mtx_destroy(&(if)->if_addr_mtx)
-#define        IF_ADDR_WLOCK(if)       mtx_lock(&(if)->if_addr_mtx)
-#define        IF_ADDR_WUNLOCK(if)     mtx_unlock(&(if)->if_addr_mtx)
-#define        IF_ADDR_RLOCK(if)       mtx_lock(&(if)->if_addr_mtx)
-#define        IF_ADDR_RUNLOCK(if)     mtx_unlock(&(if)->if_addr_mtx)
-#define        IF_ADDR_LOCK_ASSERT(if) mtx_assert(&(if)->if_addr_mtx, MA_OWNED)
-#define        IF_ADDR_WLOCK_ASSERT(if)        mtx_assert(&(if)->if_addr_mtx, 
MA_OWNED)
+#define        IF_ADDR_LOCK_INIT(if)   rw_init(&(if)->if_addr_lock, 
"if_addr_lock")
+#define        IF_ADDR_LOCK_DESTROY(if)        rw_destroy(&(if)->if_addr_lock)
+#define        IF_ADDR_WLOCK(if)       rw_wlock(&(if)->if_addr_lock)
+#define        IF_ADDR_WUNLOCK(if)     rw_wunlock(&(if)->if_addr_lock)
+#define        IF_ADDR_RLOCK(if)       rw_rlock(&(if)->if_addr_lock)
+#define        IF_ADDR_RUNLOCK(if)     rw_runlock(&(if)->if_addr_lock)
+#define        IF_ADDR_LOCK_ASSERT(if) rw_assert(&(if)->if_addr_lock, 
RA_LOCKED)
+#define        IF_ADDR_WLOCK_ASSERT(if) rw_assert(&(if)->if_addr_lock, 
RA_WLOCKED)
 /* XXX: Compat. */
 #define        IF_ADDR_LOCK(if)        IF_ADDR_WLOCK(if)
 #define        IF_ADDR_UNLOCK(if)      IF_ADDR_WUNLOCK(if)

-- 
John Baldwin
_______________________________________________
freebsd-net@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org"

Reply via email to