qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Max Reitz <mreitz@redhat.com>
To: Maxim Levitsky <mlevitsk@redhat.com>, qemu-block@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [Qemu-block] [PATCH 2/7] block: Add blk_truncate_for_formatting()
Date: Tue, 16 Jul 2019 18:03:34 +0200	[thread overview]
Message-ID: <8887bb70-7e09-4d05-cbd1-5f972a4dc1a6@redhat.com> (raw)
In-Reply-To: <8dddcc60d9eac5535af9390e054dbfca9c08db2f.camel@redhat.com>


[-- Attachment #1.1: Type: text/plain, Size: 7407 bytes --]

On 16.07.19 17:45, Maxim Levitsky wrote:
> On Tue, 2019-07-16 at 16:08 +0300, Maxim Levitsky wrote:
>> On Fri, 2019-07-12 at 19:35 +0200, Max Reitz wrote:
>>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>>> ---
>>>  include/sysemu/block-backend.h | 12 ++++++++
>>>  block/block-backend.c          | 54 ++++++++++++++++++++++++++++++++++
>>>  2 files changed, 66 insertions(+)
>>>
>>> diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
>>> index 733c4957eb..cd9ec8bf52 100644
>>> --- a/include/sysemu/block-backend.h
>>> +++ b/include/sysemu/block-backend.h
>>> @@ -236,6 +236,18 @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
>>>                            int bytes);
>>>  int blk_truncate(BlockBackend *blk, int64_t offset, PreallocMode prealloc,
>>>                   Error **errp);
>>> +
>>> +/**
>>> + * Wrapper of blk_truncate() for format drivers that need to truncate
>>> + * their protocol node before formatting it.
>>> + * Invoke blk_truncate() to truncate the file to @offset; if that
>>> + * fails with -ENOTSUP (and the file is already big enough), try to
>>> + * overwrite the first sector with zeroes.  If that succeeds, return
>>> + * success.
>>> + */
>>> +int blk_truncate_for_formatting(BlockBackend *blk, int64_t offset,
>>> +                                Error **errp);
>>> +
>>>  int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
>>>  int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
>>>                       int64_t pos, int size);
>>> diff --git a/block/block-backend.c b/block/block-backend.c
>>> index a8d160fd5d..c0e64b1ee1 100644
>>> --- a/block/block-backend.c
>>> +++ b/block/block-backend.c
>>> @@ -2041,6 +2041,60 @@ int blk_truncate(BlockBackend *blk, int64_t offset, PreallocMode prealloc,
>>>      return bdrv_truncate(blk->root, offset, prealloc, errp);
>>>  }
>>>  
>>> +int blk_truncate_for_formatting(BlockBackend *blk, int64_t offset, Error **errp)
>>> +{
>>> +    Error *local_err = NULL;
>>> +    int64_t current_size;
>>> +    int bytes_to_clear;
>>> +    int ret;
>>> +
>>> +    ret = blk_truncate(blk, offset, PREALLOC_MODE_OFF, &local_err);
>>> +    if (ret < 0 && ret != -ENOTSUP) {
>>> +        error_propagate(errp, local_err);
>>> +        return ret;
>>> +    } else if (ret >= 0) {
>>> +        return ret;
>>> +    }
>>
>> What if the truncate does succeed? For example the current implementation of raw_co_truncate,
>> does return zero when you truncate to less that block device size 
>> (and this is kind of wrong since you can't really change the block device size)

Ah, yes, stupid me.

>> Even more, I see is that in the later patch, you call this with offset == 0 which
>> I think will always succeed on a raw block device, thus skipping the zeroing code.
>>
>> How about just doing the zeroing in the bdrv_create_file_fallback?

Hm.  I can try.  The block drivers that use
blk_truncate_for_formatting() write a full header to the image file, so
they don’t need the sector be zero.

Alternatively, I could just treat ret == 0 the same as -ENOTSUP.  Then
the code would just go on to invoke blk_getlength() and see for itself
what to do.

>> Another idea:
>>
>> blk_truncate_for_formatting would first truncate the file to 0, then
>> check if the size of the file became zero in addition to the successful return value.
>>
>> If the file size became zero, truncate the file to the requested size - this should make sure that file is empty.
>> Otherwise, zero the first sector.
>>
>> It might also be nice to add a check that if the size didn't became zero, that it remained the same
>> to avoid strange situations of semi broken truncate.

Hm, I would expect the block device to handle that.  A state between
“successful resize” and “did not change at all, as intended for this
device” should always be an error.

But the device should zero the first cluster like we do here.

>> Also I would rename the function to something like blk_raw_format_file,
>> basically a function which tries its best to erase an existing file contents
>>
>>
>> Yet another idea would to drop the lying in the raw_co_truncate (on block devices), and fail always,
>> unless asked to truncate to the exact file size, and let the callers deal with that.
>> Callers where it is not critical for the truncate to work can just ignore this failure.
>> That is probably hard to implement 
>>
>> Or we can add a truncate 'mode' to .bdrv_co_truncate, which would let the caller indicate its intention,
>> that is if the caller must truncate to that size or it can accept truncate ending up in bigger file that it asked for.

Hm.  That sounds interesting.  Currently, qemu-img resize tries to
inquire whether the truncate did anything useful by checking the length
post-truncate.  It prints a warning if the size didn’t change.

Adding a flag would simplify that and probably this, so that sounds
useful indeed.

>> As we once discussed on IRC, the fact that truncate on a block device 'succeeds',
>> despite not really beeing able to change the block device size, causes other issues,
>> like not beeing able to use preallocation=full when creating a qcow2 image on a block device.
>>
>> Best regards,
>> 	Maxim Levitsky
>>
>>> +
>>> +    current_size = blk_getlength(blk);
>>> +    if (current_size < 0) {
>>> +        error_free(local_err);
>>> +        error_setg_errno(errp, -current_size,
>>> +                         "Failed to inquire new image file's current length");
>>> +        return current_size;
>>> +    }
>>> +
>>> +    if (current_size < offset) {
>>> +        /* Need to grow the image, but we failed to do that */
>>> +        error_propagate(errp, local_err);
>>> +        return -ENOTSUP;
>>> +    }
>>> +
>>> +    error_free(local_err);
>>> +    /*
>>> +     * We can deal with images that are too big.  We just need to
>>> +     * clear the first sector.
>>> +     */
>>> +
>>> +    bytes_to_clear = MIN(current_size, BDRV_SECTOR_SIZE) - offset;
> Also this I think is wrong when offset !=0, since assuming real world device, the
> MIN will be just BDRV_SECTOR_SIZE, so the result of this statement is negative number.

Oh, damn, yes.  Thanks!

> I think you want just
> bytes_to_clear = MIN(current_size, BDRV_SECTOR_SIZE);

I don’t think I want that because I want to start clearing from @offset,
so I do need to subtract it.

But of course I don’t need to do anything if @offset >=
BDRV_SECTOR_SIZE, so there should just be an additional if () block.

Max

>>> +    if (bytes_to_clear) {
>>> +        if (!(blk->root->perm & BLK_PERM_WRITE)) {
>>> +            error_setg(errp, "Cannot clear first sector of new image: "
>>> +                       "Write permission missing");
>>> +            return -EPERM;
>>> +        }
>>> +
>>> +        ret = blk_pwrite_zeroes(blk, offset, bytes_to_clear, 0);
>>> +        if (ret < 0) {
>>> +            error_setg_errno(errp, -ret, "Failed to clear the first sector of "
>>> +                             "the new image");
>>> +            return ret;
>>> +        }
>>> +    }
>>> +
>>> +    return 0;
>>> +}
>>> +
>>>  static void blk_pdiscard_entry(void *opaque)
>>>  {
>>>      BlkRwCo *rwco = opaque;
>>
>>
> 
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

  reply	other threads:[~2019-07-16 16:03 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-12 17:35 [Qemu-devel] [PATCH 0/7] block: Generic file creation fallback Max Reitz
2019-07-12 17:35 ` [Qemu-devel] [PATCH 1/7] block/nbd: Fix hang in .bdrv_close() Max Reitz
2019-07-16 13:08   ` [Qemu-devel] [Qemu-block] " Maxim Levitsky
2019-07-12 17:35 ` [Qemu-devel] [PATCH 2/7] block: Add blk_truncate_for_formatting() Max Reitz
2019-07-16 13:08   ` [Qemu-devel] [Qemu-block] " Maxim Levitsky
2019-07-16 15:45     ` Maxim Levitsky
2019-07-16 16:03       ` Max Reitz [this message]
2019-07-12 17:35 ` [Qemu-devel] [PATCH 3/7] block: Use blk_truncate_for_formatting() Max Reitz
2019-07-16 13:08   ` [Qemu-devel] [Qemu-block] " Maxim Levitsky
2019-07-12 17:35 ` [Qemu-devel] [PATCH 4/7] block: Generic file creation fallback Max Reitz
2019-07-16 13:09   ` [Qemu-devel] [Qemu-block] " Maxim Levitsky
2019-07-12 17:35 ` [Qemu-devel] [PATCH 5/7] file-posix: Drop hdev_co_create_opts() Max Reitz
2019-07-16 13:09   ` [Qemu-devel] [Qemu-block] " Maxim Levitsky
2019-07-12 17:35 ` [Qemu-devel] [PATCH 6/7] iscsi: Drop iscsi_co_create_opts() Max Reitz
2019-07-16 13:08   ` [Qemu-devel] [Qemu-block] " Maxim Levitsky
2019-07-12 17:36 ` [Qemu-devel] [PATCH 7/7] iotests: Add test for image creation fallback Max Reitz
2019-07-15  9:31   ` Thomas Huth
2019-07-15  9:48     ` Max Reitz
2019-07-16 14:10       ` Eric Blake
2019-09-05 13:30 ` [Qemu-devel] [Qemu-block] [PATCH 0/7] block: Generic file " Maxim Levitsky
2019-09-10  9:16   ` Max Reitz
2019-09-10 10:40     ` Maxim Levitsky

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8887bb70-7e09-4d05-cbd1-5f972a4dc1a6@redhat.com \
    --to=mreitz@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=mlevitsk@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).