linux-api.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v8 4/6] block: loop: prepare for supporing direct IO
       [not found] <1438256184-23645-1-git-send-email-ming.lei@canonical.com>
@ 2015-07-30 11:36 ` Ming Lei
       [not found]   ` <1438256184-23645-5-git-send-email-ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
  2015-07-30 11:36 ` [PATCH v8 5/6] block: loop: introduce ioctl command of LOOP_SET_DIRECT_IO Ming Lei
  1 sibling, 1 reply; 6+ messages in thread
From: Ming Lei @ 2015-07-30 11:36 UTC (permalink / raw)
  To: Jens Axboe, linux-kernel, Dave Kleikamp
  Cc: Zach Brown, Christoph Hellwig, Maxim Patlasov, Andrew Morton,
	Alexander Viro, Tejun Heo, Dave Chinner, Ming Lei, linux-api

This patches provides one interface for enabling direct IO
from user space:

	- userspace(such as losetup) can pass 'file' which is
	opened/fcntl as O_DIRECT

Also __loop_update_dio() is introduced to check if direct I/O
can be used on current loop setting.

The last big change is to introduce LO_FLAGS_DIRECT_IO flag
for userspace to know if direct IO is used to access backing
file.

Cc: linux-api@vger.kernel.org
Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 drivers/block/loop.c      | 63 ++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/block/loop.h      |  2 ++
 include/uapi/linux/loop.h |  1 +
 3 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 1875aad..799cc23 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -164,6 +164,47 @@ static loff_t get_loop_size(struct loop_device *lo, struct file *file)
 	return get_size(lo->lo_offset, lo->lo_sizelimit, file);
 }
 
+static void __loop_update_dio(struct loop_device *lo, bool dio)
+{
+	struct file *file = lo->lo_backing_file;
+	struct inode *inode = file->f_mapping->host;
+	bool use_dio;
+	unsigned dio_align = inode->i_sb->s_bdev ?
+		(bdev_io_min(inode->i_sb->s_bdev) - 1) : 0;
+
+	/*
+	 * We support direct I/O only if lo_offset is aligned
+	 * with the min I/O size of backing device.
+	 *
+	 * Request's offset and size will be checked in I/O path.
+	 */
+	if (dio) {
+		if (!dio_align || (lo->lo_offset & dio_align))
+			use_dio = false;
+		else
+			use_dio = true;
+	} else {
+		use_dio = false;
+	}
+
+	/* flush dirty pages before changing direct IO */
+	vfs_fsync(file, 0);
+
+	/*
+	 * The flag of LO_FLAGS_DIRECT_IO is handled similarly with
+	 * LO_FLAGS_READ_ONLY, both are set from kernel, and losetup
+	 * will get updated by ioctl(LOOP_GET_STATUS)
+	 */
+	blk_mq_freeze_queue(lo->lo_queue);
+	lo->use_dio = use_dio;
+	lo->dio_align = dio_align;
+	if (use_dio)
+		lo->lo_flags |= LO_FLAGS_DIRECT_IO;
+	else
+		lo->lo_flags &= ~LO_FLAGS_DIRECT_IO;
+	blk_mq_unfreeze_queue(lo->lo_queue);
+}
+
 static int
 figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
 {
@@ -173,8 +214,12 @@ figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
 
 	if (unlikely((loff_t)x != size))
 		return -EFBIG;
-	if (lo->lo_offset != offset)
+	if (lo->lo_offset != offset) {
 		lo->lo_offset = offset;
+
+		/* update dio if lo_offset is changed*/
+		__loop_update_dio(lo, lo->use_dio);
+	}
 	if (lo->lo_sizelimit != sizelimit)
 		lo->lo_sizelimit = sizelimit;
 	set_capacity(lo->lo_disk, x);
@@ -421,6 +466,11 @@ struct switch_request {
 	struct completion wait;
 };
 
+static inline void loop_update_dio(struct loop_device *lo)
+{
+	__loop_update_dio(lo, io_is_direct(lo->lo_backing_file));
+}
+
 /*
  * Do the actual switch; called from the BIO completion routine
  */
@@ -441,6 +491,7 @@ static void do_loop_switch(struct loop_device *lo, struct switch_request *p)
 		mapping->host->i_bdev->bd_block_size : PAGE_SIZE;
 	lo->old_gfp_mask = mapping_gfp_mask(mapping);
 	mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
+	loop_update_dio(lo);
 }
 
 /*
@@ -627,11 +678,19 @@ static ssize_t loop_attr_partscan_show(struct loop_device *lo, char *buf)
 	return sprintf(buf, "%s\n", partscan ? "1" : "0");
 }
 
+static ssize_t loop_attr_dio_show(struct loop_device *lo, char *buf)
+{
+	int dio = (lo->lo_flags & LO_FLAGS_DIRECT_IO);
+
+	return sprintf(buf, "%s\n", dio ? "1" : "0");
+}
+
 LOOP_ATTR_RO(backing_file);
 LOOP_ATTR_RO(offset);
 LOOP_ATTR_RO(sizelimit);
 LOOP_ATTR_RO(autoclear);
 LOOP_ATTR_RO(partscan);
+LOOP_ATTR_RO(dio);
 
 static struct attribute *loop_attrs[] = {
 	&loop_attr_backing_file.attr,
@@ -639,6 +698,7 @@ static struct attribute *loop_attrs[] = {
 	&loop_attr_sizelimit.attr,
 	&loop_attr_autoclear.attr,
 	&loop_attr_partscan.attr,
+	&loop_attr_dio.attr,
 	NULL,
 };
 
@@ -783,6 +843,7 @@ 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_flush(lo->lo_queue, REQ_FLUSH);
 
+	loop_update_dio(lo);
 	set_capacity(lo->lo_disk, size);
 	bd_set_size(bdev, size << 9);
 	loop_sysfs_init(lo);
diff --git a/drivers/block/loop.h b/drivers/block/loop.h
index b6c7d21..63f8e14 100644
--- a/drivers/block/loop.h
+++ b/drivers/block/loop.h
@@ -58,6 +58,8 @@ struct loop_device {
 	struct mutex		lo_ctl_mutex;
 	struct kthread_worker	worker;
 	struct task_struct	*worker_task;
+	unsigned		dio_align;
+	bool			use_dio;
 
 	struct request_queue	*lo_queue;
 	struct blk_mq_tag_set	tag_set;
diff --git a/include/uapi/linux/loop.h b/include/uapi/linux/loop.h
index e0cecd2..949851c 100644
--- a/include/uapi/linux/loop.h
+++ b/include/uapi/linux/loop.h
@@ -21,6 +21,7 @@ enum {
 	LO_FLAGS_READ_ONLY	= 1,
 	LO_FLAGS_AUTOCLEAR	= 4,
 	LO_FLAGS_PARTSCAN	= 8,
+	LO_FLAGS_DIRECT_IO	= 16,
 };
 
 #include <asm/posix_types.h>	/* for __kernel_old_dev_t */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v8 5/6] block: loop: introduce ioctl command of LOOP_SET_DIRECT_IO
       [not found] <1438256184-23645-1-git-send-email-ming.lei@canonical.com>
  2015-07-30 11:36 ` [PATCH v8 4/6] block: loop: prepare for supporing direct IO Ming Lei
