[PATCH 7/8] block: provide aio_read_pages and aio_write_pages

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This adds functions which perform direct aio read and write on the specified
pages.  This is just a hack to prototype the surrounding code without having to
start with file systems.  It just copies the generic paths which are needed for
direct io to block devices.  It calls the __blockdev_direct_IO_pages() directly
instead of changing the ->direct_IO() prototype.

To do this properly we're going to have to weave support for specifying memory
with pages into the generic paths.  We could have one entry point which takes
an abstract memory argument and conditionals in the path for working on iovecs
or pages.  Or we could have entry points for each memory argument that call
helpers.

Signed-off-by: Zach Brown <zach.brown@xxxxxxxxxx>
---
 fs/block_dev.c |  113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 113 insertions(+), 0 deletions(-)

diff --git a/fs/block_dev.c b/fs/block_dev.c
index 9cf4b92..1a07574 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1436,6 +1436,117 @@ ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
 }
 EXPORT_SYMBOL_GPL(blkdev_aio_write);
 
+/* XXX did I miss an existing helper? _length() like iov_length().. */
+static ssize_t bvec_length(const struct bio_vec *bvec, unsigned long bvec_len)
+{
+	ssize_t bytes = 0;
+	BUG_ON(bvec_len == 0);
+	while (bvec_len--)
+		bytes += (bvec++)->bv_len;
+	return bytes;
+}
+
+/*
+ * A quick prototype for testing.  This has copied the direct reading path of
+ * raw_fops.aio_read which doesn't use iovecs.
+ */
+ssize_t blkdev_aio_read_pages(struct kiocb *iocb, const struct bio_vec *bvec,
+			      unsigned long bvec_len, loff_t pos)
+{
+	struct file *file = iocb->ki_filp;
+	struct address_space *mapping = file->f_mapping;
+	struct inode *inode = mapping->host;
+	ssize_t ret;
+	size_t count;
+
+	BUG_ON(iocb->ki_pos != pos);
+
+	if (!(file->f_flags & O_DIRECT))
+		return -EINVAL;
+
+	if (pos >= i_size_read(inode))
+		return 0;
+
+	count = bvec_length(bvec, bvec_len);
+	if (!count)
+		return 0;
+
+	ret = filemap_write_and_wait_range(mapping, pos, pos + count - 1);
+	if (ret)
+		return ret;
+
+	ret = __blockdev_direct_IO_pages(READ, iocb, inode, I_BDEV(inode),
+					 bvec, bvec_len, pos,
+					 blkdev_get_blocks, NULL,
+					 DIO_NO_LOCKING);
+	if (ret)
+		file_accessed(file);
+	return ret;
+}
+
+/*
+ * A quick prototype for testing.  This has copied the direct writing path of
+ * raw_fops.aio_write which doesn't use iovecs.
+ */
+ssize_t blkdev_aio_write_pages(struct kiocb *iocb, const struct bio_vec *bvec,
+			       unsigned long bvec_len, loff_t pos)
+{
+	struct file *file = iocb->ki_filp;
+	struct address_space *mapping = file->f_mapping;
+	struct inode *inode = mapping->host;
+	ssize_t ret;
+	size_t count;
+
+	BUG_ON(iocb->ki_pos != pos);
+
+	if (!(file->f_flags & O_DIRECT))
+		return -EINVAL;
+
+	vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
+
+	count = bvec_length(bvec, bvec_len);
+
+	ret = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
+	if (ret)
+		goto out;
+
+	if (!count)
+		return 0;
+
+	ret = file_remove_suid(file);
+	if (ret)
+		goto out;
+
+	file_update_time(file);
+
+	ret = filemap_write_and_wait_range(mapping, pos, pos + count - 1);
+	if (ret)
+		goto out;
+
+	if (mapping->nrpages) {
+		ret = invalidate_inode_pages2_range(mapping,
+					pos >> PAGE_CACHE_SHIFT, 
+					(pos + count - 1) >> PAGE_CACHE_SHIFT);
+		/* XXX this'll return -EBUSY when a page can't be validated
+		 * as we're not falling back to buffered */
+		if (ret)
+			goto out;
+	}
+
+	ret = __blockdev_direct_IO_pages(WRITE, iocb, inode, I_BDEV(inode),
+					 bvec, bvec_len, pos, blkdev_get_blocks,
+					 NULL, DIO_NO_LOCKING);
+	if (ret > 0 || ret == -EIOCBQUEUED) {
+		ssize_t err; 
+		
+		err = generic_write_sync(file, pos, ret > 0 ? ret : count);
+		if (err < 0 && ret > 0)
+			ret = err;
+	}
+out:
+	return ret;
+}
+
 /*
  * Try to release a page associated with block device when the system
  * is under memory pressure.
@@ -1477,6 +1588,8 @@ const struct file_operations def_blk_fops = {
 #endif
 	.splice_read	= generic_file_splice_read,
 	.splice_write	= generic_file_splice_write,
+  	.aio_read_pages	= blkdev_aio_read_pages,
+	.aio_write_pages	= blkdev_aio_write_pages,
 };
 
 int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg)
-- 
1.6.2.5

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux