Messages in this thread | | | Date | Sun, 05 Sep 1999 14:53:08 +0200 | From | Manfred Spraul <> | Subject | Re: Race conditions in file creation in 2.3. |
| |
Alan wrote: > I think the error is coming from open() from the error message cp issued.
Yes, but it's open(O_TRUNC).
I could reproduce a bug with the attached c-program. Just start ~ 10 processes and wait [amd-K6 200, scsi, ext2 disk]
The bug could be caused by the missing synchronization of truncate() and write() This is a known problem since ~2.3.7. [neither O_APPEND, nor i_size nor f_pos are synchronized]
Unfortunately, it seems difficult to fix it properly:
1) affected files: several places outside VFS access i_sem directly: [at least] + fs/nfsd/vfs.c + arch/*/kernel/sys_*.c + drivers/char/tty_io.c
2) different types of files have completely different synchronzation requirements, so I think flags should be added to VFS which sync calls are required.
+ pipes: nothing, even parallel read()/write() calls to the same filp must not block in VFS [the pipe could use O_NONBLOCK] linux-2.2 uses a dirty hack: fs/pipe.c knows that sys_write() called down(i_sem), and pipe.c calls up().
+ e.g. raw-io: everything can run parallel _except_ parallel sys_read()/sys_write() calls to the same filp [flip->f_pos!]. No restrictions on parallel sys_pread()/sys_pwrite(). Note that this cannot be implemented in raw.c, because raw.c does not know whether sys_read() or sys_pread() was called.
+ normal files: parallel, non-overlapping read/write calls are possible[ overlapping writes violate NfsV2]. Truncate can run in parallel with read()/write() if these calls don't access the area between [old-EOF, new-EOF]. Even Windows 95 allow this level or parallelity for some files, this should be possible under Linux as well.
+ everything else: I'd call down() before calling f_ops->read()/write(), I don't know if all character devices can handle parallel read()/write() calls. If they can handle it, then they should set appopriate flags. -- Manfred#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <fcntl.h>
static char buffer[81930];
extern "C" int main( int argc, char *argv[] ) { printf("opentest <test file>\n"); if(argc != 2) { printf(" Invalid parameters.\n"); return 1; } for (;;) { int handle;
handle = open(argv[1],O_WRONLY|O_CREAT|O_TRUNC, 0600); if(handle==-1) { printf("open failed: %d.\n",errno); return 1; } write(handle, buffer, 81930); write(handle, buffer, 81930); write(handle, buffer, 81930); write(handle, buffer, 81930); write(handle, buffer, 81930); write(handle, buffer, 81930); close(handle); unlink(argv[1]); } return 0; }
| |