@ 2015-07-30 11:36 ` Ming Lei
  1 sibling, 0 replies; 6+ messages in thread
From: Ming Lei @ 2015-07-30 11:36 UTC (permalink / raw)
  To: Jens Axboe, linux-kernel, Dave Kleikamp
  Cc: Zach Brown, Christoph Hellwig, Maxim Patlasov, Andrew Morton,
	Alexander Viro, Tejun Heo, Dave Chinner, Ming Lei, linux-api

If loop block is mounted via 'mount -o loop', it isn't easy
to pass file descriptor opened as O_DIRECT, so this patch
introduces a new command to support direct IO for this case.

Cc: linux-api@vger.kernel.org
Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 drivers/block/loop.c      | 19 +++++++++++++++++++
 include/uapi/linux/loop.h |  1 +
 2 files changed, 20 insertions(+)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 799cc23..133e4c7 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1212,6 +1212,20 @@ static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
 	return figure_loop_size(lo, lo->lo_offset, lo->lo_sizelimit);
 }
 
+static int loop_set_dio(struct loop_device *lo, unsigned long arg)
+{
+	int error = -ENXIO;
+	if (lo->lo_state != Lo_bound)
+		goto out;
+
+	__loop_update_dio(lo, !!arg);
+	if (lo->use_dio == !!arg)
+		return 0;
+	error = -EINVAL;
+ out:
+	return error;
+}
+
 static int lo_ioctl(struct block_device *bdev, fmode_t mode,
 	unsigned int cmd, unsigned long arg)
 {
@@ -1255,6 +1269,11 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
 		if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
 			err = loop_set_capacity(lo, bdev);
 		break;
+	case LOOP_SET_DIRECT_IO:
+		err = -EPERM;
+		if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
+			err = loop_set_dio(lo, arg);
+		break;
 	default:
 		err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
 	}
diff --git a/include/uapi/linux/loop.h b/include/uapi/linux/loop.h
index 949851c..c8125ec 100644
--- a/include/uapi/linux/loop.h
+++ b/include/uapi/linux/loop.h
@@ -87,6 +87,7 @@ struct loop_info64 {
 #define LOOP_GET_STATUS64	0x4C05
 #define LOOP_CHANGE_FD		0x4C06
 #define LOOP_SET_CAPACITY	0x4C07
+#define LOOP_SET_DIRECT_IO	0x4C08
 
 /* /dev/loop-control interface */
 #define LOOP_CTL_ADD		0x4C80
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v8 4/6] block: loop: prepare for supporing direct IO
       [not found]   ` <1438256184-23645-5-git-send-email-ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
@ 2015-07-30 15:09     ` Christoph Hellwig
  2015-07-30 15:21       ` Ming Lei
  2015-07-30 15:30     ` Dave Kleikamp
  1 sibling, 1 reply; 6+ messages in thread
From: Christoph Hellwig @ 2015-07-30 15:09 UTC (permalink / raw)
  To: Ming Lei
  Cc: Jens Axboe, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Dave Kleikamp,
	Zach Brown, Christoph Hellwig, Maxim Patlasov, Andrew Morton,
	Alexander Viro, Tejun Heo, Dave Chinner,
	linux-api-u79uwXL29TY76Z2rM5mHXA

On Thu, Jul 30, 2015 at 07:36:22AM -0400, Ming Lei wrote:
> This patches provides one interface for enabling direct IO
> from user space:
> 
> 	- userspace(such as losetup) can pass 'file' which is
> 	opened/fcntl as O_DIRECT
> 
> Also __loop_update_dio() is introduced to check if direct I/O
> can be used on current loop setting.
> 
> The last big change is to introduce LO_FLAGS_DIRECT_IO flag
> for userspace to know if direct IO is used to access backing
> file.

Maybe i'm missing something because I was too busy to follow the
current discussion, but this still doesn't check that the loop
device sector size is aligned to the sector size of the underlying
filesystem.

E.g. with this you could create a loop device with a 512 byte
sector size on a filesystem with 4k sector size, and it would attempt
to use direct I/O and fail.

> +	unsigned dio_align = inode->i_sb->s_bdev ?
> +		(bdev_io_min(inode->i_sb->s_bdev) - 1) : 0;
> +
> +	/*
> +	 * We support direct I/O only if lo_offset is aligned
> +	 * with the min I/O size of backing device.
> +	 *
> +	 * Request's offset and size will be checked in I/O path.
> +	 */
> +	if (dio) {
> +		if (!dio_align || (lo->lo_offset & dio_align))
> +			use_dio = false;

Also this means you'll never use direct I/O on network filesystems,
which really would benefit from it.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v8 4/6] block: loop: prepare for supporing direct IO
  2015-07-30 15:09     ` Christoph Hellwig
