Re: [PATCH v4 10/10] loop: Add LOOP_CONFIGURE ioctl

2020-05-13 Thread Martijn Coenen
On Wed, May 13, 2020 at 12:22 PM Christoph Hellwig  wrote:
>
> On Wed, May 13, 2020 at 09:07:43AM +0200, Martijn Coenen wrote:
> > On Wed, May 13, 2020 at 4:30 AM Jens Axboe  wrote:
> > > > Looks acceptable to me, but I'm getting a failure applying it to
> > > > for-5.8/drivers on this patch:
> > > >
> > > > Applying: loop: Refactor loop_set_status() size calculation
> > > >
> > > > So you'll probably want to respin on the right branch.
> >
> > This series depends on a separate bugfix I sent to LKML earlier - see
> > https://lkml.org/lkml/2020/3/31/755 . I mentioned it in [00/10] of
> > this series, but perhaps I should have just included that patch.
> >
> > I just verified that patch + this series still applies cleanly on your
> > for-5.8/drivers tree, but if you prefer I send a v5 with that patch
> > going first let me know.
>
> You probably want to resend with the fix includes as the first patch.
> And drop the truncation check now that we figured out that we don't
> actually need it.

Just sent v5, thanks!

Martijn


Re: [PATCH v4 10/10] loop: Add LOOP_CONFIGURE ioctl

2020-05-13 Thread Christoph Hellwig
On Wed, May 13, 2020 at 09:07:43AM +0200, Martijn Coenen wrote:
> On Wed, May 13, 2020 at 4:30 AM Jens Axboe  wrote:
> > > Looks acceptable to me, but I'm getting a failure applying it to
> > > for-5.8/drivers on this patch:
> > >
> > > Applying: loop: Refactor loop_set_status() size calculation
> > >
> > > So you'll probably want to respin on the right branch.
> 
> This series depends on a separate bugfix I sent to LKML earlier - see
> https://lkml.org/lkml/2020/3/31/755 . I mentioned it in [00/10] of
> this series, but perhaps I should have just included that patch.
> 
> I just verified that patch + this series still applies cleanly on your
> for-5.8/drivers tree, but if you prefer I send a v5 with that patch
> going first let me know.

You probably want to resend with the fix includes as the first patch.
And drop the truncation check now that we figured out that we don't
actually need it.


Re: [PATCH v4 10/10] loop: Add LOOP_CONFIGURE ioctl

2020-05-13 Thread Martijn Coenen
On Wed, May 13, 2020 at 4:30 AM Jens Axboe  wrote:
> > Looks acceptable to me, but I'm getting a failure applying it to
> > for-5.8/drivers on this patch:
> >
> > Applying: loop: Refactor loop_set_status() size calculation
> >
> > So you'll probably want to respin on the right branch.

This series depends on a separate bugfix I sent to LKML earlier - see
https://lkml.org/lkml/2020/3/31/755 . I mentioned it in [00/10] of
this series, but perhaps I should have just included that patch.

I just verified that patch + this series still applies cleanly on your
for-5.8/drivers tree, but if you prefer I send a v5 with that patch
going first let me know.

Thanks,
Martijn



>
> Then you can also drop patch #1.
>
> --
> Jens Axboe
>


Re: [PATCH v4 10/10] loop: Add LOOP_CONFIGURE ioctl

2020-05-12 Thread Jens Axboe
On 5/12/20 8:29 PM, Jens Axboe wrote:
> On 5/12/20 12:46 AM, Martijn Coenen wrote:
>> Hi Jens,
>>
>> What do you think of this series?
> 
> Looks acceptable to me, but I'm getting a failure applying it to
> for-5.8/drivers on this patch:
> 
> Applying: loop: Refactor loop_set_status() size calculation
> 
> So you'll probably want to respin on the right branch.

Then you can also drop patch #1.

-- 
Jens Axboe



Re: [PATCH v4 10/10] loop: Add LOOP_CONFIGURE ioctl

2020-05-12 Thread Jens Axboe
On 5/12/20 12:46 AM, Martijn Coenen wrote:
> Hi Jens,
> 
> What do you think of this series?

Looks acceptable to me, but I'm getting a failure applying it to
for-5.8/drivers on this patch:

Applying: loop: Refactor loop_set_status() size calculation

So you'll probably want to respin on the right branch.

-- 
Jens Axboe



Re: [PATCH v4 10/10] loop: Add LOOP_CONFIGURE ioctl

2020-05-12 Thread Martijn Coenen
Hi Jens,

What do you think of this series?

Thanks,
Martijn

