diff mbox series

[v2,05/13] block: Switch to 64-bit bl.max_transfer

Message ID 20181115020334.1189829-6-eblake@redhat.com (mailing list archive)
State New, archived
Headers show
Series block: byte-based blocking read/write | expand

Commit Message

Eric Blake Nov. 15, 2018, 2:03 a.m. UTC
This change has no semantic impact: all drivers either leave the
value at 0 (no inherent 32-bit limit is still translated into
fragmentation below 2G; see the previous patch for that audit), or
set it to a value less than 2G.  However, switching to a larger
type and enforcing the 2G cap at the block layer makes it easier
to audit specific drivers for their robustness to larger sizing,
by letting them specify a value larger than INT_MAX if they have
been audited to be 64-bit clean.

Signed-off-by: Eric Blake <eblake@redhat.com>
---
 include/block/block_int.h | 8 +++++---
 block/io.c                | 7 +++++++
 2 files changed, 12 insertions(+), 3 deletions(-)

Comments

Kevin Wolf Nov. 15, 2018, 3:45 p.m. UTC | #1
Am 15.11.2018 um 03:03 hat Eric Blake geschrieben:
> This change has no semantic impact: all drivers either leave the
> value at 0 (no inherent 32-bit limit is still translated into
> fragmentation below 2G; see the previous patch for that audit), or
> set it to a value less than 2G.  However, switching to a larger
> type and enforcing the 2G cap at the block layer makes it easier
> to audit specific drivers for their robustness to larger sizing,
> by letting them specify a value larger than INT_MAX if they have
> been audited to be 64-bit clean.
> 
> Signed-off-by: Eric Blake <eblake@redhat.com>
> ---
>  include/block/block_int.h | 8 +++++---
>  block/io.c                | 7 +++++++
>  2 files changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index f605622216d..b19d94dac5f 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -549,9 +549,11 @@ typedef struct BlockLimits {
> 
>      /* Maximal transfer length in bytes.  Need not be power of 2, but
>       * must be multiple of opt_transfer and bl.request_alignment, or 0
> -     * for no 32-bit limit.  For now, anything larger than INT_MAX is
> -     * clamped down. */
> -    uint32_t max_transfer;
> +     * for no 32-bit limit.  The block layer fragments all actions
> +     * below 2G, so setting this value to anything larger than INT_MAX
> +     * implies that the driver has been audited for 64-bit
> +     * cleanness. */
> +    uint64_t max_transfer;
> 
>      /* memory alignment, in bytes so that no bounce buffer is needed */
>      size_t min_mem_alignment;
> diff --git a/block/io.c b/block/io.c
> index 39d4e7a3ae1..4911a1123eb 100644
> --- a/block/io.c
> +++ b/block/io.c
> @@ -159,6 +159,13 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
>      if (drv->bdrv_refresh_limits) {
>          drv->bdrv_refresh_limits(bs, errp);
>      }
> +
> +    /* Clamp max_transfer to 2G */
> +    if (bs->bl.max_transfer > UINT32_MAX) {

UINT32_MAX is 4G, not 2G.

Would it make more sense to make BDRV_REQUEST_MAX_BYTES the maximum
anyway? Allowing higher (but not too high) explicit values than what we
clamp to feels a bit odd.

BDRV_REQUEST_MAX_BYTES is probably also what drivers really expect
today.

> +        bs->bl.max_transfer = QEMU_ALIGN_DOWN(BDRV_REQUEST_MAX_BYTES,
> +                                              MAX(bs->bl.opt_transfer,
> +                                                  bs->bl.request_alignment));
> +    }
>  }

Kevin
Eric Blake Nov. 15, 2018, 4:28 p.m. UTC | #2
On 11/15/18 9:45 AM, Kevin Wolf wrote:
> Am 15.11.2018 um 03:03 hat Eric Blake geschrieben:
>> This change has no semantic impact: all drivers either leave the
>> value at 0 (no inherent 32-bit limit is still translated into
>> fragmentation below 2G; see the previous patch for that audit), or
>> set it to a value less than 2G.  However, switching to a larger
>> type and enforcing the 2G cap at the block layer makes it easier
>> to audit specific drivers for their robustness to larger sizing,
>> by letting them specify a value larger than INT_MAX if they have
>> been audited to be 64-bit clean.
>>

