diff mbox

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

Message ID 9ff9b291e3e872698a040a281549c39c0637565f.1503036471.git.osandov@fb.com (mailing list archive)
State New, archived
Headers show

Commit Message

Omar Sandoval Aug. 18, 2017, 6:15 a.m. UTC
From: Omar Sandoval <osandov@fb.com>

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.

Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 drivers/block/loop.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

Comments

Hannes Reinecke Aug. 18, 2017, 7:18 a.m. UTC | #1
On 08/18/2017 08:15 AM, Omar Sandoval wrote:
> From: Omar Sandoval <osandov@fb.com>
> 
> 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.
> 
> Signed-off-by: Omar Sandoval <osandov@fb.com>
> ---
>  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
Omar Sandoval Aug. 18, 2017, 7:38 a.m. UTC | #2
On Fri, Aug 18, 2017 at 09:18:52AM +0200, Hannes Reinecke wrote:
> On 08/18/2017 08:15 AM, Omar Sandoval wrote:
> > From: Omar Sandoval <osandov@fb.com>
> > 
> > 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.
> > 
> > Signed-off-by: Omar Sandoval <osandov@fb.com>
> > ---
> >  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.

Hi, Hannes,

Wasn't insulting you at all, the only part of the interface I'm
complaining about is LOOP_GET_STATUS missing information :)
Hannes Reinecke Aug. 18, 2017, 7:43 a.m. UTC | #3
On 08/18/2017 09:38 AM, Omar Sandoval wrote:
> On Fri, Aug 18, 2017 at 09:18:52AM +0200, Hannes Reinecke wrote:
>> On 08/18/2017 08:15 AM, Omar Sandoval wrote:
>>> From: Omar Sandoval <osandov@fb.com>
>>>
>>> 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.
>>>
>>> Signed-off-by: Omar Sandoval <osandov@fb.com>
>>> ---
>>>  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.
> 
> 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
Omar Sandoval Aug. 18, 2017, 7:47 a.m. UTC | #4
On Fri, Aug 18, 2017 at 09:43:19AM +0200, Hannes Reinecke wrote:
> On 08/18/2017 09:38 AM, Omar Sandoval wrote:
> > On Fri, Aug 18, 2017 at 09:18:52AM +0200, Hannes Reinecke wrote:
> >> On 08/18/2017 08:15 AM, Omar Sandoval wrote:
> >>> From: Omar Sandoval <osandov@fb.com>
> >>>
> >>> 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.
> >>>
> >>> Signed-off-by: Omar Sandoval <osandov@fb.com>
> >>> ---
> >>>  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.
> > 
> > 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.