On Wed, Apr 29, 2020 at 4:03 PM Martijn Coenen  wrote:
>
> This allows userspace to completely setup a loop device with a single
> ioctl, removing the in-between state where the device can be partially
> configured - eg the loop device has a backing file associated with it,
> but is reading from the wrong offset.
>
> Besides removing the intermediate state, another big benefit of this
> ioctl is that LOOP_SET_STATUS can be slow; the main reason for this
> slowness is that LOOP_SET_STATUS(64) calls blk_mq_freeze_queue() to
> freeze the associated queue; this requires waiting for RCU
> synchronization, which I've measured can take about 15-20ms on this
> device on average.
>
> In addition to doing what LOOP_SET_STATUS can do, LOOP_CONFIGURE can
> also be used to:
> - Set the correct block size immediately by setting
>   loop_config.block_size (avoids LOOP_SET_BLOCK_SIZE)
> - Explicitly request direct I/O mode by setting LO_FLAGS_DIRECT_IO
>   in loop_config.info.lo_flags (avoids LOOP_SET_DIRECT_IO)
> - Explicitly request read-only mode by setting LO_FLAGS_READ_ONLY
>   in loop_config.info.lo_flags
>
> Here's setting up ~70 regular loop devices with an offset on an x86
> Android device, using LOOP_SET_FD and LOOP_SET_STATUS:
>
> vsoc_x86:/system/apex # time for i in `seq 30 100`;
> do losetup -r -o 4096 /dev/block/loop$i com.android.adbd.apex; done
> 0m03.40s real 0m00.02s user 0m00.03s system
>
> Here's configuring ~70 devices in the same way, but using a modified
> losetup that uses the new LOOP_CONFIGURE ioctl:
>
> vsoc_x86:/system/apex # time for i in `seq 30 100`;
> do losetup -r -o 4096 /dev/block/loop$i com.android.adbd.apex; done
> 0m01.94s real 0m00.01s user 0m00.01s system
>
> Signed-off-by: Martijn Coenen 
> ---
>  drivers/block/loop.c  | 107 +++---
>  include/uapi/linux/loop.h |  21 
>  2 files changed, 99 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/block/loop.c b/drivers/block/loop.c
> index cfbdd99fdb1a..a353ce55fd18 100644
> --- a/drivers/block/loop.c
> +++ b/drivers/block/loop.c
> @@ -241,6 +241,19 @@ loop_validate_size(loff_t size)
> return 0;
>  }
>
> +/**
> + * loop_validate_block_size() - validates the passed in block size
> + * @bsize: size to validate
> + */
> +static int
> +loop_validate_block_size(unsigned short bsize)
> +{
> +   if (bsize < 512 || bsize > PAGE_SIZE || !is_power_of_2(bsize))
> +   return -EINVAL;
> +
> +   return 0;
> +}
> +
>  /**
>   * loop_set_size() - sets device size and notifies userspace
>   * @lo: struct loop_device to set the size for
> @@ -1063,23 +1076,24 @@ loop_set_status_from_info(struct loop_device *lo,
> return 0;
>  }
>
> -static int loop_set_fd(struct loop_device *lo, fmode_t mode,
> -  struct block_device *bdev, unsigned int arg)
> +static int loop_configure(struct loop_device *lo, fmode_t mode,
> + struct block_device *bdev,
> + const struct loop_config *config)
>  {
> struct file *file;
> struct inode*inode;
> struct address_space *mapping;
> struct block_device *claimed_bdev = NULL;
> -   int lo_flags = 0;
> int error;
> loff_t  size;
> boolpartscan;
> +   unsigned short  bsize;
>
> /* This is safe, since we have a reference from open(). */
> __module_get(THIS_MODULE);
>
> error = -EBADF;
> -   file = fget(arg);
> +   file = fget(config->fd);
> if (!file)
> goto out;
>
> @@ -1088,7 +1102,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t 
> mode,
>  * here to avoid changing device under exclusive owner.
>  */
> if (!(mode & FMODE_EXCL)) {
> -   claimed_bdev = bd_start_claiming(bdev, loop_set_fd);
> +   claimed_bdev = bd_start_claiming(bdev, loop_configure);
> if (IS_ERR(claimed_bdev)) {
> error = PTR_ERR(claimed_bdev);
> goto out_putf;
> @@ -1110,44 +1124,58 @@ static int loop_set_fd(struct loop_device *lo, 
> fmode_t mode,
> mapping = file->f_mapping;
> inode = mapping->host;
>
> -   if (!(file->f_mode & FMODE_WRITE) || !(mode & FMODE_WRITE) ||
> -   !file->f_op->write_iter)
> -   lo_flags |= LO_FLAGS_READ_ONLY;
> -
> size = get_loop_size(lo, file);
> error = loop_validate_size(size);
> if (error)
> goto out_unlock;
> +
> +   if ((config->info.lo_flags & ~LOOP_CONFIGURE_SETTABLE_FLAGS) != 0) {
> +   error = -EINVAL;
> +   goto out_unlock;
> +   }
> +
> +   if (config->block_size) {
> +   error = loop_validate_block_size(config->block_size);
> +   if (error)
> +

Re: [PATCH v4 10/10] loop: Add LOOP_CONFIGURE ioctl

2020-05-06 Thread Martijn Coenen
On Wed, May 6, 2020 at 11:44 AM Michael Kerrisk (man-pages) >
> Can we have also a patch for the loop.4 manual page please?

Ack, will do when the series lands.

Best,
Martijn

>
> Thanks,
>
> Michael
>
>
> --
> Michael Kerrisk
> Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
> Linux/UNIX System Programming Training: http://man7.org/training/


Re: [PATCH v4 10/10] loop: Add LOOP_CONFIGURE ioctl

2020-05-06 Thread Martijn Coenen
On Wed, May 6, 2020 at 8:09 AM Christoph Hellwig  wrote:
>
> Thanks, this looks very nice!

Thanks! And thanks for all the feedback, it has made this series a lot cleaner.

>
> Reviewed-by: Christoph Hellwig 
>
> Are you also going to submit a patch to util-linux to use the new
> ioctl?

Yeah, I'm happy to - will do it as soon as the series lands.

Best,
Martijn


Re: [PATCH v4 10/10] loop: Add LOOP_CONFIGURE ioctl

2020-05-06 Thread Michael Kerrisk (man-pages)
Hi Martijn,

On 4/29/20 4:03 PM, Martijn Coenen wrote:
> This allows userspace to completely setup a loop device with a single
> ioctl, removing the in-between state where the device can be partially
> configured - eg the loop device has a backing file associated with it,
> but is reading from the wrong offset.
> 
> Besides removing the intermediate state, another big benefit of this
> ioctl is that LOOP_SET_STATUS can be slow; the main reason for this
> slowness is that LOOP_SET_STATUS(64) calls blk_mq_freeze_queue() to
> freeze the associated queue; this requires waiting for RCU
> synchronization, which I've measured can take about 15-20ms on this
> device on average.
> 
> In addition to doing what LOOP_SET_STATUS can do, LOOP_CONFIGURE can
> also be used to:
> - Set the correct block size immediately by setting
>   loop_config.block_size (avoids LOOP_SET_BLOCK_SIZE)
> - Explicitly request direct I/O mode by setting LO_FLAGS_DIRECT_IO
>   in loop_config.info.lo_flags (avoids LOOP_SET_DIRECT_IO)
> - Explicitly request read-only mode by setting LO_FLAGS_READ_ONLY
>   in loop_config.info.lo_flags
> 
> Here's setting up ~70 regular loop devices with an offset on an x86
> Android device, using LOOP_SET_FD and LOOP_SET_STATUS:
> 
> vsoc_x86:/system/apex # time for i in `seq 30 100`;
> do losetup -r -o 4096 /dev/block/loop$i com.android.adbd.apex; done
> 0m03.40s real 0m00.02s user 0m00.03s system
> 
> Here's configuring ~70 devices in the same way, but using a modified
> losetup that uses the new LOOP_CONFIGURE ioctl:
> 
> vsoc_x86:/system/apex # time for i in `seq 30 100`;
> do losetup -r -o 4096 /dev/block/loop$i com.android.adbd.apex; done
> 0m01.94s real 0m00.01s user 0m00.01s system
> 
> Signed-off-by: Martijn Coenen 


Can we have also a patch for the loop.4 manual page please?

Thanks,

Michael


-- 
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/


Re: [PATCH v4 10/10] loop: Add LOOP_CONFIGURE ioctl

2020-05-06 Thread Christoph Hellwig
Thanks, this looks very nice!

Reviewed-by: Christoph Hellwig 

Are you also going to submit a patch to util-linux to use the new
ioctl?


[PATCH v4 10/10] loop: Add LOOP_CONFIGURE ioctl

2020-04-29 Thread Martijn Coenen
This allows userspace to completely setup a loop device with a single
ioctl, removing the in-between state where the device can be partially
configured - eg the loop device has a backing file associated with it,
but is reading from the wrong offset.

Besides removing the intermediate state, another big benefit of this
ioctl is that LOOP_SET_STATUS can be slow; the main reason for this
slowness is that LOOP_SET_STATUS(64) calls blk_mq_freeze_queue() to
freeze the associated queue; this requires waiting for RCU
synchronization, which I've measured can take about 15-20ms on this
device on average.

In addition to doing what LOOP_SET_STATUS can do, LOOP_CONFIGURE can
also be used to:
- Set the correct block size immediately by setting
  loop_config.block_size (avoids LOOP_SET_BLOCK_SIZE)
- Explicitly request direct I/O mode by setting LO_FLAGS_DIRECT_IO
  in loop_config.info.lo_flags (avoids LOOP_SET_DIRECT_IO)
- Explicitly request read-only mode by setting LO_FLAGS_READ_ONLY
  in loop_config.info.lo_flags

Here's setting up ~70 regular loop devices with an offset on an x86
Android device, using LOOP_SET_FD and LOOP_SET_STATUS:

vsoc_x86:/system/apex # time for i in `seq 30 100`;
do losetup -r -o 4096 /dev/block/loop$i com.android.adbd.apex; done
0m03.40s real 0m00.02s user 0m00.03s system

Here's configuring ~70 devices in the same way, but using a modified
losetup that uses the new LOOP_CONFIGURE ioctl:

vsoc_x86:/system/apex # time for i in `seq 30 100`;
do losetup -r -o 4096 /dev/block/loop$i com.android.adbd.apex; done
0m01.94s real 0m00.01s user 0m00.01s system

Signed-off-by: Martijn Coenen 
---
 drivers/block/loop.c  | 107 +++---
 include/uapi/linux/loop.h |  21 
 2 files changed, 99 insertions(+), 29 deletions(-)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index cfbdd99fdb1a..a353ce55fd18 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -241,6 +241,19 @@ loop_validate_size(loff_t size)
return 0;
 }
 
+/**
+ * loop_validate_block_size() - validates the passed in block size
+ * @bsize: size to validate
+ */
+static int
+loop_validate_block_size(unsigned short bsize)
+{
+   if (bsize < 512 || bsize > PAGE_SIZE || !is_power_of_2(bsize))
+   return -EINVAL;
+
+   return 0;
+}
+
 /**
  * loop_set_size() - sets device size and notifies userspace
  * @lo: struct loop_device to set the size for
@@ -1063,23 +1076,24 @@ loop_set_status_from_info(struct loop_device *lo,
return 0;
 }
 
-static int loop_set_fd(struct loop_device *lo, fmode_t mode,
-  struct block_device *bdev, unsigned int arg)
+static int loop_configure(struct loop_device *lo, fmode_t mode,
+ struct block_device *bdev,
+ const struct loop_config *config)
 {
struct file *file;
struct inode*inode;
struct address_space *mapping;
struct block_device *claimed_bdev = NULL;
-   int lo_flags = 0;
int error;
loff_t  size;
boolpartscan;
+   unsigned short  bsize;
 
/* This is safe, since we have a reference from open(). */
__module_get(THIS_MODULE);
 
error = -EBADF;
-   file = fget(arg);
+   file = fget(config->fd);
if (!file)
goto out;
 
@@ -1088,7 +1102,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t 
mode,
 * here to avoid changing device under exclusive owner.
 */
if (!(mode & FMODE_EXCL)) {
-   claimed_bdev = bd_start_claiming(bdev, loop_set_fd);
+   claimed_bdev = bd_start_claiming(bdev, loop_configure);
if (IS_ERR(claimed_bdev)) {
error = PTR_ERR(claimed_bdev);
goto out_putf;
@@ -1110,44 +1124,58 @@ static int loop_set_fd(struct loop_device *lo, fmode_t 
mode,
mapping = file->f_mapping;
inode = mapping->host;
 
-   if (!(file->f_mode & FMODE_WRITE) || !(mode & FMODE_WRITE) ||
-   !file->f_op->write_iter)
-   lo_flags |= LO_FLAGS_READ_ONLY;
-
size = get_loop_size(lo, file);
error = loop_validate_size(size);
if (error)
goto out_unlock;
+
+   if ((config->info.lo_flags & ~LOOP_CONFIGURE_SETTABLE_FLAGS) != 0) {
+   error = -EINVAL;
+   goto out_unlock;
+   }
+
+   if (config->block_size) {
+   error = loop_validate_block_size(config->block_size);
+   if (error)
+   goto out_unlock;
+   }
+
+   error = loop_set_status_from_info(lo, >info);
+   if (error)
+   goto out_unlock;
+
+   if (!(file->f_mode & FMODE_WRITE) || !(mode & FMODE_WRITE) ||
+   !file->f_op->write_iter)
+   lo->lo_flags |= LO_FLAGS_READ_ONLY;
+
error = loop_prepare_queue(lo);
if