Skip to contentSkip to conversation

loop: LOOP_FLAGS_BLOCKSIZE fixes

PATCH In review Omar Sandoval 3 participants 17 messages Aug 18, 2017 Block layer

lore
Share & tools
lore
#0 lore raw

cover loop: LOOP_FLAGS_BLOCKSIZE fixes

From: Omar Sandoval <[email protected]>

A couple of bugs I found while adding blktests for the new loop block size feature. Based on v4.13-rc5, we should get these in for 4.13.

Thanks!

Omar Sandoval (2):
loop: always return block size in LOOP_GET_STATUS
loop: fix hang if LOOP_SET_STATUS gets invalid blocksize or encrypt
type

 drivers/block/loop.c | 53 ++++++++++++++++++++++++++++++----------------------
 1 file changed, 31 insertions(+), 22 deletions(-)
Signature · 1 line
2.14.1
#1 lore raw

PATCH 1/2 loop: always return block size in LOOP_GET_STATUS

From: Omar Sandoval <[email protected]>

When I was writing a test for the new loop device block size functionality, I realized that the interface is kind of dumb:

- lo_init[0] is never filled in with the logical block size we previously set
- lo_flags returned from LOOP_GET_STATUS will have LO_FLAGS_BLOCKSIZE set if we previously called LOOP_SET_STATUS with LO_FLAGS_BLOCKSIZE set, which doesn't really mean anything

Instead, for LOOP_GET_STATUS, let's always fill in lo_init[0] and set the LO_FLAGS_BLOCKSIZE flag to indicate we support it.

---
 drivers/block/loop.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)
drivers/block/loop.c +17 -16
index ef8334949b42..39fa7f48e0c7 100644
@@ -234,7 +234,7 @@ figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit,
 		lo->lo_offset = offset;
 	if (lo->lo_sizelimit != sizelimit)
 		lo->lo_sizelimit = sizelimit;
