Index | Thread | Search

From:
Vitaliy Makkoveev <mvs@openbsd.org>
Subject:
Re: Prepare bpf_sysctl() for net_sysctl() unlocking
To:
tech@openbsd.org
Date:
Sun, 11 Aug 2024 19:23:13 +0300

Download raw body.

Thread
Anyone? Protocol sysctl(2) locking is discussible, but statistics
is per-CUP counters and could be received lockless, so partial
net_sysctl() unlocking makes sense.

> On 6 Aug 2024, at 18:40, Vitaliy Makkoveev <mvs@openbsd.org> wrote:
> 
> On Tue, Aug 06, 2024 at 03:30:01PM +0300, Vitaliy Makkoveev wrote:
>> bluhm@ reworked sysctl_int_bounded() to deal with atomically accessed
>> integer variables. bpf(4) sysctl has two such variables, NET_BPF_BUFSIZE
>> and NET_BPF_MAXBUFSIZE respectively, so rework bpf_sysctl() to be ready
>> for upcoming net_sysctl() unlocking.
>> 
>> Please note, bpf_movein() obviously require to store `bpf_maxbufsize'
>> to local variable, but bpf_sysctl() accesses it only once, so
>> atomic_load_int() is unnecessary here. This is also true for
>> `bpf_bufsize' which is accessed only once in bpfopen().
>> 
>> ok?
>> 
> 
> Use atomic_load_int(9) instead direct access.
> 
> Index: sys/net/bpf.c
> ===================================================================
> RCS file: /cvs/src/sys/net/bpf.c,v
> diff -u -p -r1.223 bpf.c
> --- sys/net/bpf.c	5 Aug 2024 23:56:10 -0000	1.223
> +++ sys/net/bpf.c	6 Aug 2024 15:39:52 -0000
> @@ -84,10 +84,15 @@
> #define PRINET  26			/* interruptible */
> 
> /*
> + * Locks used to protect data:
> + *	a	atomic
> + */
> +
> +/*
>  * The default read buffer size is patchable.
>  */
> -int bpf_bufsize = BPF_BUFSIZE;
> -int bpf_maxbufsize = BPF_MAXBUFSIZE;
> +int bpf_bufsize = BPF_BUFSIZE;		/* [a] */
> +int bpf_maxbufsize = BPF_MAXBUFSIZE;	/* [a] */
> 
> /*
>  *  bpf_iflist is the list of interfaces; each corresponds to an ifnet
> @@ -117,8 +122,6 @@ int	filt_bpfread(struct knote *, long);
> int	filt_bpfreadmodify(struct kevent *, struct knote *);
> int	filt_bpfreadprocess(struct knote *, struct kevent *);
> 
> -int	bpf_sysctl_locked(int *, u_int, void *, size_t *, void *, size_t);
> -
> struct bpf_d *bpfilter_lookup(int);
> 
> /*
> @@ -137,9 +140,6 @@ void	bpf_d_smr(void *);
> void	bpf_get(struct bpf_d *);
> void	bpf_put(struct bpf_d *);
> 
> -
> -struct rwlock bpf_sysctl_lk = RWLOCK_INITIALIZER("bpfsz");
> -
> int
> bpf_movein(struct uio *uio, struct bpf_d *d, struct mbuf **mp,
>     struct sockaddr *sockp)
> @@ -393,7 +393,7 @@ bpfopen(dev_t dev, int flag, int mode, s
> 
> 	/* Mark "free" and do most initialization. */
> 	bd->bd_unit = unit;
> -	bd->bd_bufsize = bpf_bufsize;
> +	bd->bd_bufsize = atomic_load_int(&bpf_bufsize);
> 	bd->bd_sig = SIGIO;
> 	mtx_init(&bd->bd_mtx, IPL_NET);
> 	task_set(&bd->bd_wake_task, bpf_wakeup_cb, bd);
> @@ -853,9 +853,11 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t 
> 			error = EINVAL;
> 		else {
> 			u_int size = *(u_int *)addr;
> +			int bpf_maxbufsize_local =
> +			    atomic_load_int(&bpf_maxbufsize);
> 
> -			if (size > bpf_maxbufsize)
> -				*(u_int *)addr = size = bpf_maxbufsize;
> +			if (size > bpf_maxbufsize_local)
> +				*(u_int *)addr = size = bpf_maxbufsize_local;
> 			else if (size < BPF_MINBUFSIZE)
> 				*(u_int *)addr = size = BPF_MINBUFSIZE;
> 			mtx_enter(&d->bd_mtx);
> @@ -1815,42 +1817,25 @@ bpfsdetach(void *p)
> }
> 
> int
> -bpf_sysctl_locked(int *name, u_int namelen, void *oldp, size_t *oldlenp,
> -    void *newp, size_t newlen)
> +bpf_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
> +    size_t newlen)
> {
> +	if (namelen != 1)
> +		return (ENOTDIR);
> +
> 	switch (name[0]) {
> 	case NET_BPF_BUFSIZE:
> 		return sysctl_int_bounded(oldp, oldlenp, newp, newlen,
> -		    &bpf_bufsize, BPF_MINBUFSIZE, bpf_maxbufsize);
> +		    &bpf_bufsize, BPF_MINBUFSIZE,
> +		    atomic_load_int(&bpf_maxbufsize));
> 	case NET_BPF_MAXBUFSIZE:
> 		return sysctl_int_bounded(oldp, oldlenp, newp, newlen,
> 		    &bpf_maxbufsize, BPF_MINBUFSIZE, INT_MAX);
> 	default:
> 		return (EOPNOTSUPP);
> 	}
> -}
> -
> -int
> -bpf_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
> -    size_t newlen)
> -{
> -	int flags = RW_INTR;
> -	int error;
> 
> -	if (namelen != 1)
> -		return (ENOTDIR);
> -
> -	flags |= (newp == NULL) ? RW_READ : RW_WRITE;
> -
> -	error = rw_enter(&bpf_sysctl_lk, flags);
> -	if (error != 0)
> -		return (error);
> -
> -	error = bpf_sysctl_locked(name, namelen, oldp, oldlenp, newp, newlen);
> -
> -	rw_exit(&bpf_sysctl_lk);
> -
> -	return (error);
> +	/* NOTREACHED */
> }
> 
> struct bpf_d *