On Wed, May 31, 2017 at 10:50 +0200, Alexandr Nedvedicky wrote:
> Hello Mike,
> 
> I'd like to ask you to take a one more look to change I'm going
> to commit.

Looks much better w/o SPLs.  I did't find any issues with
the diff and I'm OK with you going forward with this.

> I did one more check of changes with respect to WITH_PF_LOCK
> and found one more bit to fix. We need to keep
> pf_purge_expired_fragments() under protection of NET_LOCK()
>

Fair enough.

> diff -r 6abbb123112a .hgtags
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/.hgtags Wed May 31 10:42:50 2017 +0200
> @@ -0,0 +1,1 @@
> +d545881e2652dbc0c057691a39a095bce92f441f pf-lock.baseline

Please be careful and don't include VCS's goo in diffs.
It'd be nice if you could manage to instruct mercurial
to remove a/ and b/ parts.

> @@ -1208,15 +1208,22 @@ pf_purge_thread(void *v)
>  
>               NET_LOCK(s);
>  
> +             PF_LOCK();
>               /* process a fraction of the state table every second */
>               pf_purge_expired_states(1 + (pf_status.states
>                   / pf_default_rule.timeout[PFTM_INTERVAL]));
>  
>               /* purge other expired types every PFTM_INTERVAL seconds */
>               if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) {
> -                     pf_purge_expired_fragments();
>                       pf_purge_expired_src_nodes(0);
>                       pf_purge_expired_rules();
> +             }
> +             PF_UNLOCK();
> +             /*
> +              * Fragments don't require PF_LOCK(), they use their own mutex.
> +              */
> +             if (nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) {
> +                     pf_purge_expired_fragments();
>                       nloops = 0;
>               }
>  

Minor nit: change comment above to say "they use their own lock."
to remove the reference to a specific lock implementation.

> @@ -1320,7 +1327,6 @@ pf_remove_state(struct pf_state *cur)
>       }
>       RB_REMOVE(pf_state_tree_id, &tree_id, cur);
>  #if NPFLOW > 0
> -     if (cur->state_flags & PFSTATE_PFLOW)
>               export_pflow(cur);

If you're removing this "if" statemenet, please remove the tab
from the next line.

