[PATCH 8/8] loop: use aio to perform io on the underlying file

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

 



This uses the new kernel aio interface to process loopback IO by submitting
concurrent direct aio.  Previously loop's IO was serialized by synchronus
processing in a thread.  It specifies io memory by directly referencing the
pages in the incoming bios rather than kmapping them.

This patch lets us start testing, but we should fix the following before its
merged:

* We might want to fall back to non-vectored ops if the file doesn't support
  vectored ops.

* Talk to Jens about cleverly translating bio flags (like barriers?) down
  to the bios that fs/direct-io.c is building based on our pages?

* More carefully discover support for and enable o_direct.

* Call into fs/aio.c to discover if aio is supported.

Signed-off-by: Zach Brown <zach.brown@xxxxxxxxxx>
---
 drivers/block/loop.c |   62 +++++++++++++++++++++++++++++++++++++++++++------
 include/linux/loop.h |    1 +
 2 files changed, 55 insertions(+), 8 deletions(-)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index edda9ea..1180808 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -267,6 +267,41 @@ fail:
 	goto out;
 }
 
+void lo_rw_aio_complete(u64 data, long res)
+{
+	struct bio *bio = (struct bio *)data;
+
+	if (res > 0)
+		res = 0;
+	else if (res < 0)
+		res = -EIO;
+
+	bio_endio(bio, res);
+}
+
+static int lo_rw_aio(struct loop_device *lo, struct bio *bio, loff_t pos)
+{
+	struct file *file = lo->lo_backing_file;
+	struct kiocb *iocb;
+	unsigned short op;
+
+	iocb = aio_kernel_alloc(mapping_gfp_mask(file->f_mapping));
+	if (!iocb)
+		return -ENOMEM;
+
+	if (bio_rw(bio) & WRITE)
+		op = IOCB_CMD_PWRITEP;
+	else
+		op = IOCB_CMD_PREADP;
+
+	/* XXX can we just reference the bvec array like this? */
+	aio_kernel_init_rw(iocb, file, op, bio_iovec_idx(bio, bio->bi_idx),
+			   bio_segments(bio), pos);
+	aio_kernel_init_callback(iocb, lo_rw_aio_complete, (u64)bio);
+
+	return aio_kernel_submit(iocb);
+}
+
 /**
  * __do_lo_send_write - helper for writing data to a loop device
  *
@@ -467,13 +502,22 @@ lo_receive(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos)
 	return ret;
 }
 
-static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
+static void do_bio_filebacked(struct loop_device *lo, struct bio *bio)
 {
 	loff_t pos;
 	int ret;
 
 	pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset;
 
+	if (lo->lo_flags & LO_FLAGS_USE_AIO && lo->transfer == transfer_none) {
+		ret = lo_rw_aio(lo, bio, pos);
+		if (ret) {
+			ret = -EIO;
+			goto out;
+		}
+		return;
+	}
+
 	if (bio_rw(bio) == WRITE) {
 		bool barrier = bio_rw_flagged(bio, BIO_RW_BARRIER);
 		struct file *file = lo->lo_backing_file;
@@ -502,7 +546,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
 		ret = lo_receive(lo, bio, lo->lo_blocksize, pos);
 
 out:
-	return ret;
+	bio_endio(bio, ret);
 }
 
 /*
@@ -570,10 +614,8 @@ static inline void loop_handle_bio(struct loop_device *lo, struct bio *bio)
 	if (unlikely(!bio->bi_bdev)) {
 		do_loop_switch(lo, bio->bi_private);
 		bio_put(bio);
-	} else {
-		int ret = do_bio_filebacked(lo, bio);
-		bio_endio(bio, ret);
-	}
+	} else 
+		do_bio_filebacked(lo, bio);
 }
 
 /*
@@ -784,9 +826,13 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
 	if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) {
 		const struct address_space_operations *aops = mapping->a_ops;
 
-		if (aops->write_begin)
+		if (file->f_op->aio_write_pages && file->f_op->aio_read_pages){
+			/* XXX dangerous hack */
+			file->f_flags |= O_DIRECT;
+			lo_flags |= LO_FLAGS_USE_AIO;
+		} else if (aops->write_begin)
 			lo_flags |= LO_FLAGS_USE_AOPS;
-		if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write)
+		else if (!file->f_op->write)
 			lo_flags |= LO_FLAGS_READ_ONLY;
 
 		lo_blocksize = S_ISBLK(inode->i_mode) ?
diff --git a/include/linux/loop.h b/include/linux/loop.h
index 66c194e..97a955c 100644
--- a/include/linux/loop.h
+++ b/include/linux/loop.h
@@ -76,6 +76,7 @@ enum {
 	LO_FLAGS_READ_ONLY	= 1,
 	LO_FLAGS_USE_AOPS	= 2,
 	LO_FLAGS_AUTOCLEAR	= 4,
+	LO_FLAGS_USE_AIO	= 8,
 };
 
 #include <asm/posix_types.h>	/* for __kernel_old_dev_t */
-- 
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