On Fri, Dec 08, 2023 at 11:36:31PM +0100, Alexander Bluhm wrote:
> On Thu, Dec 07, 2023 at 06:14:30PM +0300, Vitaliy Makkoveev wrote:
> > Here id the diff. I introduces `sc_mtx' mutex(9) to protect the most of 
> > pflow_softc structure. The `send_nam', `sc_flowsrc' and `sc_flowdst' are
> > prtected by `sc_lock' rwlock(9). `sc_tmpl_ipfix' is immutable.
> > 
> > Also, the pflow_sendout_ipfix_tmpl() calls pflow_get_mbuf() with NULL
> > instead of `sc'. This fix also included to this diff.
> > 
> > Please note, this diff does not fix all the problems in the pflow(4).
> > The ifconfig create/destroy sequence could still break the kernel. I
> > have ok'ed diff to fix this but did not commit it yet for some reason.
> > Also the `pflowstats' data left unprotected. I will fix this with
> > separate diff.
> > 
> > Please test this diff and let us know the result. I will continue with
> > pflow(4) after committing this.
> 
> Your changes make sense.
> 
> >                     sc->sc_gcounter=pflowstats.pflow_flows;
> 
> Could you add some spaces around =
> sc_gcounter is set without spaced twice.
> 

Thanks, I will fix this.

> >     case SIOCGETPFLOW:
> >             bzero(&pflowr, sizeof(pflowr));
> >  
> > +           /* XXXSMP: enforce lock order */
> > +           NET_UNLOCK();
> > +           rw_enter_read(&sc->sc_lock);
> > +           NET_LOCK();
> 
> This looks ugly.  I did not find the sc_lock -> NET_LOCK() seqence.
> Where is it?  Why do we need it?  In general I think the global
> NET_LOCK() should be taken before the specific sc_lock.  Moving the
> net lock to very narrow places within other locks makes things more
> complicated.  Better take a shared net lock and hold it for more
> code.  Not sure if this is a usable solution in this case.
> 

The `sc_lock' rwlock(9) protects the `so' socket dereference. Since it
is passed to sosend() which takes netlock within, the `sc_lock' should
be taken first:

void
pflow_output_process(void *arg)
{
        struct mbuf_list ml;
        struct pflow_softc *sc = arg;
        struct mbuf *m;

        mq_delist(&sc->sc_outputqueue, &ml);
        rw_enter_read(&sc->sc_lock);
        while ((m = ml_dequeue(&ml)) != NULL) {
                pflow_sendout_mbuf(sc, m);
        }
        rw_exit_read(&sc->sc_lock);
}

int
pflow_sendout_mbuf(struct pflow_softc *sc, struct mbuf *m)
{
        counters_pkt(sc->sc_if.if_counters,
                    ifc_opackets, ifc_obytes, m->m_pkthdr.len);

        if (sc->so == NULL) {
                m_freem(m);
                return (EINVAL);
        }
        return (sosend(sc->so, sc->send_nam, NULL, m, NULL, 0));
}

I want to rework netlock relocking in pflowioctl(). Guess it should be
realeased and the `sc_lock' should be taken just after we enter
pflowioctl(). We need to release netlock because pflowioctl() calls
solcose(), socreate() and sobind(). Since the `sc_lock' will not be
relocked, the `sc_dying' should rely on it. This will fix the
pflowioctl() concurrency with pflow_clone_destroy().

> > pflow(4) after committing this.

> >     SLIST_ENTRY(pflow_softc) sc_next;
> 
> This list is protected by net lock.  Can you add an [N] here?
> 

This is not true. The netlock is not taken while export_pflow() called
from pf_purge_states(). I privately shared the diff to fix this, but not
committed it yet. I will update it and share after committing this diff.

> OK bluhm@
> 
> Feel free to address my remarks later.
> 

Reply via email to