On Fri, Jul 08, 2022 at 05:35:38PM +0900, YASUOKA Masahiko wrote:
> Hello,
> 
> On Fri, 8 Jul 2022 00:53:16 +0300
> Vitaliy Makkoveev <m...@openbsd.org> wrote:
> > The `pipex_list_mtx' mutex(9) protects global pipex(4) lists so it need
> > to be taken while we perform this foreach loop.
> > 
> > The all sessions loop was reworked to make possible to drop the lock
> > within. This is required because pipex_ppp_output() takes scheduler lock
> > when performs ip_send().
> >
> > Index: sys/net/pipex.c
> > ===================================================================
> > RCS file: /cvs/src/sys/net/pipex.c,v
> > retrieving revision 1.143
> > diff -u -p -r1.143 pipex.c
> > --- sys/net/pipex.c 2 Jul 2022 08:50:42 -0000       1.143
> > +++ sys/net/pipex.c 7 Jul 2022 21:52:16 -0000
> > @@ -842,20 +842,39 @@ pipex_ip_output(struct mbuf *m0, struct 
> >  
> >             m0->m_flags &= ~(M_BCAST|M_MCAST);
> >  
> > -           LIST_FOREACH(session_tmp, &pipex_session_list, session_list) {
> > +           mtx_enter(&pipex_list_mtx);
> > +
> > +           session_tmp = LIST_FIRST(&pipex_session_list);
> > +           while (session_tmp != NULL) {
> > +                   struct pipex_session *session_save = NULL;
> > +
> >                     if (session_tmp->ownersc != session->ownersc)
> > -                           continue;
> > +                           goto next;
> >                     if ((session->flags & (PIPEX_SFLAGS_IP_FORWARD |
> >                         PIPEX_SFLAGS_IP6_FORWARD)) == 0)
> > -                           continue;
> > +                           goto next;
> >                     m = m_copym(m0, 0, M_COPYALL, M_NOWAIT);
> >                     if (m == NULL) {
> >                             counters_inc(session->stat_counters,
> >                                 pxc_oerrors);
> > -                           continue;
> > +                           goto next;
> >                     }
> > +
> > +                   refcnt_take(&session->pxs_refcnt);
> 
> this "session" should be session_tmp?
> 

Yes, we should check `flags' on `session_tmp'. I intentionally leaved it
as is since I introduced `flags' to replace bit fields. It was not
related to the diffs. I see no reason to fix it because we already
removed PIPEXCSESSION from npppd(8) and we are going to remove it from
kernel.

Also, this logic is useless since we started to unlink session from the
stack before kill it.

> Also, isn't it needed to take reference count on top of the block?
>

We don't need to do this because we keep `pipex_session_list' mutex(9)
held. I take the reference just before release the mutex(9) and make
this session accessible to concurrent delete threads. We need to unlink
session from the `pipex_session_list' before delete it, so we can't take
reference on session with null reference counter.

It makes sense to unlock list just before m_copym(9) call and do mbuf(9)
copy with `pipex_list_mtx' mutex(9) unlocked. With the `flags' check
removal the error path will have only foreign sessions: 

                session_tmp = LIST_FIRST(&pipex_session_list);
                while (session_tmp != NULL) {
                        struct pipex_session *session_save = NULL;

                        if (session_tmp->ownersc != session->ownersc)
                                goto next;

                        refcnt_take(&session_tmp->pxs_refcnt);
                        mtx_leave(&pipex_list_mtx);

                        m = m_copym(m0, 0, M_COPYALL, M_NOWAIT)
                        if (m != NULL)
                                pipex_ppp_output(m, session_tmp, PPP_IP);
                        else
                                counters_inc(session->stat_counters,
                                    pxc_oerrors);

                        mtx_enter(&pipex_list_mtx);
                        session_save = session_tmp;
next:
                        session_tmp = LIST_NEXT(session_tmp, session_list);
                        if (session_save != NULL)
                                pipex_rele_session(session_save);
                }

The update diff below. I also found we need to increment 'pxc_oerrors'
counter on `session_tmp' instead of session.

Index: sys/net/pipex.c
===================================================================
RCS file: /cvs/src/sys/net/pipex.c,v
retrieving revision 1.143
diff -u -p -r1.143 pipex.c
--- sys/net/pipex.c     2 Jul 2022 08:50:42 -0000       1.143
+++ sys/net/pipex.c     8 Jul 2022 14:41:37 -0000
@@ -842,20 +842,38 @@ pipex_ip_output(struct mbuf *m0, struct 
 
                m0->m_flags &= ~(M_BCAST|M_MCAST);
 
-               LIST_FOREACH(session_tmp, &pipex_session_list, session_list) {
+               mtx_enter(&pipex_list_mtx);
+
+               session_tmp = LIST_FIRST(&pipex_session_list);
+               while (session_tmp != NULL) {
+                       struct pipex_session *session_save = NULL;
+
                        if (session_tmp->ownersc != session->ownersc)
-                               continue;
+                               goto next;
                        if ((session->flags & (PIPEX_SFLAGS_IP_FORWARD |
                            PIPEX_SFLAGS_IP6_FORWARD)) == 0)
-                               continue;
-                       m = m_copym(m0, 0, M_COPYALL, M_NOWAIT);
-                       if (m == NULL) {
-                               counters_inc(session->stat_counters,
+                               goto next;
+
+                       refcnt_take(&session_tmp->pxs_refcnt);
+                       mtx_leave(&pipex_list_mtx);
+
+                       m = m_copym(m0, 0, M_COPYALL, M_NOWAIT)
+                       if (m != NULL)
+                               pipex_ppp_output(m, session_tmp, PPP_IP);
+                       else
+                               counters_inc(session_tmp->stat_counters,
                                    pxc_oerrors);
-                               continue;
-                       }
-                       pipex_ppp_output(m, session_tmp, PPP_IP);
+
+                       mtx_enter(&pipex_list_mtx);
+                       session_save = session_tmp;
+next:
+                       session_tmp = LIST_NEXT(session_tmp, session_list);
+                       if (session_save != NULL)
+                               pipex_rele_session(session_save);
                }
+
+               mtx_leave(&pipex_list_mtx);
+
                m_freem(m0);
        }
 

Reply via email to