On Sat, May 27, 2017 at 20:06 +0200, Sebastien Marie wrote:
> On Sat, May 27, 2017 at 07:28:26AM +0200, Sebastien Marie wrote:
> > Hi,
> > 
> > I am experiencing often the following panic: 
> > 
> > panic: kernel diagnostic assertion "ifq_is_serialized(ifq)" failed: 
> > ../sys/net/ifq.c, line 394
> > 
> > while running with GENERIC.MP patched with mikeb@ diff:
> > 
> >  if_start(struct ifnet *ifp)
> >  {
> >         KASSERT(ifp->if_qstart == if_qstart_compat);
> > -       if_qstart_compat(&ifp->if_snd);
> > +       ifq_start(&ifp->if_snd);
> >  }
> > 
> 
> mikeb@, I don't reproduce if I backout the local diff.
> 
> it seems bce(4) doesn't like it.

Indeed, a lot of things won't like this since xxx_start may be called
directly by the driver.  To handle this situation we need to make sure
that IFQ_DEQUEUE that is called by these xxx_start routines provides a
compatible interface.  Please try the diff below.  If this solves your
issue, I'd like to get it in w/o assertions unless there are objections.


---
 sys/net/if.c     |  3 ++-
 sys/net/if_var.h |  2 +-
 sys/net/ifq.c    | 26 ++++++++++++++++++++++++++
 sys/net/ifq.h    |  1 +
 4 files changed, 30 insertions(+), 2 deletions(-)

diff --git sys/net/if.c sys/net/if.c
index 34fd1aa84d7..acea3ae53ea 100644
--- sys/net/if.c
+++ sys/net/if.c
@@ -623,12 +623,13 @@ if_attach_ifq(struct ifnet *ifp, const struct ifq_ops 
*newops, void *args)
 
 void
 if_start(struct ifnet *ifp)
 {
        KASSERT(ifp->if_qstart == if_qstart_compat);
-       if_qstart_compat(&ifp->if_snd);
+       ifq_start(&ifp->if_snd);
 }
+
 void
 if_qstart_compat(struct ifqueue *ifq)
 {
        struct ifnet *ifp = ifq->ifq_if;
        int s;
diff --git sys/net/if_var.h sys/net/if_var.h
index 14e118bcbef..9df7c8f4d80 100644
--- sys/net/if_var.h
+++ sys/net/if_var.h
@@ -255,11 +255,11 @@ do {                                                      
                \
        (err) = ifq_enqueue((ifq), (m));                                \
 } while (/* CONSTCOND */0)
 
 #define        IFQ_DEQUEUE(ifq, m)                                             
\
 do {                                                                   \
-       (m) = ifq_dequeue(ifq);                                         \
+       (m) = ifq_dequeue_compat(ifq);                                  \
 } while (/* CONSTCOND */0)
 
 #define        IFQ_PURGE(ifq)                                                  
\
 do {                                                                   \
        (void)ifq_purge(ifq);                                           \
diff --git sys/net/ifq.c sys/net/ifq.c
index d37be87f444..0a49567f81d 100644
--- sys/net/ifq.c
+++ sys/net/ifq.c
@@ -337,10 +337,36 @@ ifq_dequeue(struct ifqueue *ifq)
        ifq_deq_commit(ifq, m);
 
        return (m);
 }
 
+struct mbuf *
+ifq_dequeue_compat(struct ifqueue *ifq)
+{
+       struct mbuf *m;
+       void *serializer;
+
+       KERNEL_ASSERT_LOCKED();
+       KASSERT(ifq->ifq_serializer == NULL ||
+           ifq->ifq_serializer == curcpu());
+
+       serializer = ifq->ifq_serializer;
+       ifq->ifq_serializer = curcpu();
+
+       m = ifq_deq_begin(ifq);
+       if (m == NULL)
+               return (NULL);
+
+       ifq_deq_commit(ifq, m);
+
+       ml_purge(&ifq->ifq_free);
+
+       ifq->ifq_serializer = serializer;
+
+       return (m);
+}
+
 unsigned int
 ifq_purge(struct ifqueue *ifq)
 {
        struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        unsigned int rv;
diff --git sys/net/ifq.h sys/net/ifq.h
index 29b89c38b23..3a7fde55ca2 100644
--- sys/net/ifq.h
+++ sys/net/ifq.h
@@ -380,10 +380,11 @@ void               ifq_destroy(struct ifqueue *);
 int             ifq_enqueue(struct ifqueue *, struct mbuf *);
 struct mbuf    *ifq_deq_begin(struct ifqueue *);
 void            ifq_deq_commit(struct ifqueue *, struct mbuf *);
 void            ifq_deq_rollback(struct ifqueue *, struct mbuf *);
 struct mbuf    *ifq_dequeue(struct ifqueue *);
+struct mbuf    *ifq_dequeue_compat(struct ifqueue *);
 void            ifq_mfreem(struct ifqueue *, struct mbuf *);
 void            ifq_mfreeml(struct ifqueue *, struct mbuf_list *);
 unsigned int    ifq_purge(struct ifqueue *);
 void           *ifq_q_enter(struct ifqueue *, const struct ifq_ops *);
 void            ifq_q_leave(struct ifqueue *, void *);
-- 
2.13.0

Reply via email to