Most recent kernel where this bug did not occur: the bug is current Distribution: SUSE 10.0 Hardware Environment: x86 Software Environment: Problem Description: This is either a bug report or an attempt at clarification of expected behaviour. I do not have a 2.6.15 vanilla kernel to hand, but when I did last test that kernel, the problems described below also existed there. Recently (I'm the man-pages maintainer), I added text to the open(2) man page to document the fact that O_ASYNC does not work when supplied to open(2). In the process I observed some anomalous semantics for O_ASYNC, detailed below. Steps to reproduce: On Linux, specifying O_ASYNC when open()ing a FIFO or terminal does not enable signal-driven I/O for the file descriptor/open file description. This behaviour is sort of expected: O_ASYNC is not specified in POSIX/SUSv3, but is implemented on many Unix systems. And most Unix implementations that I've tested don't honour O_ASYNC on open(): as on Linux, the flag must be set using fcntl(F_SETFL). (It would be nice if Linux did honour the flag on open(), but that isn't essential for consistency with other implementations.) But there is some anomalous behaviour... If we do the following: 1. open() the file with O_ASYNC (aka FASYNC). We can then see that the flag is set for the open file (it can be retrieved using fcntl(F_GETFL)). 2. Set the file descriptor owner using fcntl(F_SETOWN). 3. Although O_ASYNC is set, signal-driven I/O is not enabled -- no signal is generated when I/O (e.g., input) becomes possible. (As noted above, this is more or less expected behavior.) 4. If we want to enable signal-driven I/O on the file, then we must: a) Disable O_ASYNC using fcntl(F_SETFL); b) Enable O_ASYNC using fcntl(F_SETFL); However, I see that at least some other implementations (e.g., FreeBSD 6.0) do not require step 4a in the scenario above. In other words, if we ("accidentally") specify O_ASYNC when opening a FIFO, then going on to simply enable O_ASYNC using fcntl(F_SETFL) is sufficient to enable signal-driven I/O on FreeBSD. By contrast Linux requires that we explicitly disable the flag first. The Linux behaviour seems a bit bizarre, and it seems to me that it should be fixed. I've appended a test program below. Running the program with the following arguments demonstrates that simply opening a FIFO using O_ASYNC is not enough to get signal-driven I/O semantics: $ mkfifo p $ ./test_O_ASYNC ./p & $ cat > p [type newline] Running the program with the following arguments excludes step 4a above, but does perform step 4b. This does not permit signal-driven I/O (but on FreeBSD 6.0 it does): $ mkfifo p $ ./test_O_ASYNC ./p f & $ cat > p [type newline] The following run implements step 4a and 4b, and permits signal-driven I/O: $ mkfifo p $ ./test_O_ASYNC ./p cf $ cat > p [type newline] Cheers, Michael PS The following LKML posts have some relevance: http://marc.theaimsgroup.com/?t=100572281200001&r=1&w=2 http://marc.theaimsgroup.com/?l=linux-kernel&m=100580818429730&w=2 /* test_O_ASYNC.c */ #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <signal.h> #include <fcntl.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) #define usageErr(msg, progName) \ do { fprintf(stderr, "Usage: "); \ fprintf(stderr, msg, progName); \ exit(EXIT_FAILURE); } while (0) static void handler(int sig) { printf("Caught signal %d\n", sig); } /* handler */ int main(int argc, char *argv[]) { int fd, flags; int no_open_O_ASYNC, fcntl_O_ASYNC, clear_O_ASYNC, no_F_SETOWN; struct sigaction sa; sa.sa_handler = handler; sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); if (sigaction(SIGIO, &sa, NULL) == -1) errExit("sigaction"); if (argc < 2 || strcmp(argv[1], "--help") == 0) usageErr("%s FIFO-path [nf]\n", argv[0]); no_open_O_ASYNC = argc > 2 && strchr(argv[2], 'O') != NULL; no_F_SETOWN = argc > 2 && strchr(argv[2], 'S') != NULL; fcntl_O_ASYNC = argc > 2 && strchr(argv[2], 'f') != NULL; clear_O_ASYNC = argc > 2 && strchr(argv[2], 'c') != NULL; #if 0 printf("no_open_O_ASYNC = %d\n", no_open_O_ASYNC); printf("no_F_SETOWN = %d\n", no_F_SETOWN); printf("fcntl_O_ASYNC = %d\n", fcntl_O_ASYNC); printf("clear_O_ASYNC = %d\n", clear_O_ASYNC); #endif fd = open(argv[1], O_RDONLY | (no_open_O_ASYNC ? 0 : O_ASYNC)); if (fd == -1) errExit("open"); if (!no_F_SETOWN) { if (fcntl(fd, F_SETOWN, getpid()) == -1) errExit("fcntl - F_SETOWN"); } if (clear_O_ASYNC) { flags = fcntl(fd, F_GETFL); if (flags == -1) errExit("open"); if (fcntl(fd, F_SETFL, flags & ~O_ASYNC) == -1) errExit("fcntl"); } if (fcntl_O_ASYNC) { flags = fcntl(fd, F_GETFL); if (flags == -1) errExit("open"); if (fcntl(fd, F_SETFL, flags | O_ASYNC) == -1) errExit("fcntl"); } for (;;) pause(); exit(EXIT_SUCCESS); } /* main */
Michael has anything changed in the kernel with regard to behavior of open that you reported about? Thanks.
Reply-To: michael.kerrisk@googlemail.com bugme-daemon@bugzilla.kernel.org wrote: > http://bugzilla.kernel.org/show_bug.cgi?id=5993 > > > protasnb@gmail.com changed: > > What |Removed |Added > ---------------------------------------------------------------------------- > CC| |protasnb@gmail.com > Component|Other |Other > Product|Other |File System > > > > > ------- Comment #1 from protasnb@gmail.com 2007-08-25 22:48 ------- > Michael has anything changed in the kernel with regard to behavior of open > that > you reported about? > Thanks. > > Not as far as I know.
Confirm bug. Tested on: * Ubuntu 8.04.2 AMD64 2.6.24-24-generic * Xandos i386 2.6.21.4-eeepc Further details with FASM source code for testing: http://board.flatassembler.net/topic.php?p=96629#96629