> @@ -6692,6 +6699,9 @@ pf_test(sa_family_t af, int fwdir, struc
>       }
>       pd.m->m_pkthdr.pf.flags |= PF_TAG_PROCESSED;
>  
> +     /* lock the look-up/write section of pf_test() */
> +     PF_LOCK();
> +
>       switch (pd.virtual_proto) {
>  
>       case PF_VPROTO_FRAGMENT: {

Minor nit: spell "lookup" without a dash.

> @@ -6711,7 +6721,7 @@ pf_test(sa_family_t af, int fwdir, struc
>                       REASON_SET(&reason, PFRES_NORM);
>                       DPFPRINTF(LOG_NOTICE,
>                           "dropping IPv6 packet with ICMPv4 payload");
> -                     goto done;
> +                     goto unlock;
>               }
>               action = pf_test_state_icmp(&pd, &s, &reason);
>               if (action == PF_PASS || action == PF_AFRT) {
> @@ -6736,7 +6746,7 @@ pf_test(sa_family_t af, int fwdir, struc
>                       REASON_SET(&reason, PFRES_NORM);
>                       DPFPRINTF(LOG_NOTICE,
>                           "dropping IPv4 packet with ICMPv6 payload");
> -                     goto done;
> +                     goto unlock;
>               }
>               action = pf_test_state_icmp(&pd, &s, &reason);
>               if (action == PF_PASS || action == PF_AFRT) {
> @@ -6761,7 +6771,7 @@ pf_test(sa_family_t af, int fwdir, struc
>                               pqid = 1;
>                       action = pf_normalize_tcp(&pd);
>                       if (action == PF_DROP)
> -                             goto done;
> +                             goto unlock;
>               }
>               action = pf_test_state(&pd, &s, &reason);
>               if (action == PF_PASS || action == PF_AFRT) {
> @@ -6788,6 +6798,15 @@ pf_test(sa_family_t af, int fwdir, struc
>               break;
>       }
>  
> +unlock:
> +     PF_UNLOCK();
> +
> +     /*
> +      * At the moment, we rely on NET_LOCK() to prevent removal of items
> +      * we've collected above ('s', 'r', 'anchor' and 'ruleset').  They'll
> +      * have to be refcounted when NET_LOCK() is gone.
> +      */
> +
>  done:
>       if (action != PF_DROP) {
>               if (s) {
> @@ -6991,6 +7010,7 @@ done:
>       }
>  
>       *m0 = pd.m;
> +
>       return (action);
>  }
>  
> diff -r 6abbb123112a src/sys/net/pf_ioctl.c
> --- a/src/sys/net/pf_ioctl.c  Wed May 31 10:21:18 2017 +0200
> +++ b/src/sys/net/pf_ioctl.c  Wed May 31 10:42:50 2017 +0200
> @@ -129,6 +129,10 @@ struct {
>  TAILQ_HEAD(pf_tags, pf_tagname)      pf_tags = 
> TAILQ_HEAD_INITIALIZER(pf_tags),
>                               pf_qids = TAILQ_HEAD_INITIALIZER(pf_qids);
>  
> +#ifdef WITH_PF_LOCK
> +struct rwlock                 pf_lock = RWLOCK_INITIALIZER("pf_lock");
> +#endif /* WITH_PF_LOCK */
> +
>  #if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE)
>  #error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE
>  #endif

Where do you want to define this WITH_PF_LOCK?

> diff -r 6abbb123112a src/sys/net/pfvar_priv.h
> --- a/src/sys/net/pfvar_priv.h        Wed May 31 10:21:18 2017 +0200
> +++ b/src/sys/net/pfvar_priv.h        Wed May 31 10:42:50 2017 +0200
> @@ -94,6 +98,36 @@ struct pf_pdesc {
>       } hdr;
>  };
>  
> +#ifdef WITH_PF_LOCK
> +extern struct rwlock pf_lock;
> +
> +#define PF_LOCK()            do {            \
> +             NET_ASSERT_LOCKED();            \
> +             rw_enter_write(&pf_lock);       \
> +     } while (0)
> +
> +#define PF_UNLOCK()          do {            \
> +             PF_ASSERT_LOCKED();             \
> +             rw_exit_write(&pf_lock);        \
> +     } while (0)
> +
> +#define PF_ASSERT_LOCKED()   do {                    \
> +             if (rw_status(&pf_lock) != RW_WRITE)    \
> +                     splassert_fail(RW_WRITE,        \
> +                         rw_status(&pf_lock),__func__);\
> +     } while (0)
> +
> +#define PF_ASSERT_UNLOCKED() do {                    \
> +             if (rw_status(&pf_lock) == RW_WRITE)    \
> +                     splassert_fail(0, rw_status(&pf_lock), __func__);\
> +     } while (0)
> +#else /* !WITH_PF_LOCK */
> +#define PF_LOCK()            (void)(0)
> +#define PF_UNLOCK()          (void)(0)
> +#define PF_ASSERT_LOCKED()   (void)(0)
> +#define PF_ASSERT_UNLOCKED() (void)(0)
> +#endif /* WITH_PF_LOCK */
> +
>  #endif /* _KERNEL */
>  
>  #endif /* _NET_PFVAR_PRIV_H_ */

I suggest to make this look a tiny bit prettier:

#define PF_LOCK()               do {                    \
                NET_ASSERT_LOCKED();                    \
                rw_enter_write(&pf_lock);               \
        } while (0)

#define PF_UNLOCK()             do {                    \
                PF_ASSERT_LOCKED();                     \
                rw_exit_write(&pf_lock);                \
        } while (0)

#define PF_ASSERT_LOCKED()      do {                    \
                if (rw_status(&pf_lock) != RW_WRITE)    \
                        splassert_fail(RW_WRITE,        \
                            rw_status(&pf_lock), __func__);\
        } while (0)

#define PF_ASSERT_UNLOCKED()    do {                    \
                if (rw_status(&pf_lock) == RW_WRITE)    \
                        splassert_fail(0,               \
                            rw_status(&pf_lock), __func__);\
        } while (0)

Reply via email to