>> +++ b/block/io.c
>> @@ -159,6 +159,13 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
>>       if (drv->bdrv_refresh_limits) {
>>           drv->bdrv_refresh_limits(bs, errp);
>>       }
>> +
>> +    /* Clamp max_transfer to 2G */
>> +    if (bs->bl.max_transfer > UINT32_MAX) {
> 
> UINT32_MAX is 4G, not 2G.
> 
> Would it make more sense to make BDRV_REQUEST_MAX_BYTES the maximum
> anyway?

D'oh.  Yes, that's what I intended, possibly by spelling it INT_MAX (the 
fact that the 'if' goes away in patch 13 is not an excuse for sloppy 
coding in the meantime).

> Allowing higher (but not too high) explicit values than what we
> clamp to feels a bit odd.
> 
> BDRV_REQUEST_MAX_BYTES is probably also what drivers really expect
> today.

Correct.  Well, at least the unaudited drivers (the rest of this series 
audits a few drivers that can handle larger byte values).
Kevin Wolf Nov. 16, 2018, 3:32 p.m. UTC | #3
Am 15.11.2018 um 17:28 hat Eric Blake geschrieben:
> On 11/15/18 9:45 AM, Kevin Wolf wrote:
> > Am 15.11.2018 um 03:03 hat Eric Blake geschrieben:
> > > This change has no semantic impact: all drivers either leave the
> > > value at 0 (no inherent 32-bit limit is still translated into
> > > fragmentation below 2G; see the previous patch for that audit), or
> > > set it to a value less than 2G.  However, switching to a larger
> > > type and enforcing the 2G cap at the block layer makes it easier
> > > to audit specific drivers for their robustness to larger sizing,
> > > by letting them specify a value larger than INT_MAX if they have
> > > been audited to be 64-bit clean.
> > > 
> 
> > > +++ b/block/io.c
> > > @@ -159,6 +159,13 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
> > >       if (drv->bdrv_refresh_limits) {
> > >           drv->bdrv_refresh_limits(bs, errp);
> > >       }
> > > +
> > > +    /* Clamp max_transfer to 2G */
> > > +    if (bs->bl.max_transfer > UINT32_MAX) {
> > 
> > UINT32_MAX is 4G, not 2G.
> > 
> > Would it make more sense to make BDRV_REQUEST_MAX_BYTES the maximum
> > anyway?
> 
> D'oh.  Yes, that's what I intended, possibly by spelling it INT_MAX (the
> fact that the 'if' goes away in patch 13 is not an excuse for sloppy coding
> in the meantime).

INT_MAX is not a different spelling of BDRV_REQUEST_MAX_BYTES. The
latter is slightly lower (0x7ffffe00).

Kevin
Eric Blake Nov. 16, 2018, 3:54 p.m. UTC | #4
On 11/16/18 9:32 AM, Kevin Wolf wrote:
> Am 15.11.2018 um 17:28 hat Eric Blake geschrieben:
>> On 11/15/18 9:45 AM, Kevin Wolf wrote:
>>> Am 15.11.2018 um 03:03 hat Eric Blake geschrieben:
>>>> This change has no semantic impact: all drivers either leave the
>>>> value at 0 (no inherent 32-bit limit is still translated into
>>>> fragmentation below 2G; see the previous patch for that audit), or
>>>> set it to a value less than 2G.  However, switching to a larger
>>>> type and enforcing the 2G cap at the block layer makes it easier
>>>> to audit specific drivers for their robustness to larger sizing,
>>>> by letting them specify a value larger than INT_MAX if they have
>>>> been audited to be 64-bit clean.
>>>>

>>>> +
>>>> +    /* Clamp max_transfer to 2G */
>>>> +    if (bs->bl.max_transfer > UINT32_MAX) {
>>>
>>> UINT32_MAX is 4G, not 2G.
>>>
>>> Would it make more sense to make BDRV_REQUEST_MAX_BYTES the maximum
>>> anyway?
>>
>> D'oh.  Yes, that's what I intended, possibly by spelling it INT_MAX (the
>> fact that the 'if' goes away in patch 13 is not an excuse for sloppy coding
>> in the meantime).
> 
> INT_MAX is not a different spelling of BDRV_REQUEST_MAX_BYTES. The
> latter is slightly lower (0x7ffffe00).

Ah, but:

> +    if (bs->bl.max_transfer > UINT32_MAX) {
> +        bs->bl.max_transfer = QEMU_ALIGN_DOWN(BDRV_REQUEST_MAX_BYTES,
> +                                              MAX(bs->bl.opt_transfer,
> +                                                  bs->bl.request_alignment));
> +    }

QEMU_ALIGN_DOWN() will change INT_MAX to BDRV_REQUEST_MAX_BYTES if 
bs->bl.request_alignment is 512 and opt_transfer is 0; and if either 
alignment number is larger than 512, max_transfer is capped even lower 
regardless of whether I was aligning INT_MAX or BDRV_REQUEST_MAX_BYTES 
down to an alignment boundary.
Kevin Wolf Nov. 16, 2018, 4:32 p.m. UTC | #5
Am 16.11.2018 um 16:54 hat Eric Blake geschrieben:
> On 11/16/18 9:32 AM, Kevin Wolf wrote:
> > Am 15.11.2018 um 17:28 hat Eric Blake geschrieben:
> > > On 11/15/18 9:45 AM, Kevin Wolf wrote:
> > > > Am 15.11.2018 um 03:03 hat Eric Blake geschrieben:
> > > > > This change has no semantic impact: all drivers either leave the
> > > > > value at 0 (no inherent 32-bit limit is still translated into
> > > > > fragmentation below 2G; see the previous patch for that audit), or
> > > > > set it to a value less than 2G.  However, switching to a larger
> > > > > type and enforcing the 2G cap at the block layer makes it easier
> > > > > to audit specific drivers for their robustness to larger sizing,
> > > > > by letting them specify a value larger than INT_MAX if they have
> > > > > been audited to be 64-bit clean.
> > > > > 
> 
> > > > > +
> > > > > +    /* Clamp max_transfer to 2G */
> > > > > +    if (bs->bl.max_transfer > UINT32_MAX) {
> > > > 
> > > > UINT32_MAX is 4G, not 2G.
> > > > 
> > > > Would it make more sense to make BDRV_REQUEST_MAX_BYTES the maximum
> > > > anyway?
> > > 
> > > D'oh.  Yes, that's what I intended, possibly by spelling it INT_MAX (the
> > > fact that the 'if' goes away in patch 13 is not an excuse for sloppy coding
> > > in the meantime).
> > 
> > INT_MAX is not a different spelling of BDRV_REQUEST_MAX_BYTES. The
> > latter is slightly lower (0x7ffffe00).
> 
> Ah, but:
> 
> > +    if (bs->bl.max_transfer > UINT32_MAX) {
> > +        bs->bl.max_transfer = QEMU_ALIGN_DOWN(BDRV_REQUEST_MAX_BYTES,
> > +                                              MAX(bs->bl.opt_transfer,
> > +                                                  bs->bl.request_alignment));
> > +    }
> 
> QEMU_ALIGN_DOWN() will change INT_MAX to BDRV_REQUEST_MAX_BYTES if
> bs->bl.request_alignment is 512 and opt_transfer is 0; and if either
> alignment number is larger than 512, max_transfer is capped even lower
> regardless of whether I was aligning INT_MAX or BDRV_REQUEST_MAX_BYTES down
> to an alignment boundary.

That's true. But why use INT_MAX and argue that it will be rounded to
the right value later when you can just use BDRV_REQUEST_MAX_BYTES,
which is obviously correct without additional correction?

Kevin
diff mbox series

Patch

diff --git a/include/block/block_int.h b/include/block/block_int.h
index f605622216d..b19d94dac5f 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -549,9 +549,11 @@  typedef struct BlockLimits {

     /* Maximal transfer length in bytes.  Need not be power of 2, but
      * must be multiple of opt_transfer and bl.request_alignment, or 0
-     * for no 32-bit limit.  For now, anything larger than INT_MAX is
-     * clamped down. */
-    uint32_t max_transfer;
+     * for no 32-bit limit.  The block layer fragments all actions
+     * below 2G, so setting this value to anything larger than INT_MAX
+     * implies that the driver has been audited for 64-bit
+     * cleanness. */
+    uint64_t max_transfer;

     /* memory alignment, in bytes so that no bounce buffer is needed */
     size_t min_mem_alignment;
diff --git a/block/io.c b/block/io.c
index 39d4e7a3ae1..4911a1123eb 100644
--- a/block/io.c
+++ b/block/io.c
@@ -159,6 +159,13 @@  void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
     if (drv->bdrv_refresh_limits) {
         drv->bdrv_refresh_limits(bs, errp);
     }
+
+    /* Clamp max_transfer to 2G */
+    if (bs->bl.max_transfer > UINT32_MAX) {
+        bs->bl.max_transfer = QEMU_ALIGN_DOWN(BDRV_REQUEST_MAX_BYTES,
+                                              MAX(bs->bl.opt_transfer,
+                                                  bs->bl.request_alignment));
+    }
 }

 /**