diff -urNp --exclude CVS --exclude BitKeeper x-ref/drivers/char/raw.c x/drivers/char/raw.c --- x-ref/drivers/char/raw.c 2003-07-17 05:39:38.000000000 +0200 +++ x/drivers/char/raw.c 2003-07-17 05:39:42.000000000 +0200 @@ -94,12 +94,6 @@ int raw_open(struct inode *inode, struct filp->f_op = &raw_ctl_fops; return 0; } - - if (!filp->f_iobuf) { - err = alloc_kiovec(1, &filp->f_iobuf); - if (err) - return err; - } down(&raw_devices[minor].mutex); /* @@ -145,7 +139,6 @@ int raw_open(struct inode *inode, struct set_blocksize(rdev, sector_size); raw_devices[minor].sector_size = sector_size; - filp->f_iobuf->varyio = raw_devices[minor].varyio; for (sector_bits = 0; !(sector_size & 1); ) sector_size>>=1, sector_bits++; @@ -303,7 +296,6 @@ ssize_t rw_raw_dev(int rw, struct file * size_t size, loff_t *offp) { struct kiobuf * iobuf; - int new_iobuf; int err = 0; unsigned long blocknr, blocks; size_t transferred; @@ -322,19 +314,10 @@ ssize_t rw_raw_dev(int rw, struct file * minor = MINOR(filp->f_dentry->d_inode->i_rdev); - new_iobuf = 0; - iobuf = filp->f_iobuf; - if (test_and_set_bit(0, &filp->f_iobuf_lock)) { - /* - * A parallel read/write is using the preallocated iobuf - * so just run slow and allocate a new one. - */ - err = alloc_kiovec(1, &iobuf); - if (err) - goto out; - new_iobuf = 1; - iobuf->varyio = raw_devices[minor].varyio; - } + err = alloc_kiovec(1, &iobuf); + if (err) + return err; + iobuf->varyio = raw_devices[minor].varyio; dev = to_kdev_t(raw_devices[minor].binding->bd_dev); sector_size = raw_devices[minor].sector_size; @@ -407,11 +390,7 @@ ssize_t rw_raw_dev(int rw, struct file * } out_free: - if (!new_iobuf) - clear_bit(0, &filp->f_iobuf_lock); - else - free_kiovec(1, &iobuf); - out: + free_kiovec(1, &iobuf); return err; } diff -urNp --exclude CVS --exclude BitKeeper x-ref/fs/fcntl.c x/fs/fcntl.c --- x-ref/fs/fcntl.c 2003-07-17 05:39:29.000000000 +0200 +++ x/fs/fcntl.c 2003-07-17 05:39:58.000000000 +0200 @@ -214,9 +214,9 @@ static int setfl(int fd, struct file * f return -EPERM; /* - * alloc_kiovec() and ->fasync can sleep, so abuse the i_sem + * ->fasync can sleep, so abuse the i_sem * to serialize against parallel setfl on the same filp, - * to avoid races with ->f_flags and ->f_iobuf. + * to avoid races with ->f_flags. */ down(&inode->i_sem); /* Did FASYNC state change? */ @@ -230,19 +230,6 @@ static int setfl(int fd, struct file * f } } - if (arg & O_DIRECT) { - error = -EINVAL; - if (!inode->i_mapping || !inode->i_mapping->a_ops || - !have_mapping_directIO(inode->i_mapping)) - goto out; - - if (!filp->f_iobuf) { - error = alloc_kiovec(1, &filp->f_iobuf); - if (error < 0) - goto out; - } - } - /* required for strict SunOS emulation */ if (O_NONBLOCK != O_NDELAY) if (arg & O_NDELAY) diff -urNp --exclude CVS --exclude BitKeeper x-ref/fs/file_table.c x/fs/file_table.c --- x-ref/fs/file_table.c 2003-07-17 05:39:38.000000000 +0200 +++ x/fs/file_table.c 2003-07-17 05:39:42.000000000 +0200 @@ -105,9 +105,6 @@ inline void __fput(struct file * file) locks_remove_flock(file); - if (file->f_iobuf) - free_kiovec(1, &file->f_iobuf); - if (file->f_op && file->f_op->release) file->f_op->release(inode, file); fops_put(file->f_op); diff -urNp --exclude CVS --exclude BitKeeper x-ref/fs/iobuf.c x/fs/iobuf.c --- x-ref/fs/iobuf.c 2003-07-17 05:39:30.000000000 +0200 +++ x/fs/iobuf.c 2003-07-17 05:39:42.000000000 +0200 @@ -8,7 +8,6 @@ #include #include -#include static kmem_cache_t *kiobuf_cachep; @@ -27,6 +26,8 @@ void end_kio_request(struct kiobuf *kiob static int kiobuf_init(struct kiobuf *iobuf) { + int retval; + init_waitqueue_head(&iobuf->wait_queue); iobuf->array_len = 0; iobuf->nr_pages = 0; @@ -36,7 +37,17 @@ static int kiobuf_init(struct kiobuf *io iobuf->blocks = NULL; atomic_set(&iobuf->io_count, 0); iobuf->end_io = NULL; - return expand_kiobuf(iobuf, KIO_STATIC_PAGES); + iobuf->initialized = 0; + retval = expand_kiobuf(iobuf, KIO_STATIC_PAGES); + if (unlikely(retval)) + return retval; + retval = alloc_kiobuf_bhs(iobuf); + if (unlikely(retval)) { + kfree(iobuf->maplist); + return retval; + } + iobuf->initialized = 1; + return 0; } int alloc_kiobuf_bhs(struct kiobuf * kiobuf) @@ -90,6 +101,23 @@ void free_kiobuf_bhs(struct kiobuf * kio } } +void kiobuf_ctor(void * objp, kmem_cache_t * cachep, unsigned long flag) +{ + struct kiobuf * iobuf = (struct kiobuf *) objp; + + kiobuf_init(iobuf); +} + +void kiobuf_dtor(void * objp, kmem_cache_t * cachep, unsigned long flag) +{ + struct kiobuf * iobuf = (struct kiobuf *) objp; + + if (likely(iobuf->initialized)) { + kfree(iobuf->maplist); + free_kiobuf_bhs(iobuf); + } +} + int alloc_kiovec(int nr, struct kiobuf **bufp) { int i; @@ -99,9 +127,7 @@ int alloc_kiovec(int nr, struct kiobuf * iobuf = kmem_cache_alloc(kiobuf_cachep, GFP_KERNEL); if (unlikely(!iobuf)) goto nomem; - if (unlikely(kiobuf_init(iobuf))) - goto nomem2; - if (unlikely(alloc_kiobuf_bhs(iobuf))) + if (unlikely(!iobuf->initialized)) goto nomem2; bufp[i] = iobuf; } @@ -124,9 +150,8 @@ void free_kiovec(int nr, struct kiobuf * iobuf = bufp[i]; if (iobuf->locked) unlock_kiovec(1, &iobuf); - kfree(iobuf->maplist); - free_kiobuf_bhs(iobuf); - kmem_cache_free(kiobuf_cachep, bufp[i]); + iobuf->end_io = NULL; + kmem_cache_free(kiobuf_cachep, iobuf); } } @@ -181,7 +206,7 @@ repeat: void __init iobuf_cache_init(void) { kiobuf_cachep = kmem_cache_create("kiobuf", sizeof(struct kiobuf), - 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + 0, SLAB_HWCACHE_ALIGN, kiobuf_ctor, kiobuf_dtor); if (!kiobuf_cachep) panic("Cannot create kiobuf SLAB cache"); } diff -urNp --exclude CVS --exclude BitKeeper x-ref/fs/open.c x/fs/open.c --- x-ref/fs/open.c 2003-07-17 05:39:37.000000000 +0200 +++ x/fs/open.c 2003-07-17 05:39:42.000000000 +0200 @@ -685,15 +685,6 @@ struct file *dentry_open(struct dentry * f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_sb->s_files); - /* preallocate kiobuf for O_DIRECT */ - f->f_iobuf = NULL; - f->f_iobuf_lock = 0; - if (f->f_flags & O_DIRECT) { - error = alloc_kiovec(1, &f->f_iobuf); - if (error) - goto cleanup_all; - } - if (f->f_op && f->f_op->open) { error = f->f_op->open(inode,f); if (error) @@ -710,8 +701,6 @@ struct file *dentry_open(struct dentry * return f; cleanup_all: - if (f->f_iobuf) - free_kiovec(1, &f->f_iobuf); fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) put_write_access(inode); diff -urNp --exclude CVS --exclude BitKeeper x-ref/include/linux/fs.h x/include/linux/fs.h --- x-ref/include/linux/fs.h 2003-07-17 05:39:40.000000000 +0200 +++ x/include/linux/fs.h 2003-07-17 05:39:42.000000000 +0200 @@ -659,10 +659,6 @@ struct file { /* needed for tty driver, and maybe others */ void *private_data; - - /* preallocated helper kiobuf to speedup O_DIRECT */ - struct kiobuf *f_iobuf; - long f_iobuf_lock; }; extern spinlock_t files_lock; #define file_list_lock() spin_lock(&files_lock); diff -urNp --exclude CVS --exclude BitKeeper x-ref/include/linux/iobuf.h x/include/linux/iobuf.h --- x-ref/include/linux/iobuf.h 2003-07-17 05:39:30.000000000 +0200 +++ x/include/linux/iobuf.h 2003-07-17 05:39:42.000000000 +0200 @@ -41,7 +41,8 @@ struct kiobuf int length; /* Number of valid bytes of data */ unsigned int locked : 1, /* If set, pages has been locked */ - varyio : 1; /* If set, do variable size IO */ + varyio : 1, /* If set, do variable size IO */ + initialized:1; /* If set, done initialize */ struct page ** maplist; struct buffer_head ** bh; diff -urNp --exclude CVS --exclude BitKeeper x-ref/mm/filemap.c x/mm/filemap.c --- x-ref/mm/filemap.c 2003-07-17 05:39:40.000000000 +0200 +++ x/mm/filemap.c 2003-07-17 05:39:42.000000000 +0200 @@ -1570,24 +1570,15 @@ static inline int do_call_directIO(int r static ssize_t generic_file_direct_IO(int rw, struct file * filp, char * buf, size_t count, loff_t offset) { ssize_t retval; - int new_iobuf, chunk_size, blocksize_mask, blocksize, blocksize_bits, iosize, progress; + int chunk_size, blocksize_mask, blocksize, blocksize_bits, iosize, progress; struct kiobuf * iobuf; struct address_space * mapping = filp->f_dentry->d_inode->i_mapping; struct inode * inode = mapping->host; loff_t size = i_size_read(inode); - new_iobuf = 0; - iobuf = filp->f_iobuf; - if (test_and_set_bit(0, &filp->f_iobuf_lock)) { - /* - * A parallel read/write is using the preallocated iobuf - * so just run slow and allocate a new one. - */ - retval = alloc_kiovec(1, &iobuf); - if (retval) - goto out; - new_iobuf = 1; - } + retval = alloc_kiovec(1, &iobuf); + if (retval) + goto out; blocksize = 1 << inode->i_blkbits; blocksize_bits = inode->i_blkbits; @@ -1645,10 +1636,7 @@ static ssize_t generic_file_direct_IO(in retval = progress; out_free: - if (!new_iobuf) - clear_bit(0, &filp->f_iobuf_lock); - else - free_kiovec(1, &iobuf); + free_kiovec(1, &iobuf); out: return retval; }