On 20/05/21(Thu) 14:16, Visa Hankala wrote:
> On Thu, May 20, 2021 at 11:35:32AM +0200, Martin Pieuchot wrote:
> > On 18/05/21(Tue) 14:22, Visa Hankala wrote:
> > > This diff adds f_modify and f_process callbacks to socket event filters.
> > > As a result, socket events are handled using the non-legacy paths in
> > > filter_modify() and filter_process() of kern_event.c This a step toward
> > > MP-safety. However, everything still runs under the kernel lock.
> > >
> > > The change has three intended effects:
> > >
> > > * Socket events are handled without raising the system priority level.
> > > This makes the activity observable with btrace(8).
> > >
> > > * kqueue itself no longer calls f_event of socket filterops, which
> > > allows replacing the conditional, NOTE_SUBMIT-based locking with
> > > a fixed call pattern.
> >
> > I love this.
> >
> > > * The state of a socket event is now always rechecked before delivery
> > > to user. Before, the recheck was skipped if the event was registered
> > > with EV_ONESHOT.
> >
> > To me this sounds sane. I can't think of a way to rely on the current
> > behavior. However if there's an easy way to split these changes in two
> > commits, I'd prefer to stay on the safe side.
>
> Below is an updated diff that preserves the current EV_ONESHOT
> behaviour. I have just adapted a part of the compatibility logic
> from function filter_process().
>
> When f_process is given a non-NULL kev argument, it is known that
> the callback is invoked from kqueue_scan(). If kev is NULL,
> kqueue_register() is checking if the knote should be activated and
> there is no intent to deliver the event right now.
ok mpi@
> Index: kern/uipc_socket.c
> ===================================================================
> RCS file: src/sys/kern/uipc_socket.c,v
> retrieving revision 1.261
> diff -u -p -r1.261 uipc_socket.c
> --- kern/uipc_socket.c 13 May 2021 19:43:11 -0000 1.261
> +++ kern/uipc_socket.c 20 May 2021 14:01:18 -0000
> @@ -70,15 +70,26 @@ void sorflush(struct socket *);
>
> void filt_sordetach(struct knote *kn);
> int filt_soread(struct knote *kn, long hint);
> +int filt_soreadmodify(struct kevent *kev, struct knote *kn);
> +int filt_soreadprocess(struct knote *kn, struct kevent *kev);
> +int filt_soread_common(struct knote *kn, struct socket *so);
> void filt_sowdetach(struct knote *kn);
> int filt_sowrite(struct knote *kn, long hint);
> +int filt_sowritemodify(struct kevent *kev, struct knote *kn);
> +int filt_sowriteprocess(struct knote *kn, struct kevent *kev);
> +int filt_sowrite_common(struct knote *kn, struct socket *so);
> int filt_solisten(struct knote *kn, long hint);
> +int filt_solistenmodify(struct kevent *kev, struct knote *kn);
> +int filt_solistenprocess(struct knote *kn, struct kevent *kev);
> +int filt_solisten_common(struct knote *kn, struct socket *so);
>
> const struct filterops solisten_filtops = {
> .f_flags = FILTEROP_ISFD,
> .f_attach = NULL,
> .f_detach = filt_sordetach,
> .f_event = filt_solisten,
> + .f_modify = filt_solistenmodify,
> + .f_process = filt_solistenprocess,
> };
>
> const struct filterops soread_filtops = {
> @@ -86,6 +97,8 @@ const struct filterops soread_filtops =
> .f_attach = NULL,
> .f_detach = filt_sordetach,
> .f_event = filt_soread,
> + .f_modify = filt_soreadmodify,
> + .f_process = filt_soreadprocess,
> };
>
> const struct filterops sowrite_filtops = {
> @@ -93,6 +106,8 @@ const struct filterops sowrite_filtops =
> .f_attach = NULL,
> .f_detach = filt_sowdetach,
> .f_event = filt_sowrite,
> + .f_modify = filt_sowritemodify,
> + .f_process = filt_sowriteprocess,
> };
>
> const struct filterops soexcept_filtops = {
> @@ -100,6 +115,8 @@ const struct filterops soexcept_filtops
> .f_attach = NULL,
> .f_detach = filt_sordetach,
> .f_event = filt_soread,
> + .f_modify = filt_soreadmodify,
> + .f_process = filt_soreadprocess,
> };
>
> #ifndef SOMINCONN
> @@ -2056,13 +2073,12 @@ filt_sordetach(struct knote *kn)
> }
>
> int
> -filt_soread(struct knote *kn, long hint)
> +filt_soread_common(struct knote *kn, struct socket *so)
> {
> - struct socket *so = kn->kn_fp->f_data;
> - int s, rv = 0;
> + int rv = 0;
> +
> + soassertlocked(so);
>
> - if ((hint & NOTE_SUBMIT) == 0)
> - s = solock(so);
> kn->kn_data = so->so_rcv.sb_cc;
> #ifdef SOCKET_SPLICE
> if (isspliced(so)) {
> @@ -2090,12 +2106,50 @@ filt_soread(struct knote *kn, long hint)
> } else {
> rv = (kn->kn_data >= so->so_rcv.sb_lowat);
> }
> - if ((hint & NOTE_SUBMIT) == 0)
> - sounlock(so, s);
>
> return rv;
> }
>
> +int
> +filt_soread(struct knote *kn, long hint)
> +{
> + struct socket *so = kn->kn_fp->f_data;
> +
> + return (filt_soread_common(kn, so));
> +}
> +
> +int
> +filt_soreadmodify(struct kevent *kev, struct knote *kn)
> +{
> + struct socket *so = kn->kn_fp->f_data;
> + int rv, s;
> +
> + s = solock(so);
> + knote_modify(kev, kn);
> + rv = filt_soread_common(kn, so);
> + sounlock(so, s);
> +
> + return (rv);
> +}
> +
> +int
> +filt_soreadprocess(struct knote *kn, struct kevent *kev)
> +{
> + struct socket *so = kn->kn_fp->f_data;
> + int rv, s;
> +
> + s = solock(so);
> + if (kev != NULL && (kn->kn_flags & EV_ONESHOT))
> + rv = 1;
> + else
> + rv = filt_soread_common(kn, so);
> + if (rv != 0)
> + knote_submit(kn, kev);
> + sounlock(so, s);
> +
> + return (rv);
> +}
> +
> void
> filt_sowdetach(struct knote *kn)
> {
> @@ -2107,13 +2161,12 @@ filt_sowdetach(struct knote *kn)
> }
>
> int
> -filt_sowrite(struct knote *kn, long hint)
> +filt_sowrite_common(struct knote *kn, struct socket *so)
> {
> - struct socket *so = kn->kn_fp->f_data;
> - int s, rv;
> + int rv;
> +
> + soassertlocked(so);
>
> - if ((hint & NOTE_SUBMIT) == 0)
> - s = solock(so);
> kn->kn_data = sbspace(so, &so->so_snd);
> if (so->so_state & SS_CANTSENDMORE) {
> kn->kn_flags |= EV_EOF;
> @@ -2133,27 +2186,100 @@ filt_sowrite(struct knote *kn, long hint
> } else {
> rv = (kn->kn_data >= so->so_snd.sb_lowat);
> }
> - if ((hint & NOTE_SUBMIT) == 0)
> - sounlock(so, s);
>
> return (rv);
> }
>
> int
> -filt_solisten(struct knote *kn, long hint)
> +filt_sowrite(struct knote *kn, long hint)
> {
> struct socket *so = kn->kn_fp->f_data;
> - int s;
>
> - if ((hint & NOTE_SUBMIT) == 0)
> - s = solock(so);
> + return (filt_sowrite_common(kn, so));
> +}
> +
> +int
> +filt_sowritemodify(struct kevent *kev, struct knote *kn)
> +{
> + struct socket *so = kn->kn_fp->f_data;
> + int rv, s;
> +
> + s = solock(so);
> + knote_modify(kev, kn);
> + rv = filt_sowrite_common(kn, so);
> + sounlock(so, s);
> +
> + return (rv);
> +}
> +
> +int
> +filt_sowriteprocess(struct knote *kn, struct kevent *kev)
> +{
> + struct socket *so = kn->kn_fp->f_data;
> + int rv, s;
> +
> + s = solock(so);
> + if (kev != NULL && (kn->kn_flags & EV_ONESHOT))
> + rv = 1;
> + else
> + rv = filt_sowrite_common(kn, so);
> + if (rv != 0)
> + knote_submit(kn, kev);
> + sounlock(so, s);
> +
> + return (rv);
> +}
> +
> +int
> +filt_solisten_common(struct knote *kn, struct socket *so)
> +{
> + soassertlocked(so);
> +
> kn->kn_data = so->so_qlen;
> - if ((hint & NOTE_SUBMIT) == 0)
> - sounlock(so, s);
>
> return (kn->kn_data != 0);
> }
>
> +int
> +filt_solisten(struct knote *kn, long hint)
> +{
> + struct socket *so = kn->kn_fp->f_data;
> +
> + return (filt_solisten_common(kn, so));
> +}
> +
> +int
> +filt_solistenmodify(struct kevent *kev, struct knote *kn)
> +{
> + struct socket *so = kn->kn_fp->f_data;
> + int rv, s;
> +
> + s = solock(so);
> + knote_modify(kev, kn);
> + rv = filt_solisten_common(kn, so);
> + sounlock(so, s);
> +
> + return (rv);
> +}
> +
> +int
> +filt_solistenprocess(struct knote *kn, struct kevent *kev)
> +{
> + struct socket *so = kn->kn_fp->f_data;
> + int rv, s;
> +
> + s = solock(so);
> + if (kev != NULL && (kn->kn_flags & EV_ONESHOT))
> + rv = 1;
> + else
> + rv = filt_solisten_common(kn, so);
> + if (rv != 0)
> + knote_submit(kn, kev);
> + sounlock(so, s);
> +
> + return (rv);
> +}
> +
> #ifdef DDB
> void
> sobuf_print(struct sockbuf *,
> Index: kern/uipc_syscalls.c
> ===================================================================
> RCS file: src/sys/kern/uipc_syscalls.c,v
> retrieving revision 1.190
> diff -u -p -r1.190 uipc_syscalls.c
> --- kern/uipc_syscalls.c 13 May 2021 17:31:59 -0000 1.190
> +++ kern/uipc_syscalls.c 20 May 2021 14:01:18 -0000
> @@ -308,7 +308,7 @@ doaccept(struct proc *p, int sock, struc
> : (flags & SOCK_NONBLOCK ? FNONBLOCK : 0);
>
> /* connection has been removed from the listen queue */
> - KNOTE(&head->so_rcv.sb_sel.si_note, NOTE_SUBMIT);
> + KNOTE(&head->so_rcv.sb_sel.si_note, 0);
>
> fp->f_type = DTYPE_SOCKET;
> fp->f_flag = FREAD | FWRITE | nflag;