Author: emaste
Date: Thu Mar 28 20:48:40 2013
New Revision: 248852
URL: http://svnweb.freebsd.org/changeset/base/248852

Log:
  MFC r244183 by glebius:
  
    Fix problem in r238990 (MFC'd in r240313).  The LLE_LINKED flag should be
    tested prior to entering llentry_free(), and in case if we lose the race,
    we should simply perform LLE_FREE_LOCKED().  Otherwise, if the race is
    lost by the thread performing arptimer(), it will remove two references
    from the lle instead of one.
  
    Reported by:        Ian FREISLICH <ianf clue.co.za>

Modified:
  stable/9/sys/net/if_llatbl.c
  stable/9/sys/netinet/if_ether.c
  stable/9/sys/netinet6/nd6.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/net/   (props changed)

Modified: stable/9/sys/net/if_llatbl.c
==============================================================================
--- stable/9/sys/net/if_llatbl.c        Thu Mar 28 20:37:07 2013        
(r248851)
+++ stable/9/sys/net/if_llatbl.c        Thu Mar 28 20:48:40 2013        
(r248852)
@@ -112,12 +112,6 @@ llentry_free(struct llentry *lle)
        IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp);
        LLE_WLOCK_ASSERT(lle);
 
-       /* XXX: guard against race with other llentry_free(). */
-       if (!(lle->la_flags & LLE_LINKED)) {
-               LLE_FREE_LOCKED(lle);
-               return (0);
-       }
-
        LIST_REMOVE(lle, lle_next);
        lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
 

Modified: stable/9/sys/netinet/if_ether.c
==============================================================================
--- stable/9/sys/netinet/if_ether.c     Thu Mar 28 20:37:07 2013        
(r248851)
+++ stable/9/sys/netinet/if_ether.c     Thu Mar 28 20:48:40 2013        
(r248852)
@@ -169,7 +169,6 @@ arptimer(void *arg)
 {
        struct llentry *lle = (struct llentry *)arg;
        struct ifnet *ifp;
-       size_t pkts_dropped;
 
        if (lle->la_flags & LLE_STATIC) {
                LLE_WUNLOCK(lle);
@@ -186,11 +185,20 @@ arptimer(void *arg)
        IF_AFDATA_LOCK(ifp);
        LLE_WLOCK(lle);
 
-       LLE_REMREF(lle);
-       pkts_dropped = llentry_free(lle);
+       /* Guard against race with other llentry_free(). */
+       if (lle->la_flags & LLE_LINKED) {
+               size_t pkts_dropped;
+
+               LLE_REMREF(lle);
+               pkts_dropped = llentry_free(lle);
+               ARPSTAT_ADD(dropped, pkts_dropped);
+       } else
+               LLE_FREE_LOCKED(lle);
+
        IF_AFDATA_UNLOCK(ifp);
-       ARPSTAT_ADD(dropped, pkts_dropped);
+
        ARPSTAT_INC(timeouts);
+
        CURVNET_RESTORE();
 }
 

Modified: stable/9/sys/netinet6/nd6.c
==============================================================================
--- stable/9/sys/netinet6/nd6.c Thu Mar 28 20:37:07 2013        (r248851)
+++ stable/9/sys/netinet6/nd6.c Thu Mar 28 20:48:40 2013        (r248852)
@@ -1111,8 +1111,14 @@ nd6_free(struct llentry *ln, int gc)
        LLE_WUNLOCK(ln);
        IF_AFDATA_LOCK(ifp);
        LLE_WLOCK(ln);
-       LLE_REMREF(ln);
-       llentry_free(ln);
+
+       /* Guard against race with other llentry_free(). */
+       if (ln->la_flags & LLE_LINKED) {
+               LLE_REMREF(ln);
+               llentry_free(ln);
+       } else
+               LLE_FREE_LOCKED(ln);
+
        IF_AFDATA_UNLOCK(ifp);
 
        return (next);
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to