@ 2015-07-30 15:21       ` Ming Lei
  0 siblings, 0 replies; 6+ messages in thread
From: Ming Lei @ 2015-07-30 15:21 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Jens Axboe, Linux Kernel Mailing List, Dave Kleikamp, Zach Brown,
	Maxim Patlasov, Andrew Morton, Alexander Viro, Tejun Heo,
	Dave Chinner, linux-api

On Thu, Jul 30, 2015 at 11:09 AM, Christoph Hellwig <hch@infradead.org> wrote:
> On Thu, Jul 30, 2015 at 07:36:22AM -0400, Ming Lei wrote:
>> This patches provides one interface for enabling direct IO
>> from user space:
>>
>>       - userspace(such as losetup) can pass 'file' which is
>>       opened/fcntl as O_DIRECT
>>
>> Also __loop_update_dio() is introduced to check if direct I/O
>> can be used on current loop setting.
>>
>> The last big change is to introduce LO_FLAGS_DIRECT_IO flag
>> for userspace to know if direct IO is used to access backing
>> file.
>
> Maybe i'm missing something because I was too busy to follow the
> current discussion, but this still doesn't check that the loop
> device sector size is aligned to the sector size of the underlying
> filesystem.
>
> E.g. with this you could create a loop device with a 512 byte
> sector size on a filesystem with 4k sector size, and it would attempt
> to use direct I/O and fail.

The I/O size & offset has to be checked in I/O path, see patch 6 please,
could you comment on that patch?

>
>> +     unsigned dio_align = inode->i_sb->s_bdev ?
>> +             (bdev_io_min(inode->i_sb->s_bdev) - 1) : 0;
>> +
>> +     /*
>> +      * We support direct I/O only if lo_offset is aligned
>> +      * with the min I/O size of backing device.
>> +      *
>> +      * Request's offset and size will be checked in I/O path.
>> +      */
>> +     if (dio) {
>> +             if (!dio_align || (lo->lo_offset & dio_align))
>> +                     use_dio = false;
>
> Also this means you'll never use direct I/O on network filesystems,
> which really would benefit from it.

OK, that can be done by removing !dio_align in above check.

Thanks,

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v8 4/6] block: loop: prepare for supporing direct IO
       [not found]   ` <1438256184-23645-5-git-send-email-ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
  2015-07-30 15:09     ` Christoph Hellwig
@ 2015-07-30 15:30     ` Dave Kleikamp
       [not found]       ` <55BA432F.3050603-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
  1 sibling, 1 reply; 6+ messages in thread
From: Dave Kleikamp @ 2015-07-30 15:30 UTC (permalink / raw)
  To: Ming Lei, Jens Axboe, linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Zach Brown, Christoph Hellwig, Maxim Patlasov, Andrew Morton,
	Alexander Viro, Tejun Heo, Dave Chinner,
	linux-api-u79uwXL29TY76Z2rM5mHXA

On 07/30/2015 06:36 AM, Ming Lei wrote:
> This patches provides one interface for enabling direct IO
> from user space:
> 
> 	- userspace(such as losetup) can pass 'file' which is
> 	opened/fcntl as O_DIRECT
> 
> Also __loop_update_dio() is introduced to check if direct I/O
> can be used on current loop setting.
> 
> The last big change is to introduce LO_FLAGS_DIRECT_IO flag
> for userspace to know if direct IO is used to access backing
> file.

lo->use_dio and LO_FLAGS_DIRECT_IO seem redundant. Wouldn't it be
simpler to use one or the other?

> 
> Cc: linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Signed-off-by: Ming Lei <ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
> ---
>  drivers/block/loop.c      | 63 ++++++++++++++++++++++++++++++++++++++++++++++-
>  drivers/block/loop.h      |  2 ++
>  include/uapi/linux/loop.h |  1 +
>  3 files changed, 65 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/block/loop.c b/drivers/block/loop.c
> index 1875aad..799cc23 100644
> --- a/drivers/block/loop.c
> +++ b/drivers/block/loop.c
> @@ -164,6 +164,47 @@ static loff_t get_loop_size(struct loop_device *lo, struct file *file)
>  	return get_size(lo->lo_offset, lo->lo_sizelimit, file);
>  }
>  
> +static void __loop_update_dio(struct loop_device *lo, bool dio)
> +{
> +	struct file *file = lo->lo_backing_file;
> +	struct inode *inode = file->f_mapping->host;
> +	bool use_dio;
> +	unsigned dio_align = inode->i_sb->s_bdev ?
> +		(bdev_io_min(inode->i_sb->s_bdev) - 1) : 0;
> +
> +	/*
> +	 * We support direct I/O only if lo_offset is aligned
> +	 * with the min I/O size of backing device.
> +	 *
> +	 * Request's offset and size will be checked in I/O path.
> +	 */
> +	if (dio) {
> +		if (!dio_align || (lo->lo_offset & dio_align))
> +			use_dio = false;
> +		else
> +			use_dio = true;
> +	} else {
> +		use_dio = false;
> +	}
> +
> +	/* flush dirty pages before changing direct IO */
> +	vfs_fsync(file, 0);
> +
> +	/*
> +	 * The flag of LO_FLAGS_DIRECT_IO is handled similarly with
> +	 * LO_FLAGS_READ_ONLY, both are set from kernel, and losetup
> +	 * will get updated by ioctl(LOOP_GET_STATUS)
> +	 */
> +	blk_mq_freeze_queue(lo->lo_queue);
> +	lo->use_dio = use_dio;
> +	lo->dio_align = dio_align;
> +	if (use_dio)
> +		lo->lo_flags |= LO_FLAGS_DIRECT_IO;
> +	else
> +		lo->lo_flags &= ~LO_FLAGS_DIRECT_IO;
> +	blk_mq_unfreeze_queue(lo->lo_queue);
> +}
> +
>  static int
>  figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
>  {
> @@ -173,8 +214,12 @@ figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
>  
>  	if (unlikely((loff_t)x != size))
>  		return -EFBIG;
> -	if (lo->lo_offset != offset)
> +	if (lo->lo_offset != offset) {
>  		lo->lo_offset = offset;
> +
> +		/* update dio if lo_offset is changed*/
> +		__loop_update_dio(lo, lo->use_dio);
> +	}
>  	if (lo->lo_sizelimit != sizelimit)
>  		lo->lo_sizelimit = sizelimit;
>  	set_capacity(lo->lo_disk, x);
> @@ -421,6 +466,11 @@ struct switch_request {
>  	struct completion wait;
>  };
>  
> +static inline void loop_update_dio(struct loop_device *lo)
> +{
> +	__loop_update_dio(lo, io_is_direct(lo->lo_backing_file));
> +}
> +
>  /*
>   * Do the actual switch; called from the BIO completion routine
>   */
> @@ -441,6 +491,7 @@ static void do_loop_switch(struct loop_device *lo, struct switch_request *p)
>  		mapping->host->i_bdev->bd_block_size : PAGE_SIZE;
>  	lo->old_gfp_mask = mapping_gfp_mask(mapping);
>  	mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
> +	loop_update_dio(lo);
>  }
>  
>  /*
> @@ -627,11 +678,19 @@ static ssize_t loop_attr_partscan_show(struct loop_device *lo, char *buf)
>  	return sprintf(buf, "%s\n", partscan ? "1" : "0");
>  }
>  
> +static ssize_t loop_attr_dio_show(struct loop_device *lo, char *buf)
> +{
> +	int dio = (lo->lo_flags & LO_FLAGS_DIRECT_IO);
> +
> +	return sprintf(buf, "%s\n", dio ? "1" : "0");
> +}
> +
>  LOOP_ATTR_RO(backing_file);
>  LOOP_ATTR_RO(offset);
>  LOOP_ATTR_RO(sizelimit);
>  LOOP_ATTR_RO(autoclear);
>  LOOP_ATTR_RO(partscan);
> +LOOP_ATTR_RO(dio);
>  
>  static struct attribute *loop_attrs[] = {
>  	&loop_attr_backing_file.attr,
> @@ -639,6 +698,7 @@ static struct attribute *loop_attrs[] = {
>  	&loop_attr_sizelimit.attr,
>  	&loop_attr_autoclear.attr,
>  	&loop_attr_partscan.attr,
> +	&loop_attr_dio.attr,
>  	NULL,
>  };
>  
> @@ -783,6 +843,7 @@ 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_flush(lo->lo_queue, REQ_FLUSH);
>  
> +	loop_update_dio(lo);
>  	set_capacity(lo->lo_disk, size);
>  	bd_set_size(bdev, size << 9);
>  	loop_sysfs_init(lo);
> diff --git a/drivers/block/loop.h b/drivers/block/loop.h
> index b6c7d21..63f8e14 100644
> --- a/drivers/block/loop.h
> +++ b/drivers/block/loop.h
> @@ -58,6 +58,8 @@ struct loop_device {
>  	struct mutex		lo_ctl_mutex;
>  	struct kthread_worker	worker;
>  	struct task_struct	*worker_task;
> +	unsigned		dio_align;
> +	bool			use_dio;
>  
>  	struct request_queue	*lo_queue;
>  	struct blk_mq_tag_set	tag_set;
> diff --git a/include/uapi/linux/loop.h b/include/uapi/linux/loop.h
> index e0cecd2..949851c 100644
> --- a/include/uapi/linux/loop.h
> +++ b/include/uapi/linux/loop.h
> @@ -21,6 +21,7 @@ enum {
>  	LO_FLAGS_READ_ONLY	= 1,
>  	LO_FLAGS_AUTOCLEAR	= 4,
>  	LO_FLAGS_PARTSCAN	= 8,
> +	LO_FLAGS_DIRECT_IO	= 16,
>  };
>  
>  #include <asm/posix_types.h>	/* for __kernel_old_dev_t */
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v8 4/6] block: loop: prepare for supporing direct IO
       [not found]       ` <55BA432F.3050603-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