I actually checked losetup, it works just fine with LO_FLAGS_BLOCKSIZE
always set and lo_init[0] always filled in.
Hannes Reinecke Aug. 18, 2017, 7:56 a.m. UTC | #5
On 08/18/2017 09:47 AM, Omar Sandoval wrote:
> On Fri, Aug 18, 2017 at 09:43:19AM +0200, Hannes Reinecke wrote:
>> On 08/18/2017 09:38 AM, Omar Sandoval wrote:
>>> On Fri, Aug 18, 2017 at 09:18:52AM +0200, Hannes Reinecke wrote:
[ .. ]
>>>> 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.
>>>
>>> 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.
> 
> 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
Omar Sandoval Aug. 18, 2017, 8:05 a.m. UTC | #6
On Fri, Aug 18, 2017 at 09:56:26AM +0200, Hannes Reinecke wrote:
> On 08/18/2017 09:47 AM, Omar Sandoval wrote:
> > On Fri, Aug 18, 2017 at 09:43:19AM +0200, Hannes Reinecke wrote:
> >> On 08/18/2017 09:38 AM, Omar Sandoval wrote:
> >>> On Fri, Aug 18, 2017 at 09:18:52AM +0200, Hannes Reinecke wrote:
> [ .. ]
> >>>> 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.
> >>>
> >>> 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.
> > 
> > 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?
Hannes Reinecke Aug. 18, 2017, 8:12 a.m. UTC | #7
On 08/18/2017 10:05 AM, Omar Sandoval wrote:
> On Fri, Aug 18, 2017 at 09:56:26AM +0200, Hannes Reinecke wrote:
>> On 08/18/2017 09:47 AM, Omar Sandoval wrote:
[ .. ]
>>>
>>> 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
Omar Sandoval Aug. 18, 2017, 8:22 a.m. UTC | #8
On Fri, Aug 18, 2017 at 10:12:51AM +0200, Hannes Reinecke wrote:
> On 08/18/2017 10:05 AM, Omar Sandoval wrote:
> > On Fri, Aug 18, 2017 at 09:56:26AM +0200, Hannes Reinecke wrote:
> >> On 08/18/2017 09:47 AM, Omar Sandoval wrote:
> [ .. ]
> >>>
> >>> 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...

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.
Karel Zak Aug. 18, 2017, 9:22 a.m. UTC | #9
On Fri, Aug 18, 2017 at 01:22:26AM -0700, Omar Sandoval wrote:
> On Fri, Aug 18, 2017 at 10:12:51AM +0200, Hannes Reinecke wrote:
> > On 08/18/2017 10:05 AM, Omar Sandoval wrote:
> > > On Fri, Aug 18, 2017 at 09:56:26AM +0200, Hannes Reinecke wrote:
> > >> On 08/18/2017 09:47 AM, Omar Sandoval wrote:
> > [ .. ]
> > >>>
> > >>> 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...
> 
> 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
Karel Zak Aug. 18, 2017, 9:39 a.m. UTC | #10
On Fri, Aug 18, 2017 at 01:22:26AM -0700, Omar Sandoval wrote:
> On Fri, Aug 18, 2017 at 10:12:51AM +0200, Hannes Reinecke wrote:
> > On 08/18/2017 10:05 AM, Omar Sandoval wrote:
> > > On Fri, Aug 18, 2017 at 09:56:26AM +0200, Hannes Reinecke wrote:
> > >> On 08/18/2017 09:47 AM, Omar Sandoval wrote:
> > [ .. ]
> > >>>
> > >>> 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...
> 
> 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
Omar Sandoval Aug. 18, 2017, 4:44 p.m. UTC | #11
On Fri, Aug 18, 2017 at 11:22:39AM +0200, Karel Zak wrote:
> On Fri, Aug 18, 2017 at 01:22:26AM -0700, Omar Sandoval wrote:
> > On Fri, Aug 18, 2017 at 10:12:51AM +0200, Hannes Reinecke wrote:
> > > On 08/18/2017 10:05 AM, Omar Sandoval wrote:
> > > > On Fri, Aug 18, 2017 at 09:56:26AM +0200, Hannes Reinecke wrote:
> > > >> On 08/18/2017 09:47 AM, Omar Sandoval wrote:
> > > [ .. ]
> > > >>>
> > > >>> 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...
> > 
> > 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 :)

>  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.

>  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.

>  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

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

Thank you!
Karel Zak Aug. 18, 2017, 5:25 p.m. UTC | #12
On Fri, Aug 18, 2017 at 09:44:25AM -0700, Omar Sandoval wrote:
> On Fri, Aug 18, 2017 at 11:22:39AM +0200, Karel Zak wrote:
> > On Fri, Aug 18, 2017 at 01:22:26AM -0700, Omar Sandoval wrote:
> > > On Fri, Aug 18, 2017 at 10:12:51AM +0200, Hannes Reinecke wrote:
> > > > On 08/18/2017 10:05 AM, Omar Sandoval wrote:
> > > > > On Fri, Aug 18, 2017 at 09:56:26AM +0200, Hannes Reinecke wrote:
> > > > >> On 08/18/2017 09:47 AM, Omar Sandoval wrote:
> > > > [ .. ]
> > > > >>>
> > > > >>> 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...
> > > 
> > > 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 :)
> 
> >  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.

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
diff mbox

Patch

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index ef8334949b42..39fa7f48e0c7 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -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;