diff -urN linux-2.4.21/fs/block_dev.c linux-2.4.21.SuSE/fs/block_dev.c --- linux-2.4.21/fs/block_dev.c 2003-07-01 15:49:54.000000000 +0200 +++ linux-2.4.21.SuSE/fs/block_dev.c 2003-07-01 15:51:21.000000000 +0200 @@ -719,6 +719,8 @@ direct_IO: blkdev_direct_IO, }; +static int blkdev_kvec_read(struct file *filp, kvec_cb_t cb, size_t size, loff_t pos); +static int blkdev_kvec_write(struct file *filp, kvec_cb_t cb, size_t size, loff_t pos); struct file_operations def_blk_fops = { open: blkdev_open, release: blkdev_close, @@ -728,6 +730,10 @@ mmap: generic_file_mmap, fsync: block_fsync, ioctl: blkdev_ioctl, + aio_read: generic_file_aio_read, + aio_write: generic_file_aio_write, + kvec_read: blkdev_kvec_read, + kvec_write: blkdev_kvec_write, }; const char * bdevname(kdev_t dev) @@ -741,3 +747,121 @@ sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev)); return buffer; } +static int blkdev_kvec_rw(struct file *filp, int rw, kvec_cb_t cb, size_t size, loff_t pos); +static int blkdev_kvec_read(struct file *file, kvec_cb_t cb, size_t size, loff_t pos) +{ + if (file->f_flags & O_DIRECT) + return blkdev_kvec_rw(file, READ, cb, size, pos); + else + return generic_file_kvec_read(file, cb, size, pos); +} + +static int blkdev_kvec_write(struct file *file, kvec_cb_t cb, size_t size, loff_t pos) +{ + if (file->f_flags & O_DIRECT) + return blkdev_kvec_rw(file, WRITE, cb, size, pos); + else + return generic_file_kvec_write(file, cb, size, pos); +} + +static int blkdev_kvec_rw(struct file *filp, int rw, kvec_cb_t cb, size_t size, loff_t pos) +{ + int err; + unsigned minor; + kdev_t dev; + unsigned long limit, blocknr, blocks; + + unsigned sector_size, sector_bits, sector_mask; + unsigned max_sectors; + unsigned i; + + pr_debug("blkdev_kvec_rw: %p %d %d %p %d %d %Lu\n", filp, rw, nr, kiovec, flags, size, pos); + /* + * First, a few checks on device size limits + */ + + dev = filp->f_dentry->d_inode->i_rdev; + sector_size = 512; + if (is_mounted(dev)) { + if (blksize_size[MAJOR(dev)]) + sector_size = blksize_size[MAJOR(dev)][MINOR(dev)]; + } else { + if (hardsect_size[MAJOR(dev)]) + sector_size = hardsect_size[MAJOR(dev)][MINOR(dev)]; + } + + if (sector_size == 512) /* Fastpath */ + sector_bits = 9; + else { + for (sector_bits = 0; sector_size > (1 << sector_bits); sector_bits++); + if ((1 << sector_bits) != sector_size) { + BUG(); + return -EINVAL; + } + } + + sector_mask = sector_size - 1; + max_sectors = 25000; /* KIO_MAX_SECTORS >> (sector_bits - 9); */ + + if (blk_size[MAJOR(dev)]) + limit = (((loff_t) blk_size[MAJOR(dev)][MINOR(dev)]) << BLOCK_SIZE_BITS) >> sector_bits; + else + limit = INT_MAX; + pr_debug("blkdev_kvec_rw: dev %d:%d (+%lu)\n", + MAJOR(dev), MINOR(dev), limit); + + /* EOF at the end */ + err = 0; + if (!size || (pos >> sector_bits) == limit) { + pr_debug("blkdev_kvec_rw: %Lu > %lu, %d\n", pos >> sector_bits, limit, sector_bits); + cb.fn(cb.data, cb.vec, err); + return 0; + } + + /* ENXIO for io beyond the end */ + err = -ENXIO; + if ((pos >> sector_bits) >= limit) { + pr_debug("blkdev_kvec_rw: %Lu > %lu, %d\n", pos >> sector_bits, limit, sector_bits); + goto out; + } + + err = -EINVAL; + if ((pos < 0) || (pos & sector_mask) || (size & sector_mask)) { + pr_debug("pos(%Ld)/size(%lu) wrong(%d)\n", pos, size, sector_mask); + goto out; + } + + /* Verify that the scatter-gather list is sector aligned. */ + for (i=0; inr; i++) + if ((cb.vec->veclet[i].offset & sector_mask) || + (cb.vec->veclet[i].length & sector_mask)) { + pr_debug("veclet offset/length wrong"); + goto out; + } + + /* + * Split the IO into KIO_MAX_SECTORS chunks, mapping and + * unmapping the single kiobuf as we go to perform each chunk of + * IO. + */ + + blocknr = pos >> sector_bits; + blocks = size >> sector_bits; + if (blocks > max_sectors) + blocks = max_sectors; + if (blocks > limit - blocknr) + blocks = limit - blocknr; + err = -ENXIO; + if (!blocks) { + pr_debug("blkdev: !blocks %d %ld %ld\n", max_sectors, limit, blocknr); + goto out; + } + + err = brw_kvec_async(rw, cb, dev, blocks, blocknr, sector_bits); +out: + if (err) + printk(KERN_DEBUG "blkdev_kvec_rw: ret is %d\n", err); + return err; +} + + diff -urN linux-2.4.21/mm/filemap.c linux-2.4.21.SuSE/mm/filemap.c --- linux-2.4.21/mm/filemap.c 2003-07-01 15:49:55.000000000 +0200 +++ linux-2.4.21.SuSE/mm/filemap.c 2003-07-01 15:51:21.000000000 +0200 @@ -3913,6 +3913,9 @@ unsigned long nr_pages; int ret; + /* Use the mapping host inode to get block and CODA right */ + inode = as->host; + if (io->rw == WRITE) { unsigned long long tmp; loff_t limit;