> On 6 Jul 2020, at 17:36, Martin Pieuchot <[email protected]> wrote:
> 
> On 06/07/20(Mon) 16:42, Vitaliy Makkoveev wrote:
>> [...] 
>> pipex(4) is simultaneously locked by NET_LOCK() and KERNEL_LOCK() but
>> with two exceptions:
>> 
>> 1. As you pointed pipex_pppoe_input() called without KERNEL_LOCK() held.
>> 2. pppac_start() called without NET_LOCK() held. Or with NET_LOCK()
>>   held. It depends on `if_snd' usage.
>> 
>> Diff below enforces pppac_start() to be called with NET_LOCK() held.
>> Also all externally called pipex(4) input and output routines have
>> NET_ASSERT_LOCKED() assertion.
>> 
>> Now pipex(4) is fully protected by NET_LOCK() so description of struct
>> members chenget too.
>> 
>> Index: sys/net/if_pppx.c
>> ===================================================================
>> RCS file: /cvs/src/sys/net/if_pppx.c,v
>> retrieving revision 1.90
>> diff -u -p -r1.90 if_pppx.c
>> --- sys/net/if_pppx.c        24 Jun 2020 08:52:53 -0000      1.90
>> +++ sys/net/if_pppx.c        6 Jul 2020 11:10:17 -0000
>> @@ -1117,6 +1117,8 @@ pppacopen(dev_t dev, int flags, int mode
>>      ifp->if_output = pppac_output;
>>      ifp->if_start = pppac_start;
>>      ifp->if_ioctl = pppac_ioctl;
>> +    /* XXXSMP: be sure pppac_start() called under NET_LOCK() */
>> +    IFQ_SET_MAXLEN(&ifp->if_snd, 1);
> 
> Is it possible to grab the NET_LOCK() inside pppac_start() instead of
> grabbing it outside?  This should allow *start() routine to be called
> from any context.

Unfortunately you can’t be sure about NET_LOCK() status while you are
in pppac_start(). It was described at this thread [1].

We have two cases:
1. pppac_start() called from pppac_output(). NET_LOCK() was inherited.
2. pppac_start() called from `systq’. There is no NET_LOCK() held.

NET_LOCK() is not required for pipex_{,ppp}_output() because underlay
routines were switched to ip{,6}_send().

I intentionally want to made all pipex(4) locked by one lock and be
sure it’s locking is consistent. I hope to start implementing fine
graining locks just after pipex(4) be switched to if_get(9).

> 
> It might be interesting to see that as a difference between the NET_LOCK()
> used to protect the network stack internals and the NET_LOCK() used to
> protect pipex(4) internals.  Such distinction might help to convert the
> latter into a different lock or primitive.
> 
>> Index: sys/net/pipex.c
>> ===================================================================
>> RCS file: /cvs/src/sys/net/pipex.c,v
>> retrieving revision 1.117
>> diff -u -p -r1.117 pipex.c
>> --- sys/net/pipex.c  30 Jun 2020 14:05:13 -0000      1.117
>> +++ sys/net/pipex.c  6 Jul 2020 11:10:17 -0000
>> @@ -869,6 +869,7 @@ pipex_output(struct mbuf *m0, int af, in
>>      struct ip ip;
>>      struct mbuf *mret;
>> 
>> +    NET_ASSERT_LOCKED();
> 
> This function doesn't touch any shared data structure, we'd better move
> the NET_ASSERT_LOCKED() above rn_lookuo() in pipex_lookup_by_ip_address().
> 
> Note that `pipex_rd_head4' and `pipex_rd_head6' are, with this diff,
> also protected by the NET_LOCK() and should be annotated as such.
> 
>>      session = NULL;
>>      mret = NULL;
>>      switch (af) {
>> @@ -962,6 +963,8 @@ pipex_ppp_output(struct mbuf *m0, struct
>> {
>>      u_char *cp, hdr[16];
>> 
>> +    NET_ASSERT_LOCKED();
> 
> Same here, it seems that the only reason the NET_LOCK() is necessary in
> the output path is to prevent corruption of the `session' descriptor being
> used.  So we'd rather put the assertion above the LIST_FOREACH(). 

They touch `session->stat’ :) We can switch pipex(4) to percpu counters and
output will be lockless. But I guess this should be done later.

> 
> Anyway all of those can be addressed later, your diff is ok mpi@
> 

Thanks. I will commit it if no one has objections.

1. https://marc.info/?t=158998611500002&r=1&w=2

Reply via email to