Subject: Re: struct emul modification
To: None <tech-kern@netbsd.org>
From: Emmanuel Dreyfus <p99dreyf@criens.u-psud.fr>
List: tech-kern
Date: 06/14/2001 21:21:41
Silence before, flame afterwards?

If nobody complain before sunday, I'll commit this...

> Here is the fix I propose to this problem:
> - no more emulation code in sys/kern/uipc_socket2.c
> - fixes both pipes and sockets inconsitencies
> - async I/O state is consistent if the Linux process re-reads it.
> 
> The key point is using the socket buffer SB_ASYNC flag in sowakeup() instead
> of using the socket flags SS_ASYNC. It has no bad side effect on my NetBSD
> system, I'd like to be sure it's okay before commiting the code. Is it safe to
> do it like this?
> 
> Also, I'd like to do the fix for SunOS emulation, but I need someone to test
> it.
> 
> Index: sys_socket.c
> ===================================================================
> RCS file: /cvsroot/syssrc/sys/kern/sys_socket.c,v
> retrieving revision 1.30
> diff -U4 -r1.30 sys_socket.c
> --- sys_socket.c        2001/05/19 17:28:33     1.30
> +++ sys_socket.c        2001/06/11 21:24:21
> @@ -99,14 +99,9 @@
>                         so->so_state &= ~SS_NBIO;
>                 return (0);
>  
>         case FIOASYNC:
> -               if (
> -#ifndef __HAVE_MINIMAL_EMUL
> -                   (!(so->so_state & SS_ISAPIPE) ||
> -                   (!(p->p_emul->e_flags & EMUL_NO_BSD_ASYNCIO_PIPE))) &&
> -#endif
> -                   *(int *)data) {
> +               if (*(int *)data) {
>                         so->so_state |= SS_ASYNC;
>                         so->so_rcv.sb_flags |= SB_ASYNC;
>                         so->so_snd.sb_flags |= SB_ASYNC;
>                 } else {
> Index: uipc_socket2.c
> ===================================================================
> RCS file: /cvsroot/syssrc/sys/kern/uipc_socket2.c,v
> retrieving revision 1.38
> diff -U4 -r1.38 uipc_socket2.c
> --- uipc_socket2.c      2001/04/30 03:32:56     1.38
> +++ uipc_socket2.c      2001/06/11 21:24:27
> @@ -289,9 +289,9 @@
>  
>  /*
>   * Wakeup processes waiting on a socket buffer.
>   * Do asynchronous notification via SIGIO
> - * if the socket has the SS_ASYNC flag set.
> + * if the socket buffer has the SB_ASYNC flag set.
>   */
>  void
>  sowakeup(struct socket *so, struct sockbuf *sb)
>  {
> @@ -302,9 +302,9 @@
>         if (sb->sb_flags & SB_WAIT) {
>                 sb->sb_flags &= ~SB_WAIT;
>                 wakeup((caddr_t)&sb->sb_cc);
>         }
> -       if (so->so_state & SS_ASYNC) {
> +       if (sb->sb_flags & SB_ASYNC) {
>                 if (so->so_pgid < 0)
>                         gsignal(-so->so_pgid, SIGIO);
>                 else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
>                         psignal(p, SIGIO);
> Index: proc.h
> ===================================================================
> RCS file: /cvsroot/syssrc/sys/sys/proc.h,v
> retrieving revision 1.130
> diff -U4 -r1.130 proc.h
> --- proc.h      2001/05/19 17:28:33     1.130
> +++ proc.h      2001/06/11 21:26:27
> @@ -122,18 +122,8 @@
>  /* 
>   * Emulation miscelaneous flags
>   */
>  #define        EMUL_HAS_SYS___syscall  0x001   /* Has SYS___syscall */
> -/* 
> - * No BSD style async I/O pipes. Aync I/O request through
> - * fcntl() for pipes will be ignored.  
> - */
> -#define EMUL_NO_BSD_ASYNCIO_PIPE       0x002 
> -/* 
> - * No SIGIO fired on read() calls when async I/O is enabled
> - * This is not implemented yet
> - */
> -#define EMUL_NO_SIGIO_ON_READ  0x004 
>  
>  /*
>   * Description of a process.
>   *
> Index: linux_file.c
> ===================================================================
> RCS file: /cvsroot/syssrc/sys/compat/linux/common/linux_file.c,v
> retrieving revision 1.37
> diff -U4 -r1.37 linux_file.c
> --- linux_file.c        2001/01/22 21:31:37     1.37
> +++ linux_file.c        2001/06/11 21:27:35
> @@ -53,8 +53,9 @@
>  #include <sys/mount.h>
>  #include <sys/malloc.h>
>  #include <sys/vnode.h>
>  #include <sys/tty.h>
> +#include <sys/socketvar.h>
>  #include <sys/conf.h>
>  
>  #include <sys/syscallargs.h>
>  
> @@ -319,9 +320,61 @@
>                 val = linux_to_bsd_ioflags((unsigned long)SCARG(uap, arg));
>                 SCARG(&fca, fd) = fd;
>                 SCARG(&fca, cmd) = F_SETFL;
>                 SCARG(&fca, arg) = (caddr_t) val;
> -               return sys_fcntl(p, &fca, retval);
> +               error = sys_fcntl(p, &fca, retval);
> +               /*
> +                * Linux does not send a SIGIO to the write end of a socket,
> +                * neither it does send any SIGIO for pipes. If async I/O
> +                * was requested, we keep the SS_ASYNC iin struct socket flag
> +                * set, but we clear SB_ASYNC flags on the sending buffer
> +                * (for socket), and on the sending and the receiving buffer
> +                * (for pipes). 
> +                * 
> +                * Because we do not alter to SS_ASYNC in struct socket,
> +                * the Linux process keeps a consistent view of async I/O
> +                * status if it attemps to read the async flag (SS_ASYNC)
> +                * 
> +                * This async I/O problem does matters, since some Linux
> +                * programs such as the JDK request async I/O on pipes,
> +                * but they fail if they happen to get a SIGIO to the write
> +                * end of the pipe.
> +                */
> +               if ((error == 0) && (val & O_ASYNC)) {
> +                       struct filedesc *fdp;
> +                       struct file     *fp;
> +                       struct socket *so;
> +
> +                       fdp = p->p_fd;
> +
> +                       if ((u_int)fd >= fdp->fd_nfiles ||
> +                           (fp = fdp->fd_ofiles[fd]) == NULL ||
> +                           (fp->f_iflags & FIF_WANTCLOSE) != 0)
> +                           return (EBADF);
> +
> +                       FILE_USE(fp);
> +
> +                       if ((fp->f_type == DTYPE_SOCKET) && 
> +                           (so = (struct socket*)fp->f_data)) {
> +                               /*
> +                                * Clear async I/O on sending buffer 
> +                                * This will disable SIGIO for the 
> +                                * write end of sockets and pipes.
> +                                */
> +                               so->so_snd.sb_flags &= ~SB_ASYNC;
> +                               /*
> +                                * If it's a pipe, also clear
> +                                * it on the receiving buffer.
> +                                * This will disable SIGIO for the
> +                                * read end of pipes.
> +                                */
> +                               if (so->so_state & SS_ISAPIPE)
> +                                       so->so_rcv.sb_flags &= ~SB_ASYNC;
> +                       }
> +
> +                       FILE_UNUSE(fp, p);
> +               }
> +               return error;
>         case LINUX_F_GETLK:
>                 sg = stackgap_init(p->p_emul);
>                 bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp);
>                 if ((error = copyin(arg, &lfl, sizeof lfl)))
> 
> -- 
> Emmanuel Dreyfus
> p99dreyf@criens.u-psud.fr


-- 
Emmanuel Dreyfus
p99dreyf@criens.u-psud.fr