@ 2015-07-30 15:45         ` Ming Lei
  0 siblings, 0 replies; 6+ messages in thread
From: Ming Lei @ 2015-07-30 15:45 UTC (permalink / raw)
  To: Dave Kleikamp
  Cc: Jens Axboe, Linux Kernel Mailing List, Zach Brown,
	Christoph Hellwig, Maxim Patlasov, Andrew Morton, Alexander Viro,
	Tejun Heo, Dave Chinner, linux-api-u79uwXL29TY76Z2rM5mHXA

On Thu, Jul 30, 2015 at 11:30 AM, Dave Kleikamp
<dave.kleikamp-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org> wrote:
> On 07/30/2015 06:36 AM, Ming Lei wrote:
>> This patches provides one interface for enabling direct IO
>> from user space:
>>
>>       - userspace(such as losetup) can pass 'file' which is
>>       opened/fcntl as O_DIRECT
>>
>> Also __loop_update_dio() is introduced to check if direct I/O
>> can be used on current loop setting.
>>
>> The last big change is to introduce LO_FLAGS_DIRECT_IO flag
>> for userspace to know if direct IO is used to access backing
>> file.
>
> lo->use_dio and LO_FLAGS_DIRECT_IO seem redundant. Wouldn't it be
> simpler to use one or the other?

losetup is a stateless utility, which means it need to retrieve the dio status
via the flag of LO_FLAGS_DIRECT_IO, which is one API change.

>
>>
>> Cc: linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> Signed-off-by: Ming Lei <ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
>> ---
>>  drivers/block/loop.c      | 63 ++++++++++++++++++++++++++++++++++++++++++++++-
>>  drivers/block/loop.h      |  2 ++
>>  include/uapi/linux/loop.h |  1 +
>>  3 files changed, 65 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/block/loop.c b/drivers/block/loop.c
>> index 1875aad..799cc23 100644
>> --- a/drivers/block/loop.c
>> +++ b/drivers/block/loop.c
>> @@ -164,6 +164,47 @@ static loff_t get_loop_size(struct loop_device *lo, struct file *file)
>>       return get_size(lo->lo_offset, lo->lo_sizelimit, file);
>>  }
>>
>> +static void __loop_update_dio(struct loop_device *lo, bool dio)
>> +{
>> +     struct file *file = lo->lo_backing_file;
>> +     struct inode *inode = file->f_mapping->host;
>> +     bool use_dio;
>> +     unsigned dio_align = inode->i_sb->s_bdev ?
>> +             (bdev_io_min(inode->i_sb->s_bdev) - 1) : 0;
>> +
>> +     /*
>> +      * We support direct I/O only if lo_offset is aligned
>> +      * with the min I/O size of backing device.
>> +      *
>> +      * Request's offset and size will be checked in I/O path.
>> +      */
>> +     if (dio) {
>> +             if (!dio_align || (lo->lo_offset & dio_align))
>> +                     use_dio = false;
>> +             else
>> +                     use_dio = true;
>> +     } else {
>> +             use_dio = false;
>> +     }
>> +
>> +     /* flush dirty pages before changing direct IO */
>> +     vfs_fsync(file, 0);
>> +
>> +     /*
>> +      * The flag of LO_FLAGS_DIRECT_IO is handled similarly with
>> +      * LO_FLAGS_READ_ONLY, both are set from kernel, and losetup
>> +      * will get updated by ioctl(LOOP_GET_STATUS)
>> +      */
>> +     blk_mq_freeze_queue(lo->lo_queue);
>> +     lo->use_dio = use_dio;
>> +     lo->dio_align = dio_align;
>> +     if (use_dio)
>> +             lo->lo_flags |= LO_FLAGS_DIRECT_IO;
>> +     else
>> +             lo->lo_flags &= ~LO_FLAGS_DIRECT_IO;
>> +     blk_mq_unfreeze_queue(lo->lo_queue);
>> +}
>> +
>>  static int
>>  figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
>>  {
>> @@ -173,8 +214,12 @@ figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
>>
>>       if (unlikely((loff_t)x != size))
>>               return -EFBIG;
>> -     if (lo->lo_offset != offset)
>> +     if (lo->lo_offset != offset) {
>>               lo->lo_offset = offset;
>> +
>> +             /* update dio if lo_offset is changed*/
>> +             __loop_update_dio(lo, lo->use_dio);
>> +     }
>>       if (lo->lo_sizelimit != sizelimit)
>>               lo->lo_sizelimit = sizelimit;
>>       set_capacity(lo->lo_disk, x);
>> @@ -421,6 +466,11 @@ struct switch_request {
>>       struct completion wait;
>>  };
>>
>> +static inline void loop_update_dio(struct loop_device *lo)
>> +{
>> +     __loop_update_dio(lo, io_is_direct(lo->lo_backing_file));
>> +}
>> +
>>  /*
>>   * Do the actual switch; called from the BIO completion routine
>>   */
>> @@ -441,6 +491,7 @@ static void do_loop_switch(struct loop_device *lo, struct switch_request *p)
>>               mapping->host->i_bdev->bd_block_size : PAGE_SIZE;
>>       lo->old_gfp_mask = mapping_gfp_mask(mapping);
>>       mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
>> +     loop_update_dio(lo);
>>  }
>>
>>  /*
>> @@ -627,11 +678,19 @@ static ssize_t loop_attr_partscan_show(struct loop_device *lo, char *buf)
>>       return sprintf(buf, "%s\n", partscan ? "1" : "0");
>>  }
>>
>> +static ssize_t loop_attr_dio_show(struct loop_device *lo, char *buf)
>> +{
>> +     int dio = (lo->lo_flags & LO_FLAGS_DIRECT_IO);
>> +
>> +     return sprintf(buf, "%s\n", dio ? "1" : "0");
>> +}
>> +
>>  LOOP_ATTR_RO(backing_file);
>>  LOOP_ATTR_RO(offset);
>>  LOOP_ATTR_RO(sizelimit);
>>  LOOP_ATTR_RO(autoclear);
>>  LOOP_ATTR_RO(partscan);
>> +LOOP_ATTR_RO(dio);
>>
>>  static struct attribute *loop_attrs[] = {
>>       &loop_attr_backing_file.attr,
>> @@ -639,6 +698,7 @@ static struct attribute *loop_attrs[] = {
>>       &loop_attr_sizelimit.attr,
>>       &loop_attr_autoclear.attr,
>>       &loop_attr_partscan.attr,
>> +     &loop_attr_dio.attr,
>>       NULL,
>>  };
>>
>> @@ -783,6 +843,7 @@ 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_flush(lo->lo_queue, REQ_FLUSH);
>>
>> +     loop_update_dio(lo);
>>       set_capacity(lo->lo_disk, size);
>>       bd_set_size(bdev, size << 9);
>>       loop_sysfs_init(lo);
>> diff --git a/drivers/block/loop.h b/drivers/block/loop.h
>> index b6c7d21..63f8e14 100644
>> --- a/drivers/block/loop.h
>> +++ b/drivers/block/loop.h
>> @@ -58,6 +58,8 @@ struct loop_device {
>>       struct mutex            lo_ctl_mutex;
>>       struct kthread_worker   worker;
>>       struct task_struct      *worker_task;
>> +     unsigned                dio_align;
>> +     bool                    use_dio;
>>
>>       struct request_queue    *lo_queue;
>>       struct blk_mq_tag_set   tag_set;
>> diff --git a/include/uapi/linux/loop.h b/include/uapi/linux/loop.h
>> index e0cecd2..949851c 100644
>> --- a/include/uapi/linux/loop.h
>> +++ b/include/uapi/linux/loop.h
>> @@ -21,6 +21,7 @@ enum {
>>       LO_FLAGS_READ_ONLY      = 1,
>>       LO_FLAGS_AUTOCLEAR      = 4,
>>       LO_FLAGS_PARTSCAN       = 8,
>> +     LO_FLAGS_DIRECT_IO      = 16,
>>  };
>>
>>  #include <asm/posix_types.h> /* for __kernel_old_dev_t */
>>

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-07-30 15:45 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <1438256184-23645-1-git-send-email-ming.lei@canonical.com>
2015-07-30 11:36 ` [PATCH v8 4/6] block: loop: prepare for supporing direct IO Ming Lei
     [not found]   ` <1438256184-23645-5-git-send-email-ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
2015-07-30 15:09     ` Christoph Hellwig
2015-07-30 15:21       ` Ming Lei
2015-07-30 15:30     ` Dave Kleikamp
     [not found]       ` <55BA432F.3050603-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
2015-07-30 15:45         ` Ming Lei
2015-07-30 11:36 ` [PATCH v8 5/6] block: loop: introduce ioctl command of LOOP_SET_DIRECT_IO Ming Lei

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).