> On 16 May 2023, at 18:35, Alexander Bluhm <alexander.bl...@gmx.net> wrote:
> 
> I saw one issue in sysctl_niq().  Another CPU could write mq_maxlen
> and our logic is inconsistent.  Below is a fix with read once.  Each
> CPU detects its own change, last write wins.  Or should we protect
> everything with mq_mtx?  Then sysctl 123 -> 345 would have the
> correct old value on both CPUs.

I don’t assume this case as issue, since if we have two concurrent
sysctl calls modifying the same mib we can’t predict which value will
be set last. To me, the "maxlen != mq->mq_maxlen” check could be
avoided and the "!error” or "error == 0” check is pretty enough:

        error = sysctl_int(oldp, oldlenp, newp, newlen, &maxlen);
        if (!error)
                mq_set_maxlen(mq, maxlen);

If you want to keep the check, I prefer to protect everything with
mq_mtx, and push the check within mq_set_maxlen(). At least this is
clean and strictly predictable comparing with
oldmax = newmax = READ_ONCE().

> 
> bluhm
> 
> Index: kern/uipc_mbuf.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_mbuf.c,v
> retrieving revision 1.285
> diff -u -p -r1.285 uipc_mbuf.c
> --- kern/uipc_mbuf.c  5 May 2023 01:19:51 -0000       1.285
> +++ kern/uipc_mbuf.c  16 May 2023 15:05:52 -0000
> @@ -1788,7 +1788,7 @@ int
> sysctl_mq(int *name, u_int namelen, void *oldp, size_t *oldlenp,
>     void *newp, size_t newlen, struct mbuf_queue *mq)
> {
> -     unsigned int maxlen;
> +     unsigned int oldmax, newmax;
>       int error;
> 
>       /* All sysctl names at this level are terminal. */
> @@ -1799,10 +1799,10 @@ sysctl_mq(int *name, u_int namelen, void
>       case IFQCTL_LEN:
>               return (sysctl_rdint(oldp, oldlenp, newp, mq_len(mq)));
>       case IFQCTL_MAXLEN:
> -             maxlen = mq->mq_maxlen;
> -             error = sysctl_int(oldp, oldlenp, newp, newlen, &maxlen);
> -             if (!error && maxlen != mq->mq_maxlen)
> -                     mq_set_maxlen(mq, maxlen);
> +             oldmax = newmax = READ_ONCE(mq->mq_maxlen);
> +             error = sysctl_int(oldp, oldlenp, newp, newlen, &newmax);
> +             if (!error && oldmax != newmax)
> +                     mq_set_maxlen(mq, newmax);
>               return (error);
>       case IFQCTL_DROPS:
>               return (sysctl_rdint(oldp, oldlenp, newp, mq_drops(mq)));

Reply via email to