fs/buffer.c | 19 ++++++++----------- fs/direct-io.c | 12 ++++++++---- mm/filemap.c | 23 ++++++++++++----------- 3 files changed, 28 insertions(+), 26 deletions(-) diff -puN fs/direct-io.c~O_DIRECT-race-fixes-fixes fs/direct-io.c --- 25/fs/direct-io.c~O_DIRECT-race-fixes-fixes 2003-09-10 23:45:15.000000000 -0700 +++ 25-akpm/fs/direct-io.c 2003-09-10 23:45:15.000000000 -0700 @@ -470,10 +470,14 @@ static int get_more_blocks(struct dio *d fs_count++; if (dio->is_reg_file) { - if (dio->block_in_file > dio->inode->i_size) { + if (dio->block_in_file >= (i_size_read(dio->inode) >> + dio->blkbits)) beyond_eof = 1; - } } + /* + * AKPM: huh? We call get_blocks(create==0) for hole + * overwrites? + */ ret = (*dio->get_blocks)(dio->inode, fs_startblk, fs_count, map_bh, (dio->rw == WRITE) && beyond_eof); } @@ -782,9 +786,9 @@ do_holes: if (!buffer_mapped(map_bh)) { char *kaddr; - if (dio->rw == WRITE) { + /* AKPM: eargh, -ENOTBLK is a hack */ + if (dio->rw == WRITE) return -ENOTBLK; - } if (dio->block_in_file >= i_size_read(dio->inode)>>blkbits) { diff -puN mm/filemap.c~O_DIRECT-race-fixes-fixes mm/filemap.c --- 25/mm/filemap.c~O_DIRECT-race-fixes-fixes 2003-09-10 23:45:15.000000000 -0700 +++ 25-akpm/mm/filemap.c 2003-09-10 23:45:15.000000000 -0700 @@ -70,6 +70,9 @@ * ->mmap_sem * ->i_sem (msync) * + * ->i_alloc_sem + * ->i_sem (various) + * * ->inode_lock * ->sb_lock (fs/fs-writeback.c) * ->mapping->page_lock (__sync_single_inode) @@ -1843,18 +1846,17 @@ __generic_file_aio_write_nolock(struct k status = generic_osync_inode(inode, OSYNC_METADATA); if (written >= 0 && !is_sync_kiocb(iocb)) written = -EIOCBQUEUED; - if (written == -ENOTBLK) { - if (S_ISREG(inode->i_mode)) { - down(&inode->i_sem); - } - goto do_buffer_io; - } - goto out_status; + if (written != -ENOTBLK) + goto out_status; + /* + * direct-io write to a hole: fall through to buffered I/O + */ + written = 0; + if (S_ISREG(inode->i_mode)) + down(&inode->i_sem); } -do_buffer_io: buf = iov->iov_base; - written = 0; /* Reset in case this is a fallback from O_DIRECT */ do { unsigned long index; unsigned long offset; @@ -1953,9 +1955,8 @@ do_buffer_io: if (unlikely(file->f_flags & O_DIRECT)) { if (written) do_fdatasync(file); - if (S_ISREG(inode->i_mode)) { + if (S_ISREG(inode->i_mode)) up(&inode->i_sem); - } } out_status: diff -puN fs/buffer.c~O_DIRECT-race-fixes-fixes fs/buffer.c --- 25/fs/buffer.c~O_DIRECT-race-fixes-fixes 2003-09-10 23:45:18.000000000 -0700 +++ 25-akpm/fs/buffer.c 2003-09-10 23:45:54.000000000 -0700 @@ -402,20 +402,17 @@ asmlinkage long sys_fdatasync(unsigned i { struct file * file; struct inode * inode; - int ret, err; + int ret; ret = -EBADF; file = fget(fd); - if (!file) - goto out; - - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - ret = do_fdatasync(file); - up(&inode->i_sem); -out_putf: - fput(file); -out: + if (file) { + inode = file->f_dentry->d_inode; + down(&inode->i_sem); + ret = do_fdatasync(file); + up(&inode->i_sem); + fput(file); + } return ret; } _