From: Jens Axboe <jens.axboe@oracle.com>
To: linux-kernel@vger.kernel.org
Cc: jeff@garzik.org, benh@kernel.crashing.org, htejun@gmail.com,
bzolnier@gmail.com, alan@lxorguk.ukuu.org.uk,
Jens Axboe <jens.axboe@oracle.com>
Subject: [PATCH 4/5] loop: support O_DIRECT transfer mode
Date: Thu, 20 Aug 2009 12:17:43 +0200 [thread overview]
Message-ID: <1250763466-24282-9-git-send-email-jens.axboe@oracle.com> (raw)
In-Reply-To: <1250763466-24282-8-git-send-email-jens.axboe@oracle.com>
Make use of the (now) page array backed O_DIRECT with a special
transfer mode for loop.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
drivers/block/loop.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++-
include/linux/loop.h | 1 +
2 files changed, 139 insertions(+), 1 deletions(-)
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 5757188..cf8cf20 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -82,6 +82,9 @@ static DEFINE_MUTEX(loop_devices_mutex);
static int max_part;
static int part_shift;
+static int odirect = 1;
+
+#define LOOP_MAX_DIRECT_SEGMENTS 32
/*
* Transfer functions
@@ -201,6 +204,124 @@ lo_do_transfer(struct loop_device *lo, int cmd,
return lo->transfer(lo, cmd, rpage, roffs, lpage, loffs, size, rblock);
}
+static int direct_fill_pages(struct bio *bio, struct page **pages)
+{
+ unsigned int i, pidx = 0;
+ struct bio_vec *bvec;
+
+ bio_for_each_segment(bvec, bio, i)
+ pages[pidx++] = bvec->bv_page;
+
+ return pidx;
+}
+
+/*
+ * Use the O_DIRECT IO path for this read
+ */
+static int lo_direct_read(struct loop_device *lo, struct bio *bio, loff_t pos)
+{
+ struct file *file = lo->lo_backing_file;
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
+ struct page *pages[LOOP_MAX_DIRECT_SEGMENTS];
+ struct kiocb iocb;
+ loff_t size;
+ int ret = 0;
+ struct dio_args args = {
+ .rw = READ,
+ .pages = pages,
+ .length = bio->bi_size,
+ .user_addr = 0,
+ .offset = pos,
+ };
+
+ init_sync_kiocb(&iocb, file);
+ iocb.ki_pos = pos;
+ iocb.ki_left = bio->bi_size;
+ kiocbSetKernel(&iocb);
+
+ args.nr_segs = direct_fill_pages(bio, pages);
+ args.first_page_off = bio->bi_io_vec[0].bv_offset;
+
+ size = i_size_read(inode);
+ if (pos >= size)
+ return 0;
+
+ ret = filemap_write_and_wait_range(mapping, pos, pos + bio->bi_size-1);
+ if (ret)
+ return ret;
+
+ ret = mapping->a_ops->direct_IO(&iocb, &args);
+ if (ret > 0) {
+ file_accessed(file);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/*
+ * Use the O_DIRECT IO path for this write
+ */
+static int lo_direct_write(struct loop_device *lo, struct bio *bio, loff_t pos)
+{
+ struct file *file = lo->lo_backing_file;
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
+ struct page *pages[LOOP_MAX_DIRECT_SEGMENTS];
+ struct kiocb iocb;
+ int ret = 0;
+ pgoff_t end;
+ struct dio_args args = {
+ .rw = WRITE,
+ .pages = pages,
+ .length = bio->bi_size,
+ .user_addr = 0,
+ .offset = pos,
+ };
+
+ ret = filemap_write_and_wait_range(mapping, pos, pos + bio->bi_size-1);
+ if (ret)
+ goto out;
+
+ end = (pos + bio->bi_size - 1) >> PAGE_CACHE_SHIFT;
+ if (mapping->nrpages) {
+ ret = invalidate_inode_pages2_range(mapping,
+ pos >> PAGE_CACHE_SHIFT, end);
+ if (ret) {
+ if (ret == -EBUSY)
+ ret = 0;
+ goto out;
+ }
+ }
+
+ init_sync_kiocb(&iocb, file);
+ iocb.ki_pos = pos;
+ iocb.ki_left = bio->bi_size;
+ kiocbSetKernel(&iocb);
+
+ args.nr_segs = direct_fill_pages(bio, pages);
+ args.first_page_off = bio->bi_io_vec[0].bv_offset;
+
+ ret = mapping->a_ops->direct_IO(&iocb, &args);
+
+ if (mapping->nrpages) {
+ invalidate_inode_pages2_range(mapping,
+ pos >> PAGE_CACHE_SHIFT, end);
+ }
+
+ if (ret > 0) {
+ loff_t end = pos + ret;
+ if (end > i_size_read(inode) && !S_ISBLK(inode->i_mode)) {
+ i_size_write(inode, end);
+ mark_inode_dirty(inode);
+ }
+ ret = 0;
+ }
+out:
+ return ret;
+}
+
/**
* do_lo_send_aops - helper for writing data to a loop device
*
@@ -347,6 +468,9 @@ static int lo_send(struct loop_device *lo, struct bio *bio, loff_t pos)
struct page *page = NULL;
int i, ret = 0;
+ if (lo->lo_flags & LO_FLAGS_ODIRECT)
+ return lo_direct_write(lo, bio, pos);
+
do_lo_send = do_lo_send_aops;
if (!(lo->lo_flags & LO_FLAGS_USE_AOPS)) {
do_lo_send = do_lo_send_direct_write;
@@ -458,6 +582,9 @@ lo_receive(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos)
struct bio_vec *bvec;
int i, ret = 0;
+ if (lo->lo_flags & LO_FLAGS_ODIRECT)
+ return lo_direct_read(lo, bio, pos);
+
bio_for_each_segment(bvec, bio, i) {
ret = do_lo_receive(lo, bvec, bsize, pos);
if (ret < 0)
@@ -784,7 +911,11 @@ 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 (odirect) {
+ if (!aops->direct_IO)
+ goto out_putf;
+ lo_flags |= LO_FLAGS_ODIRECT;
+ } else if (aops->write_begin)
lo_flags |= LO_FLAGS_USE_AOPS;
if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write)
lo_flags |= LO_FLAGS_READ_ONLY;
@@ -831,6 +962,10 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
if (!(lo_flags & LO_FLAGS_READ_ONLY) && file->f_op->fsync)
blk_queue_ordered(lo->lo_queue, QUEUE_ORDERED_DRAIN, NULL);
+ if (odirect) {
+ blk_queue_max_phys_segments(lo->lo_queue, LOOP_MAX_DIRECT_SEGMENTS);
+ blk_queue_max_hw_segments(lo->lo_queue, LOOP_MAX_DIRECT_SEGMENTS);
+ }
set_capacity(lo->lo_disk, size);
bd_set_size(bdev, size << 9);
@@ -1456,6 +1591,8 @@ module_param(max_loop, int, 0);
MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
module_param(max_part, int, 0);
MODULE_PARM_DESC(max_part, "Maximum number of partitions per loop device");
+module_param(odirect, int, 0);
+MODULE_PARM_DESC(odirect, "Use O_DIRECT for IO");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);
diff --git a/include/linux/loop.h b/include/linux/loop.h
index 66c194e..a7433c0 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_ODIRECT = 8,
};
#include <asm/posix_types.h> /* for __kernel_old_dev_t */
--
1.6.4.53.g3f55e
next prev parent reply other threads:[~2009-08-20 10:19 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-08-20 10:17 [PATCH 0/6] Lazy workqueues Jens Axboe
2009-08-20 10:17 ` [PATCH 1/4] direct-io: unify argument passing by adding a dio_args structure Jens Axboe
2009-08-20 10:17 ` [PATCH 1/6] workqueue: replace singlethread/freezable/rt parameters and variables with flags Jens Axboe
2009-08-20 10:17 ` [PATCH 2/4] direct-io: make O_DIRECT IO path be page based Jens Axboe
2009-08-20 10:17 ` [PATCH 2/6] workqueue: add support for lazy workqueues Jens Axboe
2009-08-20 10:17 ` [PATCH 3/6] crypto: use " Jens Axboe
2009-08-20 10:17 ` [PATCH 3/4] direct-io: add a "IO for kernel" flag to kiocb Jens Axboe
2009-08-20 10:17 ` [PATCH 4/6] libata: use lazy workqueues for the pio task Jens Axboe
2009-08-20 10:17 ` Jens Axboe [this message]
2009-08-20 10:17 ` [PATCH 5/6] aio: use lazy workqueues Jens Axboe
2009-08-20 10:17 ` [PATCH 4/4] direct-io: get rid of irq flag saving where it isn't needed Jens Axboe
2009-08-20 10:17 ` [PATCH 6/6] sunrpc: use lazy workqueues Jens Axboe
2009-08-21 0:20 ` [PATCH 2/6] workqueue: add support for " Andrew Morton
2009-08-24 8:06 ` Jens Axboe
2009-08-20 13:19 ` [PATCH 2/4] direct-io: make O_DIRECT IO path be page based Trond Myklebust
2009-08-24 7:58 ` Jens Axboe
2009-08-21 0:12 ` Andrew Morton
2009-08-24 8:00 ` Jens Axboe
2009-08-21 0:03 ` [PATCH 1/4] direct-io: unify argument passing by adding a dio_args structure Andrew Morton
2009-08-24 7:58 ` Jens Axboe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1250763466-24282-9-git-send-email-jens.axboe@oracle.com \
--to=jens.axboe@oracle.com \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=benh@kernel.crashing.org \
--cc=bzolnier@gmail.com \
--cc=htejun@gmail.com \
--cc=jeff@garzik.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®