From: Pavel Hrdina <phrdina@redhat.com>
To: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Cc: kwolf@redhat.com, stefanha@gmail.com, qemu-devel@nongnu.org,
armbru@redhat.com, pbonzini@redhat.com, lcapitulino@redhat.com
Subject: Re: [Qemu-devel] [PATCH 4/7] block: distinguish id and name in bdrv_find_snapshot()
Date: Thu, 02 May 2013 23:12:15 +0200 [thread overview]
Message-ID: <5182D6AF.6000001@redhat.com> (raw)
In-Reply-To: <5181C933.2050708@linux.vnet.ibm.com>
On 2.5.2013 04:02, Wenchao Xia wrote:
> 于 2013-5-1 2:16, Eric Blake 写道:
>> On 04/26/2013 03:31 AM, Wenchao Xia wrote:
>>> To make it clear about id and name in searching, the API is changed
>>> a bit to distinguish them, and caller can choose to search by id or
>>> name.
>>> If not found, *errp will be set to tip why.
>>>
>>> Note that the caller logic is changed a bit:
>>> 1) In del_existing_snapshots() called by do_savevm(), it travers twice
>>> to find the snapshot, instead once, so matching sequence may change
>>> if there are unwisely chosen, mixed id and names.
>>> 2) In do_savevm(), same with del_existing_snapshot(), when it tries to
>>> find the snapshot to overwrite, matching sequence may change for same
>>> reason.
>>> 3) In load_vmstate(), first when it tries to find the snapshot to be
>>> loaded,
>>> sequence may change for the same reason of above. Later in
>>> validation, the
>>> logic is changed to be more strict to require both id and name matching.
>>> 4) In do_info_snapshot(), in validation, the logic is changed to be more
>>> strict to require both id and name matching.
>>>
>>> Savevm, loadvm logic may need to be improved later, to avoid mixing
>>> of them.
>>>
>>> Some code is borrowed from Pavel's patch.
>>>
>>> Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
>>> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
>>> ---
>>> block/snapshot.c | 72
>>> +++++++++++++++++++++++++++++++++++++++-------
>>> include/block/snapshot.h | 5 ++-
>>> savevm.c | 35 ++++++++++++----------
>>> 3 files changed, 83 insertions(+), 29 deletions(-)
>>
>>> + *
>>> + * Returns: true when a snapshot is found and @sn_info will be
>>> filled, false
>>> + * when error or not found with @errp filled if errp != NULL.
>>> + */
>>> +bool bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo
>>> *sn_info,
>>> + const char *id, const char *name, Error **errp)
>>
>> Unusual convention to have (input, output, input, input, output)
>> parameters; as long as you are changing the signature, I'd consider
>> putting all input parameters (bs, id, name) firs, then output parameters
>> last (sn_info, errp).
>>
>>> {
>>> QEMUSnapshotInfo *sn_tab, *sn;
>>> - int nb_sns, i, ret;
>>> + int nb_sns, i;
>>> + bool ret = false;
>>>
>>> - ret = -ENOENT;
>>> nb_sns = bdrv_snapshot_list(bs, &sn_tab);
>>> if (nb_sns < 0) {
>>> - return ret;
>>> + error_setg_errno(errp, -nb_sns, "Failed to get a snapshot
>>> list");
>>> + return false;
>>> + } else if (nb_sns == 0) {
>>> + error_setg(errp, "Device has no snapshots");
>>> + return false;
>>> }
>>> - for (i = 0; i < nb_sns; i++) {
>>> - sn = &sn_tab[i];
>>> - if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
>>> - *sn_info = *sn;
>>> - ret = 0;
>>> - break;
>>> +
>>
>> No assertion that at least one of id or name is provided,...
>>
>>> +
>>> + if (id && name) {
>>> + for (i = 0; i < nb_sns; i++) {
>>> + sn = &sn_tab[i];
>>> + if (!strcmp(sn->id_str, id) && !strcmp(sn->name, name)) {
>>> + *sn_info = *sn;
>>> + ret = true;
>>> + break;
>>> + }
>>> + }
>>> + } else if (id) {
>>> + for (i = 0; i < nb_sns; i++) {
>>> + sn = &sn_tab[i];
>>> + if (!strcmp(sn->id_str, id)) {
>>> + *sn_info = *sn;
>>> + ret = true;
>>> + break;
>>> + }
>>> + }
>>> + } else if (name) {
>>> + for (i = 0; i < nb_sns; i++) {
>>> + sn = &sn_tab[i];
>>> + if (!strcmp(sn->name, name)) {
>>> + *sn_info = *sn;
>>> + ret = true;
>>> + break;
>>> + }
>>> }
>>> }
>>> +
>>> + if (!ret) {
>>> + error_setg(errp, "Device have no matching snapshot");
>>> + }
>>
>> ...therefore, if I call bdrv_snapshot_find(bs, &info, NULL, NULL, errp),
>> I'll get this error. Seems okay.
>>
>>> +++ b/savevm.c
>>> @@ -2286,8 +2286,8 @@ static int del_existing_snapshots(Monitor *mon,
>>> const char *name)
>>> bs = NULL;
>>> while ((bs = bdrv_next(bs))) {
>>> if (bdrv_can_snapshot(bs) &&
>>> - bdrv_snapshot_find(bs, snapshot, name) >= 0)
>>> - {
>>> + (bdrv_snapshot_find(bs, snapshot, name, NULL, NULL) ||
>>> + bdrv_snapshot_find(bs, snapshot, NULL, name, NULL))) {
>>
>> This does an id lookup first, and falls back to a name lookup. Is that
>> what we want? Consider an image with the following snapshots:
>>
>> id 1 name 2
>> id 2 name 3
>> id 3 name 1
>> id 4 name 5
>>
>> Pre-patch, find(1) gives id 1, find(2) gives id 1, find(3) gives id 2,
>> find(4) gives id 4, find(5) gives id 4; no way to get id 3. Post-patch,
>> find(1,NULL) gives id 1, find(2,NULL) gives id 2, find(3,NULL) gives id
>> 3, find(4,NULL) gives id 4, find(5,NULL) fails and you fall back to
>> find(NULL,5) to give id 4. Thus, it only makes a difference for
>> snapshots whose name is a numeric string that also matches an id, where
>> your change now favors the id lookup over the entire set instead of the
>> first name or id match while doing a single pass over the set.
>>
>> Pavel's series on top of this would change the code to favor a name-only
>> lookup, or an explicit HMP option to do an id-only lookup, instead of
>> this code's double lookup.
>>
>> At this point, I'm okay with the semantics of this patch (especially
>> since we may be cleaning it up further in Pavel's patch series), but it
>> deserves explicit documentation in the commit message on what semantics
>> are changing (favoring id more strongly) and why (so that we can select
>> all possible snapshots, instead of being unable to select snapshots
>> whose id was claimed as a name of an earlier snapshot).
>>
> To avoid trouble, I think a new function named
> bdrv_snapshot_find_by_id_and_name() is better. Later Pavel
> can directly call this new function, and after that we can
> delete original bdrv_snapshot_find(). Pavel, what do you
> think?
Yes, we can create a new function with the new logic and the old one
will be dropped in my patch series. That's why I removed the old find
logic in my patch series in the last patch.
>
>>> @@ -2437,12 +2437,14 @@ int load_vmstate(const char *name)
>>> @@ -2461,11 +2463,11 @@ int load_vmstate(const char *name)
>>> return -ENOTSUP;
>>> }
>>>
>>> - ret = bdrv_snapshot_find(bs, &sn, name);
>>> - if (ret < 0) {
>>> + /* vm snapshot will always have same id and name, check
>>> do_savevm(). */
>>> + if (!bdrv_snapshot_find(bs, &sn, sn.id_str, sn.name, NULL)) {
>>> error_report("Device '%s' does not have the requested
>>> snapshot '%s'",
>>> bdrv_get_device_name(bs), name);
>>> - return ret;
>>> + return -ENOENT;
>>> }
>>
>> Are we 100% sure that a given snapshot name has the same id across all
>> block devices? Or is it possible to have:
>>
>> disk a: [id 1 name A, id 2 name B]
>> disk b: [id 1 name B]
>>
>> where it is possible to load snapshot [B] and get consistent state? If
>> it is possible to have non-matched ids across same-name snapshots, then
>> looking up by requiring a match of both id and name will fail, whereas
>> the pre-patch code would succeed.
>>
> not possible, I checked the existing code, a loadable snapshot, that
> is the one with vmstate, will always have same id and name, see savevm
> logic and qcow2's snapshot creation code.
> What changes is: previous, in "info snapshot", it will try show some
> snapshot that may have the situation you described above, which may be
> brought by qemu-img or hotplug operation, and which can't be loaded in
> "loadvm". Now it will be filtered out.
> Maybe there are more complicated case, but I think let management
> stack handling it, is a better option.
>
>
>>> }
>>>
>>> @@ -2536,7 +2538,7 @@ void do_info_snapshots(Monitor *mon, const
>>> QDict *qdict)
>>> {
>>> BlockDriverState *bs, *bs1;
>>> QEMUSnapshotInfo *sn_tab, *sn, s, *sn_info = &s;
>>> - int nb_sns, i, ret, available;
>>> + int nb_sns, i, available;
>>> int total;
>>> int *available_snapshots;
>>> char buf[256];
>>> @@ -2567,8 +2569,9 @@ void do_info_snapshots(Monitor *mon, const
>>> QDict *qdict)
>>>
>>> while ((bs1 = bdrv_next(bs1))) {
>>> if (bdrv_can_snapshot(bs1) && bs1 != bs) {
>>> - ret = bdrv_snapshot_find(bs1, sn_info, sn->id_str);
>>> - if (ret < 0) {
>>> + /* vm snapshot will always have same id and name */
>>> + if (!bdrv_snapshot_find(bs1, sn_info,
>>> + sn->id_str, sn->name, NULL)) {
>>
>> Again, is this true, or are you needlessly filtering out snapshots that
>> have a consistent name but non-matching ids?
>>
>
>
next prev parent reply other threads:[~2013-05-02 21:12 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-04-26 9:31 [Qemu-devel] [PATCH 0/7] qapi and snapshot code clean up in block layer Wenchao Xia
2013-04-26 9:31 ` [Qemu-devel] [PATCH 1/7] block: drop bs_snapshots global variable Wenchao Xia
2013-04-26 9:31 ` [Qemu-devel] [PATCH 2/7] block: move bdrv_snapshot_find() to block/snapshot.c Wenchao Xia
2013-04-26 9:31 ` [Qemu-devel] [PATCH 3/7] block: move snapshot code in block.c " Wenchao Xia
2013-04-26 19:05 ` Eric Blake
2013-04-26 9:31 ` [Qemu-devel] [PATCH 4/7] block: distinguish id and name in bdrv_find_snapshot() Wenchao Xia
2013-04-26 14:34 ` Stefan Hajnoczi
2013-04-26 14:47 ` Eric Blake
2013-04-27 3:34 ` Wenchao Xia
2013-04-30 17:52 ` Eric Blake
2013-04-30 18:16 ` Eric Blake
2013-05-02 2:02 ` Wenchao Xia
2013-05-02 21:12 ` Pavel Hrdina [this message]
2013-04-26 9:31 ` [Qemu-devel] [PATCH 5/7] block: move collect_snapshots() and collect_image_info() to block/qapi.c Wenchao Xia
2013-04-26 9:31 ` [Qemu-devel] [PATCH 6/7] block: move qmp and info dump related code " Wenchao Xia
2013-04-30 17:50 ` Eric Blake
2013-04-26 9:31 ` [Qemu-devel] [PATCH 7/7] block: dump to monitor for bdrv_snapshot_dump() and bdrv_image_info_dump() Wenchao Xia
2013-04-26 14:46 ` Stefan Hajnoczi
2013-04-27 3:37 ` Wenchao Xia
2013-04-29 19:05 ` Luiz Capitulino
2013-05-02 2:05 ` Wenchao Xia
2013-05-02 12:02 ` Luiz Capitulino
2013-05-03 2:51 ` Wenchao Xia
2013-05-06 2:09 ` Wenchao Xia
2013-05-06 13:22 ` Luiz Capitulino
2013-05-15 2:10 ` Wenchao Xia
2013-05-15 12:28 ` Luiz Capitulino
2013-05-16 2:22 ` Wenchao Xia
2013-05-16 12:17 ` Luiz Capitulino
2013-05-17 3:30 ` Wenchao Xia
2013-05-17 12:30 ` Luiz Capitulino
2013-05-20 2:39 ` Wenchao Xia
2013-05-22 2:09 ` Wenchao Xia
2013-05-22 12:23 ` Luiz Capitulino
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=5182D6AF.6000001@redhat.com \
--to=phrdina@redhat.com \
--cc=armbru@redhat.com \
--cc=kwolf@redhat.com \
--cc=lcapitulino@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@gmail.com \
--cc=xiawenc@linux.vnet.ibm.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).