qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Max Reitz <mreitz@redhat.com>
To: Zhang Haoyu <zhanghy@sangfor.com>, Eric Blake <eblake@redhat.com>,
	qemu-devel <qemu-devel@nongnu.org>
Cc: Kevin Wolf <kwolf@redhat.com>, Stefan Hajnoczi <stefanha@gmail.com>
Subject: Re: [Qemu-devel] [question] is it possible that big-endian l1 tableoffsetreferenced by other I/O while updating l1 table offset in qcow2_update_snapshot_refcount?
Date: Mon, 13 Oct 2014 10:02:52 +0200	[thread overview]
Message-ID: <543B872C.4090104@redhat.com> (raw)
In-Reply-To: <201410131513365349242@sangfor.com>

Am 13.10.2014 um 09:13 schrieb Zhang Haoyu:
>>>>>>> Hi,
>>>>>>> I encounter a problem that after deleting snapshot, the qcow2 image size is very larger than that it should be displayed by ls command,
>>>>>>> but the virtual disk size is okay via qemu-img info.
>>>>>>> I suspect that during updating l1 table offset, other I/O job reference the big-endian l1 table offset (very large value),
>>>>>>> so the file is truncated to very large.
>>>>>> Not quite.  Rather, all the data that the snapshot used to occupy is
>>>>>> still consuming holes in the file; the maximum offset of the file is
>>>>>> still unchanged, even if the file is no longer using as many referenced
>>>>>> clusters.  Recent changes have gone in to sparsify the file when
>>>>>> possible (punching holes if your kernel and file system is new enough to
>>>>>> support that), so that it is not consuming the amount of disk space that
>>>>>> a mere ls reports.  But if what you are asking for is a way to compact
>>>>>> the file back down, then you'll need to submit a patch.  The idea of
>>>>>> having an online defragmenter for qcow2 files has been kicked around
>>>>>> before, but it is complex enough that no one has attempted a patch yet.
>>>>> Sorry, I didn't clarify the problem clearly.
>>>>> In qcow2_update_snapshot_refcount(), below code,
>>>>>        /* Update L1 only if it isn't deleted anyway (addend = -1) */
>>>>>        if (ret == 0 && addend >= 0 && l1_modified) {
>>>>>            for (i = 0; i < l1_size; i++) {
>>>>>                cpu_to_be64s(&l1_table[i]);
>>>>>            }
>>>>>
>>>>>            ret = bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table, l1_size2);
>>>>>
>>>>>            for (i = 0; i < l1_size; i++) {
>>>>>                be64_to_cpus(&l1_table[i]);
>>>>>            }
>>>>>        }
>>>>> between cpu_to_be64s(&l1_table[i]); and be64_to_cpus(&l1_table[i]);,
>>>>> is it possible that there is other I/O reference this interim l1 table whose entries contain the be64 l2 table offset?
>>>>> The be64 l2 table offset maybe a very large value, hundreds of TB is possible,
>>>>> then the qcow2 file will be truncated to far larger than normal size.
>>>>> So we'll see the huge size of the qcow2 file by ls -hl, but the size is still normal displayed by qemu-img info.
>>>>>
>>>>> If the possibility mentioned above exists, below raw code may fix it,
>>>>>         if (ret == 0 && addend >= 0 && l1_modified) {
>>>>>            tmp_l1_table = g_malloc0(l1_size * sizeof(uint64_t))
>>>>>            memcpy(tmp_l1_table, l1_table, l1_size * sizeof(uint64_t));
>>>>>            for (i = 0; i < l1_size; i++) {
>>>>>                cpu_to_be64s(&tmp_l1_table[i]);
>>>>>            }
>>>>>            ret = bdrv_pwrite_sync(bs->file, l1_table_offset, tmp_l1_table, l1_size2);
>>>>>
>>>>>            free(tmp_l1_table);
>>>>>        }
>>>> l1_table is already a local variable (local to
>>>> qcow2_update_snapshot_refcount()), so I can't really imagine how
>>>> introducing another local buffer should mitigate the problem, if there
>>>> is any.
>>>>
>>> l1_table is not necessarily a local variable to qcow2_update_snapshot_refcount,
>>> which depends on condition of "if (l1_table_offset != s->l1_table_offset)",
>>> if the condition not true, l1_table = s->l1_table.
>> Oh, yes, you're right. Okay, so in theory nothing should happen anyway,
>> because qcow2 does not have to be reentrant (so s->l1_table will not be
>> accessed while it's big endian and therefore possibly not in CPU order).
> Could you detail how qcow2 does not have to be reentrant?
> In below stack,
> qcow2_update_snapshot_refcount
> |- cpu_to_be64s(&l1_table[i])
> |- bdrv_pwrite_sync

This is executed on bs->file, not the qcow2 BDS.

Max

> |-- bdrv_pwrite
> |--- bdrv_pwritev
> |---- bdrv_prwv_co
> |----- aio_poll(aio_context) <== this aio_context is qemu_aio_context
> |------ aio_dispatch
> |------- bdrv_co_io_em_complete
> |-------- qemu_coroutine_enter(co->coroutine, NULL); <== coroutine entry is bdrv_co_do_rw
> bdrv_co_do_rw will access l1_table to perform I/O operation.
>
> Thanks,
> Zhang Haoyu
>> But I find it rather ugly to convert the cached L1 table to big endian,
>> so I'd be fine with the patch you proposed.
>>
>> Max

  reply	other threads:[~2014-10-13  8:03 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-10-09 11:17 [Qemu-devel] [question] is it posssible that big-endian l1 table offset referenced by other I/O while updating l1 table offset in qcow2_update_snapshot_refcount? Zhang Haoyu
2014-10-09 14:58 ` Eric Blake
2014-10-10  1:54 ` [Qemu-devel] [question] is it possible " Zhang Haoyu
2014-10-12 13:23   ` Max Reitz
2014-10-13  3:17     ` [Qemu-devel] [question] is it possible that big-endian l1 tableoffset " Zhang Haoyu
2014-10-13  6:40       ` Max Reitz
2014-10-13  7:13         ` [Qemu-devel] [question] is it possible that big-endian l1 tableoffsetreferenced " Zhang Haoyu
2014-10-13  8:02           ` Max Reitz [this message]
2014-10-13  8:19             ` [Qemu-devel] [question] is it possible that big-endian l1 tableoffsetreferencedby " Zhang Haoyu
2014-10-13  9:00               ` Max Reitz
2014-10-14  1:55                 ` [Qemu-devel] [question] is it possible that big-endian l1tableoffsetreferencedby other I/O while updating l1 table offset inqcow2_update_snapshot_refcount? Zhang Haoyu

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=543B872C.4090104@redhat.com \
    --to=mreitz@redhat.com \
    --cc=eblake@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@gmail.com \
    --cc=zhanghy@sangfor.com \
    /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).