-	if (lo->lo_flags & LO_FLAGS_BLOCKSIZE) {
+	if (lo->lo_logical_blocksize != logical_blocksize) {
 		lo->lo_logical_blocksize = logical_blocksize;
 		blk_queue_physical_block_size(lo->lo_queue, lo->lo_blocksize);
 		blk_queue_logical_block_size(lo->lo_queue,
@@ -820,7 +820,7 @@ static void loop_config_discard(struct loop_device *lo)
 	struct file *file = lo->lo_backing_file;
 	struct inode *inode = file->f_mapping->host;
 	struct request_queue *q = lo->lo_queue;
-	int lo_bits = 9;
+	int lo_bits = blksize_bits(lo->lo_logical_blocksize);
 
 	/*
 	 * We use punch hole to reclaim the free space used by the
@@ -840,8 +840,6 @@ static void loop_config_discard(struct loop_device *lo)
 
 	q->limits.discard_granularity = inode->i_sb->s_blocksize;
 	q->limits.discard_alignment = 0;
-	if (lo->lo_flags & LO_FLAGS_BLOCKSIZE)
-		lo_bits = blksize_bits(lo->lo_logical_blocksize);
 
 	blk_queue_max_discard_sectors(q, UINT_MAX >> lo_bits);
 	blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> lo_bits);
@@ -1061,6 +1059,7 @@ static int loop_clr_fd(struct loop_device *lo)
 	lo->lo_offset = 0;
 	lo->lo_sizelimit = 0;
 	lo->lo_encrypt_key_size = 0;
+	lo->lo_logical_blocksize = 512;
 	memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
 	memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
 	memset(lo->lo_file_name, 0, LO_NAME_SIZE);
@@ -1105,6 +1104,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
 	struct loop_func_table *xfer;
 	kuid_t uid = current_uid();
 	int lo_flags = lo->lo_flags;
+	unsigned lo_logical_blocksize;
 
 	if (lo->lo_encrypt_key_size &&
 	    !uid_eq(lo->lo_key_owner, uid) &&
@@ -1138,25 +1138,24 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
 		goto exit;
 
 	if (info->lo_flags & LO_FLAGS_BLOCKSIZE) {
-		if (!(lo->lo_flags & LO_FLAGS_BLOCKSIZE))
-			lo->lo_logical_blocksize = 512;
-		lo->lo_flags |= LO_FLAGS_BLOCKSIZE;
-		if (LO_INFO_BLOCKSIZE(info) != 512 &&
-		    LO_INFO_BLOCKSIZE(info) != 1024 &&
-		    LO_INFO_BLOCKSIZE(info) != 2048 &&
-		    LO_INFO_BLOCKSIZE(info) != 4096)
+		lo_logical_blocksize = LO_INFO_BLOCKSIZE(info);
+		if (lo_logical_blocksize != 512 &&
+		    lo_logical_blocksize != 1024 &&
+		    lo_logical_blocksize != 2048 &&
+		    lo_logical_blocksize != 4096)
 			return -EINVAL;
-		if (LO_INFO_BLOCKSIZE(info) > lo->lo_blocksize)
+		if (lo_logical_blocksize > lo->lo_blocksize)
 			return -EINVAL;
+	} else {
+		lo_logical_blocksize = lo->lo_logical_blocksize;
 	}
 
 	if (lo->lo_offset != info->lo_offset ||
 	    lo->lo_sizelimit != info->lo_sizelimit ||
 	    lo->lo_flags != lo_flags ||
-	    ((lo->lo_flags & LO_FLAGS_BLOCKSIZE) &&
-	     lo->lo_logical_blocksize != LO_INFO_BLOCKSIZE(info))) {
+	    lo->lo_logical_blocksize != lo_logical_blocksize) {
 		if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit,
-				     LO_INFO_BLOCKSIZE(info))) {
+				     lo_logical_blocksize)) {
 			err = -EFBIG;
 			goto exit;
 		}
@@ -1223,7 +1222,7 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info)
 	info->lo_rdevice = huge_encode_dev(lo->lo_device ? stat.rdev : stat.dev);
 	info->lo_offset = lo->lo_offset;
 	info->lo_sizelimit = lo->lo_sizelimit;
-	info->lo_flags = lo->lo_flags;
+	info->lo_flags = lo->lo_flags | LO_FLAGS_BLOCKSIZE;
 	memcpy(info->lo_file_name, lo->lo_file_name, LO_NAME_SIZE);
 	memcpy(info->lo_crypt_name, lo->lo_crypt_name, LO_NAME_SIZE);
 	info->lo_encrypt_type =
@@ -1233,6 +1232,7 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info)
 		memcpy(info->lo_encrypt_key, lo->lo_encrypt_key,
 		       lo->lo_encrypt_key_size);
 	}
+	LO_INFO_BLOCKSIZE(info) = lo->lo_logical_blocksize;
 	return 0;
 }
 
@@ -1835,6 +1835,7 @@ static int loop_add(struct loop_device **l, int i)
 	mutex_init(&lo->lo_ctl_mutex);
 	atomic_set(&lo->lo_refcnt, 0);
 	lo->lo_number		= i;
+	lo->lo_logical_blocksize = 512;
 	spin_lock_init(&lo->lo_lock);
 	disk->major		= LOOP_MAJOR;
 	disk->first_minor	= i << part_shift;
Signature · 1 line
2.14.1
#2 lore raw

Re: [PATCH 1/2] loop: always return block size in LOOP_GET_STATUS

Quoted 11 lines · Omar Sandoval

From: Omar Sandoval <[email protected]>

When I was writing a test for the new loop device block size functionality, I realized that the interface is kind of dumb:

- lo_init[0] is never filled in with the logical block size we previously set
- lo_flags returned from LOOP_GET_STATUS will have LO_FLAGS_BLOCKSIZE set if we previously called LOOP_SET_STATUS with LO_FLAGS_BLOCKSIZE set, which doesn't really mean anything

Quoted 8 lines

Instead, for LOOP_GET_STATUS, let's always fill in lo_init[0] and set the LO_FLAGS_BLOCKSIZE flag to indicate we support it.

---
 drivers/block/loop.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

Phew. 'Dumb interface'.
'tis wasn't me who designed the interface; Backwards compability are the watchwords here. Personally, I would have loved to design a new interface.

I've got quite some flak for daring to break existing interfaces, most notably setting logical and physical blocksize per default (which I would _love_ to have done, seeing that it really makes sense here). But as this would change the behaviour I've gone through pains (and several _years_ of iterations) to get this sorted.

So if you design a blocktest for that ensure that
a) the sysfs attributes before and after the patch are _identical_
b) the sysfs attributes will only change if the 'LO_FLAGS_BLOCKSIZE' flag has been set
and
c) validate the written blocksizes; this is required to be able to install bootloaders there

This whole interface was designed such that you can prepare bootable diskimages for S/390 DASDs, which use a native 4k blocksize.

Cheers,

Hannes

Signature · 5 lines
Dr. Hannes Reinecke		   Teamlead Storage & Networking
[email protected]			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)
#3 lore raw

Re: [PATCH 1/2] loop: always return block size in LOOP_GET_STATUS

Quoted 39 lines · Hannes Reinecke
Quoted 11 lines · Omar Sandoval

From: Omar Sandoval <[email protected]>

When I was writing a test for the new loop device block size functionality, I realized that the interface is kind of dumb:

- lo_init[0] is never filled in with the logical block size we previously set
- lo_flags returned from LOOP_GET_STATUS will have LO_FLAGS_BLOCKSIZE set if we previously called LOOP_SET_STATUS with LO_FLAGS_BLOCKSIZE set, which doesn't really mean anything

Quoted 8 lines

Instead, for LOOP_GET_STATUS, let's always fill in lo_init[0] and set the LO_FLAGS_BLOCKSIZE flag to indicate we support it.

---
 drivers/block/loop.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

Phew. 'Dumb interface'.
'tis wasn't me who designed the interface; Backwards compability are the watchwords here. Personally, I would have loved to design a new interface.

I've got quite some flak for daring to break existing interfaces, most notably setting logical and physical blocksize per default (which I would _love_ to have done, seeing that it really makes sense here). But as this would change the behaviour I've gone through pains (and several _years_ of iterations) to get this sorted.

So if you design a blocktest for that ensure that
a) the sysfs attributes before and after the patch are _identical_
b) the sysfs attributes will only change if the 'LO_FLAGS_BLOCKSIZE' flag has been set
and
c) validate the written blocksizes; this is required to be able to install bootloaders there

Quoted 2 lines

This whole interface was designed such that you can prepare bootable diskimages for S/390 DASDs, which use a native 4k blocksize.

Hi, Hannes,

Wasn't insulting you at all, the only part of the interface I'm complaining about is LOOP_GET_STATUS missing information :)

#4 lore raw

Re: [PATCH 1/2] loop: always return block size in LOOP_GET_STATUS

Quoted 40 lines · Omar Sandoval
Quoted 39 lines · Hannes Reinecke
Quoted 11 lines · Omar Sandoval

From: Omar Sandoval <[email protected]>

When I was writing a test for the new loop device block size functionality, I realized that the interface is kind of dumb:

- lo_init[0] is never filled in with the logical block size we previously set
- lo_flags returned from LOOP_GET_STATUS will have LO_FLAGS_BLOCKSIZE set if we previously called LOOP_SET_STATUS with LO_FLAGS_BLOCKSIZE set, which doesn't really mean anything

Quoted 8 lines

Instead, for LOOP_GET_STATUS, let's always fill in lo_init[0] and set the LO_FLAGS_BLOCKSIZE flag to indicate we support it.

---
 drivers/block/loop.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

Phew. 'Dumb interface'.
'tis wasn't me who designed the interface; Backwards compability are the watchwords here. Personally, I would have loved to design a new interface.

I've got quite some flak for daring to break existing interfaces, most notably setting logical and physical blocksize per default (which I would _love_ to have done, seeing that it really makes sense here). But as this would change the behaviour I've gone through pains (and several _years_ of iterations) to get this sorted.

So if you design a blocktest for that ensure that
a) the sysfs attributes before and after the patch are _identical_
b) the sysfs attributes will only change if the 'LO_FLAGS_BLOCKSIZE' flag has been set
and
c) validate the written blocksizes; this is required to be able to install bootloaders there

Quoted 8 lines
Quoted 2 lines

This whole interface was designed such that you can prepare bootable diskimages for S/390 DASDs, which use a native 4k blocksize.

Hi, Hannes,

Wasn't insulting you at all, the only part of the interface I'm complaining about is LOOP_GET_STATUS missing information :)

Sure. Just saying.
But please make sure only to return that information if the LO_FLAGS_BLOCKSIZE flag is set; otherwise there's a rick of confusing losetup.

Cheers,

Hannes

Signature · 5 lines
Dr. Hannes Reinecke		   Teamlead Storage & Networking
[email protected]			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)
#5 lore raw

Re: [PATCH 1/2] loop: always return block size in LOOP_GET_STATUS

Quoted 46 lines · Hannes Reinecke
Quoted 45 lines · Omar Sandoval
Quoted 39 lines · Hannes Reinecke
Quoted 11 lines · Omar Sandoval

From: Omar Sandoval <[email protected]>

When I was writing a test for the new loop device block size functionality, I realized that the interface is kind of dumb:

- lo_init[0] is never filled in with the logical block size we previously set
- lo_flags returned from LOOP_GET_STATUS will have LO_FLAGS_BLOCKSIZE set if we previously called LOOP_SET_STATUS with LO_FLAGS_BLOCKSIZE set, which doesn't really mean anything

Quoted 8 lines

Instead, for LOOP_GET_STATUS, let's always fill in lo_init[0] and set the LO_FLAGS_BLOCKSIZE flag to indicate we support it.

---
 drivers/block/loop.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

Phew. 'Dumb interface'.
'tis wasn't me who designed the interface; Backwards compability are the watchwords here. Personally, I would have loved to design a new interface.

I've got quite some flak for daring to break existing interfaces, most notably setting logical and physical blocksize per default (which I would _love_ to have done, seeing that it really makes sense here). But as this would change the behaviour I've gone through pains (and several _years_ of iterations) to get this sorted.

So if you design a blocktest for that ensure that
a) the sysfs attributes before and after the patch are _identical_
b) the sysfs attributes will only change if the 'LO_FLAGS_BLOCKSIZE' flag has been set
and
c) validate the written blocksizes; this is required to be able to install bootloaders there

Quoted 2 lines

This whole interface was designed such that you can prepare bootable diskimages for S/390 DASDs, which use a native 4k blocksize.

Hi, Hannes,

Quoted 7 lines
Quoted 3 lines

Wasn't insulting you at all, the only part of the interface I'm complaining about is LOOP_GET_STATUS missing information :)

Sure. Just saying.
But please make sure only to return that information if the LO_FLAGS_BLOCKSIZE flag is set; otherwise there's a rick of confusing losetup.

I actually checked losetup, it works just fine with LO_FLAGS_BLOCKSIZE always set and lo_init[0] always filled in.

#6 lore raw

Re: [PATCH 1/2] loop: always return block size in LOOP_GET_STATUS

Quoted 3 lines · Omar Sandoval
Quoted 2 lines · Hannes Reinecke
Quoted 1 line · Omar Sandoval

On Fri, Aug 18, 2017 at 09:18:52AM +0200, Hannes Reinecke wrote:

[ .. ]

Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
Quoted 14 lines

I've got quite some flak for daring to break existing interfaces, most notably setting logical and physical blocksize per default (which I would _love_ to have done, seeing that it really makes sense here). But as this would change the behaviour I've gone through pains (and several _years_ of iterations) to get this sorted.

So if you design a blocktest for that ensure that
a) the sysfs attributes before and after the patch are _identical_
b) the sysfs attributes will only change if the 'LO_FLAGS_BLOCKSIZE' flag has been set
and
c) validate the written blocksizes; this is required to be able to install bootloaders there

Quoted 2 lines

This whole interface was designed such that you can prepare bootable diskimages for S/390 DASDs, which use a native 4k blocksize.

Hi, Hannes,

Wasn't insulting you at all, the only part of the interface I'm complaining about is LOOP_GET_STATUS missing information :)

Quoted 8 lines
Quoted 4 lines

Sure. Just saying.
But please make sure only to return that information if the LO_FLAGS_BLOCKSIZE flag is set; otherwise there's a rick of confusing losetup.

I actually checked losetup, it works just fine with LO_FLAGS_BLOCKSIZE always set and lo_init[0] always filled in.

The original argument I had with the util-linux maintainer did not revolve so much around technical details :-)

Cheers,

Hannes

Signature · 5 lines
Dr. Hannes Reinecke		   Teamlead Storage & Networking
[email protected]			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)
#7 lore raw

Re: [PATCH 1/2] loop: always return block size in LOOP_GET_STATUS

Quoted 32 lines · Hannes Reinecke
Quoted 3 lines · Omar Sandoval
Quoted 2 lines · Hannes Reinecke
Quoted 1 line · Omar Sandoval

On Fri, Aug 18, 2017 at 09:18:52AM +0200, Hannes Reinecke wrote:

[ .. ]

Quoted 27 lines
Quoted 26 lines
Quoted 14 lines
Quoted 14 lines

I've got quite some flak for daring to break existing interfaces, most notably setting logical and physical blocksize per default (which I would _love_ to have done, seeing that it really makes sense here). But as this would change the behaviour I've gone through pains (and several _years_ of iterations) to get this sorted.

So if you design a blocktest for that ensure that
a) the sysfs attributes before and after the patch are _identical_
b) the sysfs attributes will only change if the 'LO_FLAGS_BLOCKSIZE' flag has been set
and
c) validate the written blocksizes; this is required to be able to install bootloaders there

Quoted 8 lines
Quoted 2 lines

This whole interface was designed such that you can prepare bootable diskimages for S/390 DASDs, which use a native 4k blocksize.

Hi, Hannes,

Wasn't insulting you at all, the only part of the interface I'm complaining about is LOOP_GET_STATUS missing information :)

Sure. Just saying.
But please make sure only to return that information if the LO_FLAGS_BLOCKSIZE flag is set; otherwise there's a rick of confusing losetup.

Quoted 5 lines
Quoted 3 lines

I actually checked losetup, it works just fine with LO_FLAGS_BLOCKSIZE always set and lo_init[0] always filled in.

The original argument I had with the util-linux maintainer did not revolve so much around technical details :-)

Karel, what were your concerns here?

#8 lore raw

Re: [PATCH 1/2] loop: always return block size in LOOP_GET_STATUS

Quoted 2 lines · Omar Sandoval
Quoted 1 line · Hannes Reinecke

On 08/18/2017 09:47 AM, Omar Sandoval wrote:

[ .. ]

Quoted 9 lines
Quoted 6 lines
Quoted 4 lines

I actually checked losetup, it works just fine with LO_FLAGS_BLOCKSIZE always set and lo_init[0] always filled in.

The original argument I had with the util-linux maintainer did not revolve so much around technical details :-)

Karel, what were your concerns here?

It wasn't Karel, it was our guy.
Doesn't make it any better, though...

Cheers,

Hannes

Signature · 5 lines
Dr. Hannes Reinecke		   Teamlead Storage & Networking
[email protected]			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)
#9 lore raw

Re: [PATCH 1/2] loop: always return block size in LOOP_GET_STATUS

Quoted 8 lines · Hannes Reinecke
Quoted 2 lines · Omar Sandoval
Quoted 1 line · Hannes Reinecke

On 08/18/2017 09:47 AM, Omar Sandoval wrote:

[ .. ]

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

I actually checked losetup, it works just fine with LO_FLAGS_BLOCKSIZE always set and lo_init[0] always filled in.

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

The original argument I had with the util-linux maintainer did not revolve so much around technical details :-)

Karel, what were your concerns here?

It wasn't Karel, it was our guy.
Doesn't make it any better, though...

I just went through the code and util-linux doesn't mention lo_init at all except for the definition, and everywhere it's using lo_flags would work fine with the behavior I implemented here. Unless there's an actual issue someone can point out, I see no reason to not do it this way.

#10 lore raw

Re: [PATCH 1/2] loop: always return block size in LOOP_GET_STATUS

Quoted 14 lines · Omar Sandoval
Quoted 13 lines · Hannes Reinecke
Quoted 2 lines · Omar Sandoval
Quoted 1 line · Hannes Reinecke

On 08/18/2017 09:47 AM, Omar Sandoval wrote:

[ .. ]

Quoted 9 lines
Quoted 6 lines
Quoted 4 lines

I actually checked losetup, it works just fine with LO_FLAGS_BLOCKSIZE always set and lo_init[0] always filled in.

The original argument I had with the util-linux maintainer did not revolve so much around technical details :-)

Karel, what were your concerns here?

Quoted 7 lines
Quoted 2 lines

It wasn't Karel, it was our guy.
Doesn't make it any better, though...

I just went through the code and util-linux doesn't mention lo_init at all except for the definition, and everywhere it's using lo_flags would work fine with the behavior I implemented here. Unless there's an actual issue someone can point out, I see no reason to not do it this way.

Hmm.. we have loopdev API enhancement in Linus' tree and losetup maintainer have no clue about it ;-)

Anyway, I like the idea with LO_FLAGS_BLOCKSIZE and lo_init[]. It seems like a backwardly compatible way how to make loopdevs usable for dd(1) images from non-512 devices, etc.

For now nothing uses lo_init[], so it seems no problem to use it for LOOP_GET_STATUS64.

Note that we use LOOP_GET_STATUS64 and struct loop_info64 only, old API around "struct loop_info" is no more used by util-linux.

The important detail is that for losetup (to show mapped devices) is more important /sys than LOOP_GET_STATUS64. The /sys is better because it does not require root permissions and it makes losetup (and lsblk) usable for regular users.

I guess /sys/block/loopN/queue/minimum_io_size is affected by Hannes' LO_FLAGS_BLOCKSIZE patches, so non-512 I/O sizes for loopdevs are visible in "lsblk -t /dev/loopN" output, right?

I'll add --blocksize <size> to losetup, and BLKSZ column to output to make the new feature usable also for end-users.

Thanks for CC:

Karel

Signature · 2 lines
 Karel Zak  <[email protected]>
 http://karelzak.blogspot.com
#11 lore raw

Re: [PATCH 1/2] loop: always return block size in LOOP_GET_STATUS

Quoted 18 lines · Karel Zak
Quoted 17 lines · Omar Sandoval
Quoted 15 lines · Hannes Reinecke
Quoted 2 lines · Omar Sandoval
Quoted 1 line · Hannes Reinecke

On 08/18/2017 09:47 AM, Omar Sandoval wrote:

[ .. ]

Quoted 9 lines
Quoted 6 lines
Quoted 4 lines

I actually checked losetup, it works just fine with LO_FLAGS_BLOCKSIZE always set and lo_init[0] always filled in.

The original argument I had with the util-linux maintainer did not revolve so much around technical details :-)

Karel, what were your concerns here?

It wasn't Karel, it was our guy.
Doesn't make it any better, though...

Quoted 7 lines
Quoted 4 lines

I just went through the code and util-linux doesn't mention lo_init at all except for the definition, and everywhere it's using lo_flags would work fine with the behavior I implemented here. Unless there's an actual issue someone can point out, I see no reason to not do it this way.

Hmm.. we have loopdev API enhancement in Linus' tree and losetup maintainer have no clue about it ;-)

Ha, glad you're hearing about it now before it's too late :)

Quoted 6 lines

Anyway, I like the idea with LO_FLAGS_BLOCKSIZE and lo_init[]. It seems like a backwardly compatible way how to make loopdevs usable for dd(1) images from non-512 devices, etc.

For now nothing uses lo_init[], so it seems no problem to use it for LOOP_GET_STATUS64.

Do you see any issues with the behavior I added in this patch? Namely, LOOP_GET_STATUS{,64} will always return lo_flags with LO_FLAGS_BLOCKSIZE set and lo_init[0] will always contain the blocksize. Older userspace which doesn't know about LO_FLAGS_BLOCKSIZE will just ignore it and the LOOP_GET_STATUS64; modify stuff; LOOP_SET_STATUS64 pattern will still work.

Quoted 7 lines

Note that we use LOOP_GET_STATUS64 and struct loop_info64 only, old API around "struct loop_info" is no more used by util-linux.

The important detail is that for losetup (to show mapped devices) is more important /sys than LOOP_GET_STATUS64. The /sys is better because it does not require root permissions and it makes losetup (and lsblk) usable for regular users.

Ah, I'll spin a followup patch to add it to sysfs.

Quoted 3 lines

I guess /sys/block/loopN/queue/minimum_io_size is affected by Hannes' LO_FLAGS_BLOCKSIZE patches, so non-512 I/O sizes for loopdevs are visible in "lsblk -t /dev/loopN" output, right?

Yup:

# lsblk -t /dev/loop0
NAME  ALIGNMENT MIN-IO OPT-IO PHY-SEC LOG-SEC ROTA SCHED       RQ-SIZE  RA WSAME
loop0         0   4096      0    4096    4096    1 mq-deadline     256 128    0B
Quoted 2 lines

I'll add --blocksize <size> to losetup, and BLKSZ column to output to make the new feature usable also for end-users.

Thank you!

#12 lore raw

Re: [PATCH 1/2] loop: always return block size in LOOP_GET_STATUS

Quoted 36 lines · Omar Sandoval
Quoted 18 lines · Karel Zak
Quoted 17 lines · Omar Sandoval
Quoted 15 lines · Hannes Reinecke
Quoted 2 lines · Omar Sandoval
Quoted 1 line · Hannes Reinecke

On 08/18/2017 09:47 AM, Omar Sandoval wrote:

[ .. ]

Quoted 9 lines
Quoted 6 lines
Quoted 4 lines

I actually checked losetup, it works just fine with LO_FLAGS_BLOCKSIZE always set and lo_init[0] always filled in.

The original argument I had with the util-linux maintainer did not revolve so much around technical details :-)

Karel, what were your concerns here?

It wasn't Karel, it was our guy.
Doesn't make it any better, though...

Quoted 7 lines
Quoted 4 lines

I just went through the code and util-linux doesn't mention lo_init at all except for the definition, and everywhere it's using lo_flags would work fine with the behavior I implemented here. Unless there's an actual issue someone can point out, I see no reason to not do it this way.

Hmm.. we have loopdev API enhancement in Linus' tree and losetup maintainer have no clue about it ;-)

Ha, glad you're hearing about it now before it's too late :)

Quoted 6 lines

Anyway, I like the idea with LO_FLAGS_BLOCKSIZE and lo_init[]. It seems like a backwardly compatible way how to make loopdevs usable for dd(1) images from non-512 devices, etc.

For now nothing uses lo_init[], so it seems no problem to use it for LOOP_GET_STATUS64.

Quoted 6 lines

Do you see any issues with the behavior I added in this patch? Namely, LOOP_GET_STATUS{,64} will always return lo_flags with LO_FLAGS_BLOCKSIZE set and lo_init[0] will always contain the blocksize. Older userspace which doesn't know about LO_FLAGS_BLOCKSIZE will just ignore it and the LOOP_GET_STATUS64; modify stuff; LOOP_SET_STATUS64 pattern will still work.

Yes, I think your idea is correct. All unknown flags should be ignored by userspace. This is not the first time the API (lo_flags) is extended by a new flag.

Karel

Signature · 2 lines
 Karel Zak  <[email protected]>
 http://karelzak.blogspot.com
#13 lore raw

Re: [PATCH 1/2] loop: always return block size in LOOP_GET_STATUS

In reply to Omar Sandoval
Quoted 14 lines · Omar Sandoval
Quoted 13 lines · Hannes Reinecke
Quoted 2 lines · Omar Sandoval
Quoted 1 line · Hannes Reinecke

On 08/18/2017 09:47 AM, Omar Sandoval wrote:

[ .. ]

Quoted 9 lines
Quoted 6 lines
Quoted 4 lines

I actually checked losetup, it works just fine with LO_FLAGS_BLOCKSIZE always set and lo_init[0] always filled in.

The original argument I had with the util-linux maintainer did not revolve so much around technical details :-)

Karel, what were your concerns here?

Quoted 7 lines
Quoted 2 lines

It wasn't Karel, it was our guy.
Doesn't make it any better, though...

I just went through the code and util-linux doesn't mention lo_init at all except for the definition, and everywhere it's using lo_flags would work fine with the behavior I implemented here. Unless there's an actual issue someone can point out, I see no reason to not do it this way.

BTW guys, it seems the current LO_FLAGS_BLOCKSIZE implementation does not care about images from disks where is non-zero alignment offset. It mean disks where is extra offset between logical and physical sectors mapping. Something like:

modprobe scsi_debug dev_size_mb=100 sector_size=512 physblk_exp=3 lowest_aligned=7

...just pedantic note; IMHO it's fine to ignore this use-case ;-)

Karel

Signature · 2 lines
 Karel Zak  <[email protected]>
 http://karelzak.blogspot.com
#14 lore raw

PATCH 2/2 loop: fix hang if LOOP_SET_STATUS gets invalid blocksize or encrypt type

In reply to Omar Sandoval

From: Omar Sandoval <[email protected]>

In both of these error cases, we need to make sure to unfreeze the queue before we return.

Fixes ecdd09597a57 ("block/loop: fix race between I/O and set_status")
Fixes f2c6df7dbf9a ("loop: support 4k physical blocksize")
---
 drivers/block/loop.c | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)
drivers/block/loop.c +16 -8
index 39fa7f48e0c7..6c7609b3305d 100644
@@ -1125,11 +1125,15 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
 	if (info->lo_encrypt_type) {
 		unsigned int type = info->lo_encrypt_type;
 
-		if (type >= MAX_LO_CRYPT)
-			return -EINVAL;
+		if (type >= MAX_LO_CRYPT) {
+			err = -EINVAL;
+			goto exit;
+		}
 		xfer = xfer_funcs[type];
-		if (xfer == NULL)
-			return -EINVAL;
+		if (xfer == NULL) {
+			err = -EINVAL;
+			goto exit;
+		}
 	} else
 		xfer = NULL;
 
@@ -1142,10 +1146,14 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
 		if (lo_logical_blocksize != 512 &&
 		    lo_logical_blocksize != 1024 &&
 		    lo_logical_blocksize != 2048 &&
-		    lo_logical_blocksize != 4096)
-			return -EINVAL;
-		if (lo_logical_blocksize > lo->lo_blocksize)
-			return -EINVAL;
+		    lo_logical_blocksize != 4096) {
+			err = -EINVAL;
+			goto exit;
+		}
+		if (lo_logical_blocksize > lo->lo_blocksize) {
+			err = -EINVAL;
+			goto exit;
+		}
 	} else {
 		lo_logical_blocksize = lo->lo_logical_blocksize;
 	}
Signature · 1 line
2.14.1
#15 lore raw

Re: [PATCH 2/2] loop: fix hang if LOOP_SET_STATUS gets invalid blocksize or encrypt type

Quoted 55 lines · Omar Sandoval

From: Omar Sandoval <[email protected]>

In both of these error cases, we need to make sure to unfreeze the queue before we return.

Fixes ecdd09597a57 ("block/loop: fix race between I/O and set_status")
Fixes f2c6df7dbf9a ("loop: support 4k physical blocksize")
---
 drivers/block/loop.c | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)
drivers/block/loop.c +16 -8
index 39fa7f48e0c7..6c7609b3305d 100644
@@ -1125,11 +1125,15 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
 	if (info->lo_encrypt_type) {
 		unsigned int type = info->lo_encrypt_type;
 
-		if (type >= MAX_LO_CRYPT)
-			return -EINVAL;
+		if (type >= MAX_LO_CRYPT) {
+			err = -EINVAL;
+			goto exit;
+		}
 		xfer = xfer_funcs[type];
-		if (xfer == NULL)
-			return -EINVAL;
+		if (xfer == NULL) {
+			err = -EINVAL;
+			goto exit;
+		}
 	} else
 		xfer = NULL;
 
@@ -1142,10 +1146,14 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
 		if (lo_logical_blocksize != 512 &&
 		    lo_logical_blocksize != 1024 &&
 		    lo_logical_blocksize != 2048 &&
-		    lo_logical_blocksize != 4096)
-			return -EINVAL;
-		if (lo_logical_blocksize > lo->lo_blocksize)
-			return -EINVAL;
+		    lo_logical_blocksize != 4096) {
+			err = -EINVAL;
+			goto exit;
+		}
+		if (lo_logical_blocksize > lo->lo_blocksize) {
+			err = -EINVAL;
+			goto exit;
+		}
 	} else {
 		lo_logical_blocksize = lo->lo_logical_blocksize;
 	}
Quoted 1 line

Cheers,

Hannes

Signature · 5 lines
Dr. Hannes Reinecke		   Teamlead Storage & Networking
[email protected]			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)