* [PATCH v6 00/11] Exposing backing-chain allocation over NBD
@ 2020-10-27 5:05 Eric Blake
2020-10-27 5:05 ` [PATCH v6 01/11] block: Simplify QAPI_LIST_ADD Eric Blake
` (10 more replies)
0 siblings, 11 replies; 28+ messages in thread
From: Eric Blake @ 2020-10-27 5:05 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, pkrempa, qemu-block, armbru, rjones, vsementsov, stefanha
v5 was here:
https://lists.gnu.org/archive/html/qemu-devel/2020-10/msg07124.html
Also available at:
https://repo.or.cz/qemu/ericb.git/shortlog/refs/tags/nbd-alloc-depth-v6
Since v5:
- rebase to master (mostly affects 8/11) [Vladimir]
- drop v5 1/12, and replace with new v6 1/11 [Markus]
- rearrange series to complete 'bitmaps' before 'allocation-depth'
- don't alter 'nbd-server-add' [Peter]
- simplify qemu:allocation-depth to just be an integer [Vladimir]
I want at least 1-7/11 in a pull request this week for 5.2 soft
freeze, but it would also be nice to get the feature of 8-10/11 in as
well. 11/11 is less important, but a nice followup to 2/11.
(Oh, and my KVM Forum presentation this Friday uses these patches ;)
Eric Blake (11):
block: Simplify QAPI_LIST_ADD
qapi: Make QAPI_LIST_ADD() public
nbd: Utilize QAPI_CLONE for type conversion
nbd: Update qapi to support exporting multiple bitmaps
nbd: Simplify qemu bitmap context name
nbd: Refactor counting of metadata contexts
nbd: Allow export of multiple bitmaps for one device
block: Return depth level during bdrv_is_allocated_above
nbd: Add new qemu:allocation-depth metadata context
nbd: Add 'qemu-nbd -A' to expose allocation depth
qapi: Use QAPI_LIST_ADD() where possible
docs/devel/writing-qmp-commands.txt | 13 +-
docs/interop/nbd.txt | 23 ++-
docs/system/deprecated.rst | 3 +-
docs/tools/qemu-nbd.rst | 8 +-
qapi/block-core.json | 7 +-
qapi/block-export.json | 46 ++++--
block/coroutines.h | 6 +-
hw/net/rocker/rocker_fp.h | 2 +-
include/block/nbd.h | 8 +-
include/qapi/util.h | 8 ++
block/io.c | 29 +++-
block.c | 14 +-
block/commit.c | 2 +-
block/gluster.c | 19 +--
block/mirror.c | 2 +-
block/nbd.c | 26 +++-
block/stream.c | 2 +-
blockdev-nbd.c | 19 +--
chardev/char.c | 21 ++-
hw/core/machine.c | 6 +-
hw/net/rocker/rocker.c | 8 +-
hw/net/rocker/rocker_fp.c | 14 +-
hw/net/virtio-net.c | 21 +--
migration/migration.c | 7 +-
migration/postcopy-ram.c | 7 +-
monitor/hmp-cmds.c | 11 +-
nbd/server.c | 208 +++++++++++++++++++++-------
qemu-img.c | 5 +-
qemu-nbd.c | 30 ++--
qga/commands-posix.c | 13 +-
qga/commands-win32.c | 17 +--
qga/commands.c | 6 +-
qom/qom-qmp-cmds.c | 29 ++--
target/arm/helper.c | 6 +-
target/arm/monitor.c | 13 +-
target/i386/cpu.c | 6 +-
target/mips/helper.c | 6 +-
target/s390x/cpu_models.c | 12 +-
tests/test-clone-visitor.c | 7 +-
tests/test-qobject-output-visitor.c | 42 +++---
tests/test-visitor-serialization.c | 5 +-
trace/qmp.c | 22 ++-
ui/vnc.c | 21 +--
util/qemu-config.c | 14 +-
target/ppc/translate_init.c.inc | 12 +-
tests/qemu-iotests/291 | 6 +-
tests/qemu-iotests/309 | 77 ++++++++++
tests/qemu-iotests/309.out | 22 +++
tests/qemu-iotests/group | 1 +
49 files changed, 542 insertions(+), 370 deletions(-)
create mode 100755 tests/qemu-iotests/309
create mode 100644 tests/qemu-iotests/309.out
--
2.29.0
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v6 01/11] block: Simplify QAPI_LIST_ADD
2020-10-27 5:05 [PATCH v6 00/11] Exposing backing-chain allocation over NBD Eric Blake
@ 2020-10-27 5:05 ` Eric Blake
2020-10-27 10:06 ` Vladimir Sementsov-Ogievskiy
2020-10-27 12:58 ` Markus Armbruster
2020-10-27 5:05 ` [PATCH v6 02/11] qapi: Make QAPI_LIST_ADD() public Eric Blake
` (9 subsequent siblings)
10 siblings, 2 replies; 28+ messages in thread
From: Eric Blake @ 2020-10-27 5:05 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, pkrempa, qemu-block, armbru, rjones, vsementsov, stefanha,
Max Reitz
There is no need to rely on the verbosity of the gcc/clang compiler
extension of g_new(typeof(X), 1) when we can instead use the standard
g_malloc(sizeof(X)). In general, we like g_new over g_malloc for
returning type X rather than void* to let the compiler catch more
potential typing mistakes, but in this particular macro, our other use
of typeof on the same line already ensures we are getting correct
results.
Suggested-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
---
block.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/block.c b/block.c
index 430edf79bb10..857387f3912f 100644
--- a/block.c
+++ b/block.c
@@ -5231,7 +5231,7 @@ BlockDeviceInfoList *bdrv_named_nodes_list(bool flat,
}
#define QAPI_LIST_ADD(list, element) do { \
- typeof(list) _tmp = g_new(typeof(*(list)), 1); \
+ typeof(list) _tmp = g_malloc(sizeof(*(list))); \
_tmp->value = (element); \
_tmp->next = (list); \
(list) = _tmp; \
--
2.29.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v6 02/11] qapi: Make QAPI_LIST_ADD() public
2020-10-27 5:05 [PATCH v6 00/11] Exposing backing-chain allocation over NBD Eric Blake
2020-10-27 5:05 ` [PATCH v6 01/11] block: Simplify QAPI_LIST_ADD Eric Blake
@ 2020-10-27 5:05 ` Eric Blake
2020-10-27 5:05 ` [PATCH v6 03/11] nbd: Utilize QAPI_CLONE for type conversion Eric Blake
` (8 subsequent siblings)
10 siblings, 0 replies; 28+ messages in thread
From: Eric Blake @ 2020-10-27 5:05 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, pkrempa, Michael Roth, qemu-block, armbru, rjones,
vsementsov, stefanha, Max Reitz
We have a useful macro for inserting at the front of any
QAPI-generated list; move it from block.c to qapi/util.h so more
places can use it, including one earlier place in block.c.
There are many more places in the codebase that can benefit from using
the macro, but converting them will be left to later patches.
In theory, all QAPI list types are child classes of GenericList; but
in practice, that relationship is not explicitly spelled out in the C
type declarations (rather, it is something that happens implicitly due
to C compatible layouts), and the macro does not actually depend on
the GenericList type. We considered moving GenericList from visitor.h
into util.h to group related code; however, such a move would be
awkward if we do not also move GenericAlternate. Unfortunately,
moving GenericAlternate would introduce its own problems of
declaration circularity (qapi-builtin-types.h needs a complete
definition of QEnumLookup from util.h, but GenericAlternate needs a
complete definition of QType from qapi-builtin-types.h).
Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
---
include/qapi/util.h | 8 ++++++++
block.c | 14 ++------------
2 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/include/qapi/util.h b/include/qapi/util.h
index a7c3c6414874..501abca38eaa 100644
--- a/include/qapi/util.h
+++ b/include/qapi/util.h
@@ -22,4 +22,12 @@ int qapi_enum_parse(const QEnumLookup *lookup, const char *buf,
int parse_qapi_name(const char *name, bool complete);
+/* For any GenericList @list, insert @element at the front. */
+#define QAPI_LIST_ADD(list, element) do { \
+ typeof(list) _tmp = g_malloc(sizeof(*(list))); \
+ _tmp->value = (element); \
+ _tmp->next = (list); \
+ (list) = _tmp; \
+} while (0)
+
#endif
diff --git a/block.c b/block.c
index 857387f3912f..8f9df5547d5a 100644
--- a/block.c
+++ b/block.c
@@ -5211,7 +5211,7 @@ BlockDriverState *bdrv_find_node(const char *node_name)
BlockDeviceInfoList *bdrv_named_nodes_list(bool flat,
Error **errp)
{
- BlockDeviceInfoList *list, *entry;
+ BlockDeviceInfoList *list;
BlockDriverState *bs;
list = NULL;
@@ -5221,22 +5221,12 @@ BlockDeviceInfoList *bdrv_named_nodes_list(bool flat,
qapi_free_BlockDeviceInfoList(list);
return NULL;
}
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = list;
- list = entry;
+ QAPI_LIST_ADD(list, info);
}
return list;
}
-#define QAPI_LIST_ADD(list, element) do { \
- typeof(list) _tmp = g_malloc(sizeof(*(list))); \
- _tmp->value = (element); \
- _tmp->next = (list); \
- (list) = _tmp; \
-} while (0)
-
typedef struct XDbgBlockGraphConstructor {
XDbgBlockGraph *graph;
GHashTable *graph_nodes;
--
2.29.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v6 03/11] nbd: Utilize QAPI_CLONE for type conversion
2020-10-27 5:05 [PATCH v6 00/11] Exposing backing-chain allocation over NBD Eric Blake
2020-10-27 5:05 ` [PATCH v6 01/11] block: Simplify QAPI_LIST_ADD Eric Blake
2020-10-27 5:05 ` [PATCH v6 02/11] qapi: Make QAPI_LIST_ADD() public Eric Blake
@ 2020-10-27 5:05 ` Eric Blake
2020-10-27 5:05 ` [PATCH v6 04/11] nbd: Update qapi to support exporting multiple bitmaps Eric Blake
` (7 subsequent siblings)
10 siblings, 0 replies; 28+ messages in thread
From: Eric Blake @ 2020-10-27 5:05 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, pkrempa, qemu-block, armbru, rjones, vsementsov, stefanha,
Max Reitz
Rather than open-coding the translation from the deprecated
NbdServerAddOptions type to the preferred BlockExportOptionsNbd, it's
better to utilize QAPI_CLONE_MEMBERS. This solves a couple of issues:
first, if we do any more refactoring of the base type (which an
upcoming patch plans to do), we don't have to revisit the open-coding.
Second, our assignment to arg->name is fishy: the generated QAPI code
for qapi_free_NbdServerAddOptions does not visit arg->name if
arg->has_name is false, but if it DID visit it, we would have
introduced a double-free situation when arg is finally freed.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
---
blockdev-nbd.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index 8174023e5c47..cee9134b12eb 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -14,6 +14,8 @@
#include "sysemu/block-backend.h"
#include "hw/block/block.h"
#include "qapi/error.h"
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-block-export.h"
#include "qapi/qapi-commands-block-export.h"
#include "block/nbd.h"
#include "io/channel-socket.h"
@@ -195,7 +197,8 @@ void qmp_nbd_server_add(NbdServerAddOptions *arg, Error **errp)
* the device name as a default here for compatibility.
*/
if (!arg->has_name) {
- arg->name = arg->device;
+ arg->has_name = true;
+ arg->name = g_strdup(arg->device);
}
export_opts = g_new(BlockExportOptions, 1);
@@ -205,15 +208,9 @@ void qmp_nbd_server_add(NbdServerAddOptions *arg, Error **errp)
.node_name = g_strdup(bdrv_get_node_name(bs)),
.has_writable = arg->has_writable,
.writable = arg->writable,
- .u.nbd = {
- .has_name = true,
- .name = g_strdup(arg->name),
- .has_description = arg->has_description,
- .description = g_strdup(arg->description),
- .has_bitmap = arg->has_bitmap,
- .bitmap = g_strdup(arg->bitmap),
- },
};
+ QAPI_CLONE_MEMBERS(BlockExportOptionsNbd, &export_opts->u.nbd,
+ qapi_NbdServerAddOptions_base(arg));
/*
* nbd-server-add doesn't complain when a read-only device should be
--
2.29.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v6 04/11] nbd: Update qapi to support exporting multiple bitmaps
2020-10-27 5:05 [PATCH v6 00/11] Exposing backing-chain allocation over NBD Eric Blake
` (2 preceding siblings ...)
2020-10-27 5:05 ` [PATCH v6 03/11] nbd: Utilize QAPI_CLONE for type conversion Eric Blake
@ 2020-10-27 5:05 ` Eric Blake
2020-10-27 10:29 ` Vladimir Sementsov-Ogievskiy
2020-10-27 12:37 ` Peter Krempa
2020-10-27 5:05 ` [PATCH v6 05/11] nbd: Simplify qemu bitmap context name Eric Blake
` (6 subsequent siblings)
10 siblings, 2 replies; 28+ messages in thread
From: Eric Blake @ 2020-10-27 5:05 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, pkrempa, qemu-block, reviewer:Incompatible changes, armbru,
rjones, vsementsov, stefanha, Max Reitz
Since 'block-export-add' is new to 5.2, we can still tweak the
interface; there, allowing 'bitmaps':['str'] is nicer than
'bitmap':'str'. This wires up the qapi and qemu-nbd changes to permit
passing multiple bitmaps as distinct metadata contexts that the NBD
client may request, but the actual support for more than one will
require a further patch to the server.
Note that there are no changes made to the existing deprecated
'nbd-server-add' command; this required splitting the QAPI type
BlockExportOptionsNbd, which fortunately does not affect QMP
introspection.
Signed-off-by: Eric Blake <eblake@redhat.com>
---
docs/system/deprecated.rst | 3 ++-
qapi/block-export.json | 41 +++++++++++++++++++++++++++-----------
blockdev-nbd.c | 6 +++++-
nbd/server.c | 19 ++++++++++++------
qemu-nbd.c | 18 ++++++++---------
5 files changed, 58 insertions(+), 29 deletions(-)
diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst
index 0ebce37a1919..32a0e620dbb9 100644
--- a/docs/system/deprecated.rst
+++ b/docs/system/deprecated.rst
@@ -257,7 +257,8 @@ the 'wait' field, which is only applicable to sockets in server mode
''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Use the more generic commands ``block-export-add`` and ``block-export-del``
-instead.
+instead. As part of this deprecation, where ``nbd-server-add`` used a
+single ``bitmap``, the new ``block-export-add`` uses a list of ``bitmaps``.
Human Monitor Protocol (HMP) commands
-------------------------------------
diff --git a/qapi/block-export.json b/qapi/block-export.json
index 480c497690b0..c4125f4d2104 100644
--- a/qapi/block-export.json
+++ b/qapi/block-export.json
@@ -63,10 +63,10 @@
'*max-connections': 'uint32' } }
##
-# @BlockExportOptionsNbd:
+# @BlockExportOptionsNbdBase:
#
-# An NBD block export (options shared between nbd-server-add and the NBD branch
-# of block-export-add).
+# An NBD block export (common options shared between nbd-server-add and
+# the NBD branch of block-export-add).
#
# @name: Export name. If unspecified, the @device parameter is used as the
# export name. (Since 2.12)
@@ -74,15 +74,27 @@
# @description: Free-form description of the export, up to 4096 bytes.
# (Since 5.0)
#
-# @bitmap: Also export the dirty bitmap reachable from @device, so the
-# NBD client can use NBD_OPT_SET_META_CONTEXT with
-# "qemu:dirty-bitmap:NAME" to inspect the bitmap. (since 4.0)
-#
# Since: 5.0
##
+{ 'struct': 'BlockExportOptionsNbdBase',
+ 'data': { '*name': 'str', '*description': 'str' } }
+
+##
+# @BlockExportOptionsNbd:
+#
+# An NBD block export (distinct options used in the NBD branch of
+# block-export-add).
+#
+# @bitmaps: Also export each of the named dirty bitmaps reachable from
+# @device, so the NBD client can use NBD_OPT_SET_META_CONTEXT with
+# the metadata context name "qemu:dirty-bitmap:BITMAP" to inspect
+# each bitmap.
+#
+# Since: 5.2
+##
{ 'struct': 'BlockExportOptionsNbd',
- 'data': { '*name': 'str', '*description': 'str',
- '*bitmap': 'str' } }
+ 'base': 'BlockExportOptionsNbdBase',
+ 'data': { '*bitmaps': ['str'] } }
##
# @BlockExportOptionsVhostUserBlk:
@@ -106,19 +118,24 @@
##
# @NbdServerAddOptions:
#
-# An NBD block export.
+# An NBD block export, per legacy nbd-server-add command.
#
# @device: The device name or node name of the node to be exported
#
# @writable: Whether clients should be able to write to the device via the
# NBD connection (default false).
#
+# @bitmap: Also export a single dirty bitmap reachable from @device, so the
+# NBD client can use NBD_OPT_SET_META_CONTEXT with the metadata
+# context name "qemu:dirty-bitmap:BITMAP" to inspect the bitmap
+# (since 4.0).
+#
# Since: 5.0
##
{ 'struct': 'NbdServerAddOptions',
- 'base': 'BlockExportOptionsNbd',
+ 'base': 'BlockExportOptionsNbdBase',
'data': { 'device': 'str',
- '*writable': 'bool' } }
+ '*writable': 'bool', '*bitmap': 'str' } }
##
# @nbd-server-add:
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index cee9134b12eb..d1d41f635564 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -209,8 +209,12 @@ void qmp_nbd_server_add(NbdServerAddOptions *arg, Error **errp)
.has_writable = arg->has_writable,
.writable = arg->writable,
};
- QAPI_CLONE_MEMBERS(BlockExportOptionsNbd, &export_opts->u.nbd,
+ QAPI_CLONE_MEMBERS(BlockExportOptionsNbdBase, &export_opts->u.nbd,
qapi_NbdServerAddOptions_base(arg));
+ if (arg->has_bitmap) {
+ export_opts->u.nbd.has_bitmaps = true;
+ QAPI_LIST_ADD(export_opts->u.nbd.bitmaps, g_strdup(arg->bitmap));
+ }
/*
* nbd-server-add doesn't complain when a read-only device should be
diff --git a/nbd/server.c b/nbd/server.c
index 08b621f70a3a..8d01662b4511 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -1474,6 +1474,7 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
uint64_t perm, shared_perm;
bool readonly = !exp_args->writable;
bool shared = !exp_args->writable;
+ strList *bitmaps;
int ret;
assert(exp_args->type == BLOCK_EXPORT_TYPE_NBD);
@@ -1533,12 +1534,18 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
}
exp->size = QEMU_ALIGN_DOWN(size, BDRV_SECTOR_SIZE);
- if (arg->bitmap) {
+ /* XXX Allow more than one bitmap */
+ if (arg->bitmaps && arg->bitmaps->next) {
+ error_setg(errp, "multiple bitmaps per export not supported yet");
+ return -EOPNOTSUPP;
+ }
+ for (bitmaps = arg->bitmaps; bitmaps; bitmaps = bitmaps->next) {
+ const char *bitmap = bitmaps->value;
BlockDriverState *bs = blk_bs(blk);
BdrvDirtyBitmap *bm = NULL;
while (bs) {
- bm = bdrv_find_dirty_bitmap(bs, arg->bitmap);
+ bm = bdrv_find_dirty_bitmap(bs, bitmap);
if (bm != NULL) {
break;
}
@@ -1548,7 +1555,7 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
if (bm == NULL) {
ret = -ENOENT;
- error_setg(errp, "Bitmap '%s' is not found", arg->bitmap);
+ error_setg(errp, "Bitmap '%s' is not found", bitmap);
goto fail;
}
@@ -1562,15 +1569,15 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
ret = -EINVAL;
error_setg(errp,
"Enabled bitmap '%s' incompatible with readonly export",
- arg->bitmap);
+ bitmap);
goto fail;
}
bdrv_dirty_bitmap_set_busy(bm, true);
exp->export_bitmap = bm;
- assert(strlen(arg->bitmap) <= BDRV_BITMAP_MAX_NAME_SIZE);
+ assert(strlen(bitmap) <= BDRV_BITMAP_MAX_NAME_SIZE);
exp->export_bitmap_context = g_strdup_printf("qemu:dirty-bitmap:%s",
- arg->bitmap);
+ bitmap);
assert(strlen(exp->export_bitmap_context) < NBD_MAX_STRING_SIZE);
}
diff --git a/qemu-nbd.c b/qemu-nbd.c
index a0701cdf369d..4b7825c44093 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -574,7 +574,7 @@ int main(int argc, char **argv)
QDict *options = NULL;
const char *export_name = NULL; /* defaults to "" later for server mode */
const char *export_description = NULL;
- const char *bitmap = NULL;
+ strList *bitmaps = NULL;
const char *tlscredsid = NULL;
bool imageOpts = false;
bool writethrough = true;
@@ -690,7 +690,7 @@ int main(int argc, char **argv)
flags &= ~BDRV_O_RDWR;
break;
case 'B':
- bitmap = optarg;
+ QAPI_LIST_ADD(bitmaps, g_strdup(optarg));
break;
case 'k':
sockpath = optarg;
@@ -786,7 +786,7 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
if (export_name || export_description || dev_offset ||
- device || disconnect || fmt || sn_id_or_name || bitmap ||
+ device || disconnect || fmt || sn_id_or_name || bitmaps ||
seen_aio || seen_discard || seen_cache) {
error_report("List mode is incompatible with per-device settings");
exit(EXIT_FAILURE);
@@ -1067,12 +1067,12 @@ int main(int argc, char **argv)
.has_writable = true,
.writable = !readonly,
.u.nbd = {
- .has_name = true,
- .name = g_strdup(export_name),
- .has_description = !!export_description,
- .description = g_strdup(export_description),
- .has_bitmap = !!bitmap,
- .bitmap = g_strdup(bitmap),
+ .has_name = true,
+ .name = g_strdup(export_name),
+ .has_description = !!export_description,
+ .description = g_strdup(export_description),
+ .has_bitmaps = !!bitmaps,
+ .bitmaps = bitmaps,
},
};
blk_exp_add(export_opts, &error_fatal);
--
2.29.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v6 05/11] nbd: Simplify qemu bitmap context name
2020-10-27 5:05 [PATCH v6 00/11] Exposing backing-chain allocation over NBD Eric Blake
` (3 preceding siblings ...)
2020-10-27 5:05 ` [PATCH v6 04/11] nbd: Update qapi to support exporting multiple bitmaps Eric Blake
@ 2020-10-27 5:05 ` Eric Blake
2020-10-27 5:05 ` [PATCH v6 06/11] nbd: Refactor counting of metadata contexts Eric Blake
` (5 subsequent siblings)
10 siblings, 0 replies; 28+ messages in thread
From: Eric Blake @ 2020-10-27 5:05 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, pkrempa, qemu-block, armbru, rjones, vsementsov, stefanha
Each dirty bitmap already knows its name; by reducing the scope of the
places where we construct "qemu:dirty-bitmap:NAME" strings, tracking
the name is more localized, and there are fewer per-export fields to
worry about. This in turn will make it easier for an upcoming patch
to export more than one bitmap at once.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
nbd/server.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/nbd/server.c b/nbd/server.c
index 8d01662b4511..77fdecdf9dec 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -95,7 +95,6 @@ struct NBDExport {
Notifier eject_notifier;
BdrvDirtyBitmap *export_bitmap;
- char *export_bitmap_context;
};
static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
@@ -871,14 +870,15 @@ static bool nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta,
}
if (nbd_strshift(&query, "dirty-bitmap:")) {
+ const char *bm_name;
+
trace_nbd_negotiate_meta_query_parse("dirty-bitmap:");
if (!meta->exp->export_bitmap) {
trace_nbd_negotiate_meta_query_skip("no dirty-bitmap exported");
return true;
}
- if (nbd_meta_empty_or_pattern(client,
- meta->exp->export_bitmap_context +
- strlen("qemu:dirty-bitmap:"), query)) {
+ bm_name = bdrv_dirty_bitmap_name(meta->exp->export_bitmap);
+ if (nbd_meta_empty_or_pattern(client, bm_name, query)) {
meta->bitmap = true;
}
return true;
@@ -1004,8 +1004,11 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
}
if (meta->bitmap) {
- ret = nbd_negotiate_send_meta_context(client,
- meta->exp->export_bitmap_context,
+ const char *bm_name = bdrv_dirty_bitmap_name(meta->exp->export_bitmap);
+ g_autofree char *context = g_strdup_printf("qemu:dirty-bitmap:%s",
+ bm_name);
+
+ ret = nbd_negotiate_send_meta_context(client, context,
NBD_META_ID_DIRTY_BITMAP,
errp);
if (ret < 0) {
@@ -1576,9 +1579,6 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
bdrv_dirty_bitmap_set_busy(bm, true);
exp->export_bitmap = bm;
assert(strlen(bitmap) <= BDRV_BITMAP_MAX_NAME_SIZE);
- exp->export_bitmap_context = g_strdup_printf("qemu:dirty-bitmap:%s",
- bitmap);
- assert(strlen(exp->export_bitmap_context) < NBD_MAX_STRING_SIZE);
}
blk_add_aio_context_notifier(blk, blk_aio_attached, blk_aio_detach, exp);
@@ -1656,7 +1656,6 @@ static void nbd_export_delete(BlockExport *blk_exp)
if (exp->export_bitmap) {
bdrv_dirty_bitmap_set_busy(exp->export_bitmap, false);
- g_free(exp->export_bitmap_context);
}
}
--
2.29.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v6 06/11] nbd: Refactor counting of metadata contexts
2020-10-27 5:05 [PATCH v6 00/11] Exposing backing-chain allocation over NBD Eric Blake
` (4 preceding siblings ...)
2020-10-27 5:05 ` [PATCH v6 05/11] nbd: Simplify qemu bitmap context name Eric Blake
@ 2020-10-27 5:05 ` Eric Blake
2020-10-27 10:33 ` Vladimir Sementsov-Ogievskiy
2020-10-27 5:05 ` [PATCH v6 07/11] nbd: Allow export of multiple bitmaps for one device Eric Blake
` (4 subsequent siblings)
10 siblings, 1 reply; 28+ messages in thread
From: Eric Blake @ 2020-10-27 5:05 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, pkrempa, qemu-block, armbru, rjones, vsementsov, stefanha
Rather than open-code the count of negotiated contexts at several
sites, embed it directly into the struct. This will make it easier
for upcoming commits to support even more simultaneous contexts.
Signed-off-by: Eric Blake <eblake@redhat.com>
---
nbd/server.c | 26 +++++++++++++++-----------
1 file changed, 15 insertions(+), 11 deletions(-)
diff --git a/nbd/server.c b/nbd/server.c
index 77fdecdf9dec..42d494bc9616 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -104,8 +104,7 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
* NBD_OPT_LIST_META_CONTEXT. */
typedef struct NBDExportMetaContexts {
NBDExport *exp;
- bool valid; /* means that negotiation of the option finished without
- errors */
+ size_t count; /* number of negotiated contexts */
bool base_allocation; /* export base:allocation context (block status) */
bool bitmap; /* export qemu:dirty-bitmap:<export bitmap name> */
} NBDExportMetaContexts;
@@ -445,7 +444,9 @@ static int nbd_negotiate_handle_list(NBDClient *client, Error **errp)
static void nbd_check_meta_export(NBDClient *client)
{
- client->export_meta.valid &= client->exp == client->export_meta.exp;
+ if (client->exp != client->export_meta.exp) {
+ client->export_meta.count = 0;
+ }
}
/* Send a reply to NBD_OPT_EXPORT_NAME.
@@ -945,6 +946,7 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
NBDExportMetaContexts local_meta;
uint32_t nb_queries;
int i;
+ size_t count = 0;
if (!client->structured_reply) {
return nbd_opt_invalid(client, errp,
@@ -1001,6 +1003,7 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
if (ret < 0) {
return ret;
}
+ count++;
}
if (meta->bitmap) {
@@ -1014,11 +1017,12 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
if (ret < 0) {
return ret;
}
+ count++;
}
ret = nbd_negotiate_send_rep(client, NBD_REP_ACK, errp);
if (ret == 0) {
- meta->valid = true;
+ meta->count = count;
}
return ret;
@@ -2337,18 +2341,16 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
return nbd_send_generic_reply(client, request->handle, -EINVAL,
"need non-zero length", errp);
}
- if (client->export_meta.valid &&
- (client->export_meta.base_allocation ||
- client->export_meta.bitmap))
- {
+ if (client->export_meta.count) {
bool dont_fragment = request->flags & NBD_CMD_FLAG_REQ_ONE;
+ int contexts_remaining = client->export_meta.count;
if (client->export_meta.base_allocation) {
ret = nbd_co_send_block_status(client, request->handle,
blk_bs(exp->common.blk),
request->from,
request->len, dont_fragment,
- !client->export_meta.bitmap,
+ !--contexts_remaining,
NBD_META_ID_BASE_ALLOCATION,
errp);
if (ret < 0) {
@@ -2360,13 +2362,15 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
ret = nbd_co_send_bitmap(client, request->handle,
client->exp->export_bitmap,
request->from, request->len,
- dont_fragment,
- true, NBD_META_ID_DIRTY_BITMAP, errp);
+ dont_fragment, !--contexts_remaining,
+ NBD_META_ID_DIRTY_BITMAP, errp);
if (ret < 0) {
return ret;
}
}
+ assert(!contexts_remaining);
+
return 0;
} else {
return nbd_send_generic_reply(client, request->handle, -EINVAL,
--
2.29.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v6 07/11] nbd: Allow export of multiple bitmaps for one device
2020-10-27 5:05 [PATCH v6 00/11] Exposing backing-chain allocation over NBD Eric Blake
` (5 preceding siblings ...)
2020-10-27 5:05 ` [PATCH v6 06/11] nbd: Refactor counting of metadata contexts Eric Blake
@ 2020-10-27 5:05 ` Eric Blake
2020-10-27 5:05 ` [PATCH v6 08/11] block: Return depth level during bdrv_is_allocated_above Eric Blake
` (3 subsequent siblings)
10 siblings, 0 replies; 28+ messages in thread
From: Eric Blake @ 2020-10-27 5:05 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, pkrempa, qemu-block, armbru, rjones, vsementsov, stefanha,
Max Reitz
With this, 'qemu-nbd -B b0 -B b1 -f qcow2 img.qcow2' can let you sniff
out multiple bitmaps from one server. qemu-img as client can still
only read one bitmap per client connection, but other NBD clients
(hello libnbd) can now read multiple bitmaps in a single pass.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
nbd/server.c | 100 ++++++++++++++++++++++++++++-------------
tests/qemu-iotests/291 | 6 +--
2 files changed, 72 insertions(+), 34 deletions(-)
diff --git a/nbd/server.c b/nbd/server.c
index 42d494bc9616..b6841e455414 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -27,6 +27,7 @@
#include "qemu/units.h"
#define NBD_META_ID_BASE_ALLOCATION 0
+/* Dirty bitmaps use 'NBD_META_ID_DIRTY_BITMAP + i', so keep this id last. */
#define NBD_META_ID_DIRTY_BITMAP 1
/*
@@ -94,7 +95,8 @@ struct NBDExport {
BlockBackend *eject_notifier_blk;
Notifier eject_notifier;
- BdrvDirtyBitmap *export_bitmap;
+ BdrvDirtyBitmap **export_bitmaps;
+ size_t nr_export_bitmaps;
};
static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
@@ -106,7 +108,10 @@ typedef struct NBDExportMetaContexts {
NBDExport *exp;
size_t count; /* number of negotiated contexts */
bool base_allocation; /* export base:allocation context (block status) */
- bool bitmap; /* export qemu:dirty-bitmap:<export bitmap name> */
+ bool *bitmaps; /*
+ * export qemu:dirty-bitmap:<export bitmap name>,
+ * sized by exp->nr_export_bitmaps
+ */
} NBDExportMetaContexts;
struct NBDClient {
@@ -857,6 +862,8 @@ static bool nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta,
static bool nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta,
const char *query)
{
+ size_t i;
+
if (!nbd_strshift(&query, "qemu:")) {
return false;
}
@@ -864,24 +871,33 @@ static bool nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta,
if (!*query) {
if (client->opt == NBD_OPT_LIST_META_CONTEXT) {
- meta->bitmap = !!meta->exp->export_bitmap;
+ memset(meta->bitmaps, 1, meta->exp->nr_export_bitmaps);
}
trace_nbd_negotiate_meta_query_parse("empty");
return true;
}
if (nbd_strshift(&query, "dirty-bitmap:")) {
- const char *bm_name;
-
trace_nbd_negotiate_meta_query_parse("dirty-bitmap:");
- if (!meta->exp->export_bitmap) {
- trace_nbd_negotiate_meta_query_skip("no dirty-bitmap exported");
+ if (!*query) {
+ if (client->opt == NBD_OPT_LIST_META_CONTEXT) {
+ memset(meta->bitmaps, 1, meta->exp->nr_export_bitmaps);
+ }
+ trace_nbd_negotiate_meta_query_parse("empty");
return true;
}
- bm_name = bdrv_dirty_bitmap_name(meta->exp->export_bitmap);
- if (nbd_meta_empty_or_pattern(client, bm_name, query)) {
- meta->bitmap = true;
+
+ for (i = 0; i < meta->exp->nr_export_bitmaps; i++) {
+ const char *bm_name;
+
+ bm_name = bdrv_dirty_bitmap_name(meta->exp->export_bitmaps[i]);
+ if (strcmp(bm_name, query) == 0) {
+ meta->bitmaps[i] = true;
+ trace_nbd_negotiate_meta_query_parse(query);
+ return true;
+ }
}
+ trace_nbd_negotiate_meta_query_skip("no dirty-bitmap match");
return true;
}
@@ -943,9 +959,10 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
{
int ret;
g_autofree char *export_name = NULL;
- NBDExportMetaContexts local_meta;
+ g_autofree bool *bitmaps = NULL;
+ NBDExportMetaContexts local_meta = {0};
uint32_t nb_queries;
- int i;
+ size_t i;
size_t count = 0;
if (!client->structured_reply) {
@@ -960,6 +977,7 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
meta = &local_meta;
}
+ g_free(meta->bitmaps);
memset(meta, 0, sizeof(*meta));
ret = nbd_opt_read_name(client, &export_name, NULL, errp);
@@ -974,6 +992,10 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
return nbd_opt_drop(client, NBD_REP_ERR_UNKNOWN, errp,
"export '%s' not present", sane_name);
}
+ meta->bitmaps = g_new0(bool, meta->exp->nr_export_bitmaps);
+ if (client->opt == NBD_OPT_LIST_META_CONTEXT) {
+ bitmaps = meta->bitmaps;
+ }
ret = nbd_opt_read(client, &nb_queries, sizeof(nb_queries), false, errp);
if (ret <= 0) {
@@ -986,7 +1008,7 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
if (client->opt == NBD_OPT_LIST_META_CONTEXT && !nb_queries) {
/* enable all known contexts */
meta->base_allocation = true;
- meta->bitmap = !!meta->exp->export_bitmap;
+ memset(meta->bitmaps, 1, meta->exp->nr_export_bitmaps);
} else {
for (i = 0; i < nb_queries; ++i) {
ret = nbd_negotiate_meta_query(client, meta, errp);
@@ -1006,13 +1028,19 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
count++;
}
- if (meta->bitmap) {
- const char *bm_name = bdrv_dirty_bitmap_name(meta->exp->export_bitmap);
- g_autofree char *context = g_strdup_printf("qemu:dirty-bitmap:%s",
- bm_name);
+ for (i = 0; i < meta->exp->nr_export_bitmaps; i++) {
+ const char *bm_name;
+ g_autofree char *context = NULL;
+
+ if (!meta->bitmaps[i]) {
+ continue;
+ }
+
+ bm_name = bdrv_dirty_bitmap_name(meta->exp->export_bitmaps[i]);
+ context = g_strdup_printf("qemu:dirty-bitmap:%s", bm_name);
ret = nbd_negotiate_send_meta_context(client, context,
- NBD_META_ID_DIRTY_BITMAP,
+ NBD_META_ID_DIRTY_BITMAP + i,
errp);
if (ret < 0) {
return ret;
@@ -1366,6 +1394,7 @@ void nbd_client_put(NBDClient *client)
QTAILQ_REMOVE(&client->exp->clients, client, next);
blk_exp_unref(&client->exp->common);
}
+ g_free(client->export_meta.bitmaps);
g_free(client);
}
}
@@ -1482,6 +1511,7 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
bool readonly = !exp_args->writable;
bool shared = !exp_args->writable;
strList *bitmaps;
+ size_t i;
int ret;
assert(exp_args->type == BLOCK_EXPORT_TYPE_NBD);
@@ -1541,12 +1571,12 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
}
exp->size = QEMU_ALIGN_DOWN(size, BDRV_SECTOR_SIZE);
- /* XXX Allow more than one bitmap */
- if (arg->bitmaps && arg->bitmaps->next) {
- error_setg(errp, "multiple bitmaps per export not supported yet");
- return -EOPNOTSUPP;
- }
for (bitmaps = arg->bitmaps; bitmaps; bitmaps = bitmaps->next) {
+ exp->nr_export_bitmaps++;
+ }
+ exp->export_bitmaps = g_new0(BdrvDirtyBitmap *, exp->nr_export_bitmaps);
+ for (i = 0, bitmaps = arg->bitmaps; bitmaps;
+ i++, bitmaps = bitmaps->next) {
const char *bitmap = bitmaps->value;
BlockDriverState *bs = blk_bs(blk);
BdrvDirtyBitmap *bm = NULL;
@@ -1580,11 +1610,15 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
goto fail;
}
- bdrv_dirty_bitmap_set_busy(bm, true);
- exp->export_bitmap = bm;
+ exp->export_bitmaps[i] = bm;
assert(strlen(bitmap) <= BDRV_BITMAP_MAX_NAME_SIZE);
}
+ /* Mark bitmaps busy in a separate loop, to simplify roll-back concerns. */
+ for (i = 0; i < exp->nr_export_bitmaps; i++) {
+ bdrv_dirty_bitmap_set_busy(exp->export_bitmaps[i], true);
+ }
+
blk_add_aio_context_notifier(blk, blk_aio_attached, blk_aio_detach, exp);
QTAILQ_INSERT_TAIL(&exports, exp, next);
@@ -1592,6 +1626,7 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
return 0;
fail:
+ g_free(exp->export_bitmaps);
g_free(exp->name);
g_free(exp->description);
return ret;
@@ -1641,6 +1676,7 @@ static void nbd_export_request_shutdown(BlockExport *blk_exp)
static void nbd_export_delete(BlockExport *blk_exp)
{
+ size_t i;
NBDExport *exp = container_of(blk_exp, NBDExport, common);
assert(exp->name == NULL);
@@ -1658,8 +1694,8 @@ static void nbd_export_delete(BlockExport *blk_exp)
blk_aio_detach, exp);
}
- if (exp->export_bitmap) {
- bdrv_dirty_bitmap_set_busy(exp->export_bitmap, false);
+ for (i = 0; i < exp->nr_export_bitmaps; i++) {
+ bdrv_dirty_bitmap_set_busy(exp->export_bitmaps[i], false);
}
}
@@ -2268,6 +2304,7 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
int flags;
NBDExport *exp = client->exp;
char *msg;
+ size_t i;
switch (request->type) {
case NBD_CMD_CACHE:
@@ -2358,12 +2395,15 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
}
}
- if (client->export_meta.bitmap) {
+ for (i = 0; i < client->exp->nr_export_bitmaps; i++) {
+ if (!client->export_meta.bitmaps[i]) {
+ continue;
+ }
ret = nbd_co_send_bitmap(client, request->handle,
- client->exp->export_bitmap,
+ client->exp->export_bitmaps[i],
request->from, request->len,
dont_fragment, !--contexts_remaining,
- NBD_META_ID_DIRTY_BITMAP, errp);
+ NBD_META_ID_DIRTY_BITMAP + i, errp);
if (ret < 0) {
return ret;
}
diff --git a/tests/qemu-iotests/291 b/tests/qemu-iotests/291
index 4f837b205655..37848ac60bba 100755
--- a/tests/qemu-iotests/291
+++ b/tests/qemu-iotests/291
@@ -107,16 +107,14 @@ echo
# x-dirty-bitmap is a hack for reading bitmaps; it abuses block status to
# report "data":false for portions of the bitmap which are set
IMG="driver=nbd,server.type=unix,server.path=$nbd_unix_socket"
-nbd_server_start_unix_socket -r -f qcow2 -B b0 "$TEST_IMG"
+nbd_server_start_unix_socket -r -f qcow2 \
+ -B b0 -B b1 -B b2 -B b3 "$TEST_IMG"
$QEMU_IMG map --output=json --image-opts \
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b0" | _filter_qemu_img_map
-nbd_server_start_unix_socket -r -f qcow2 -B b1 "$TEST_IMG"
$QEMU_IMG map --output=json --image-opts \
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b1" | _filter_qemu_img_map
-nbd_server_start_unix_socket -r -f qcow2 -B b2 "$TEST_IMG"
$QEMU_IMG map --output=json --image-opts \
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map
-nbd_server_start_unix_socket -r -f qcow2 -B b3 "$TEST_IMG"
$QEMU_IMG map --output=json --image-opts \
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b3" | _filter_qemu_img_map
--
2.29.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v6 08/11] block: Return depth level during bdrv_is_allocated_above
2020-10-27 5:05 [PATCH v6 00/11] Exposing backing-chain allocation over NBD Eric Blake
` (6 preceding siblings ...)
2020-10-27 5:05 ` [PATCH v6 07/11] nbd: Allow export of multiple bitmaps for one device Eric Blake
@ 2020-10-27 5:05 ` Eric Blake
2020-10-27 12:05 ` Vladimir Sementsov-Ogievskiy
2020-10-27 5:05 ` [PATCH v6 09/11] nbd: Add new qemu:allocation-depth metadata context Eric Blake
` (2 subsequent siblings)
10 siblings, 1 reply; 28+ messages in thread
From: Eric Blake @ 2020-10-27 5:05 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, Fam Zheng, pkrempa, qemu-block, armbru, rjones, vsementsov,
stefanha, Max Reitz, John Snow
When checking for allocation across a chain, it's already easy to
count the depth within the chain at which the allocation is found.
Instead of throwing that information away, return it to the caller.
Existing callers only cared about allocated/non-allocated, but having
a depth available will be used by NBD in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
---
block/coroutines.h | 6 ++++--
block/io.c | 29 ++++++++++++++++++++++-------
block/commit.c | 2 +-
block/mirror.c | 2 +-
block/stream.c | 2 +-
5 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/block/coroutines.h b/block/coroutines.h
index 1cb3128b942c..4cfb4946e65e 100644
--- a/block/coroutines.h
+++ b/block/coroutines.h
@@ -47,7 +47,8 @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
int64_t bytes,
int64_t *pnum,
int64_t *map,
- BlockDriverState **file);
+ BlockDriverState **file,
+ int *depth);
int generated_co_wrapper
bdrv_common_block_status_above(BlockDriverState *bs,
BlockDriverState *base,
@@ -57,7 +58,8 @@ bdrv_common_block_status_above(BlockDriverState *bs,
int64_t bytes,
int64_t *pnum,
int64_t *map,
- BlockDriverState **file);
+ BlockDriverState **file,
+ int *depth);
int coroutine_fn bdrv_co_readv_vmstate(BlockDriverState *bs,
QEMUIOVector *qiov, int64_t pos);
diff --git a/block/io.c b/block/io.c
index 02528b3823fe..7751cdb81948 100644
--- a/block/io.c
+++ b/block/io.c
@@ -2349,20 +2349,28 @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
int64_t bytes,
int64_t *pnum,
int64_t *map,
- BlockDriverState **file)
+ BlockDriverState **file,
+ int *depth)
{
int ret;
BlockDriverState *p;
int64_t eof = 0;
+ int dummy;
assert(!include_base || base); /* Can't include NULL base */
+ if (!depth) {
+ depth = &dummy;
+ }
+ *depth = 0;
+
if (!include_base && bs == base) {
*pnum = bytes;
return 0;
}
ret = bdrv_co_block_status(bs, want_zero, offset, bytes, pnum, map, file);
+ ++*depth;
if (ret < 0 || *pnum == 0 || ret & BDRV_BLOCK_ALLOCATED || bs == base) {
return ret;
}
@@ -2379,6 +2387,7 @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
{
ret = bdrv_co_block_status(p, want_zero, offset, bytes, pnum, map,
file);
+ ++*depth;
if (ret < 0) {
return ret;
}
@@ -2437,7 +2446,7 @@ int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
int64_t *map, BlockDriverState **file)
{
return bdrv_common_block_status_above(bs, base, false, true, offset, bytes,
- pnum, map, file);
+ pnum, map, file, NULL);
}
int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
@@ -2455,7 +2464,7 @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
ret = bdrv_common_block_status_above(bs, bs, true, false, offset,
bytes, pnum ? pnum : &dummy, NULL,
- NULL);
+ NULL, NULL);
if (ret < 0) {
return ret;
}
@@ -2465,8 +2474,9 @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
/*
* Given an image chain: ... -> [BASE] -> [INTER1] -> [INTER2] -> [TOP]
*
- * Return 1 if (a prefix of) the given range is allocated in any image
- * between BASE and TOP (BASE is only included if include_base is set).
+ * Return a positive depth if (a prefix of) the given range is allocated
+ * in any image between BASE and TOP (BASE is only included if include_base
+ * is set). Depth 1 is TOP, 2 is the first backing layer, and so forth.
* BASE can be NULL to check if the given offset is allocated in any
* image of the chain. Return 0 otherwise, or negative errno on
* failure.
@@ -2483,13 +2493,18 @@ int bdrv_is_allocated_above(BlockDriverState *top,
bool include_base, int64_t offset,
int64_t bytes, int64_t *pnum)
{
+ int depth;
int ret = bdrv_common_block_status_above(top, base, include_base, false,
- offset, bytes, pnum, NULL, NULL);
+ offset, bytes, pnum, NULL, NULL,
+ &depth);
if (ret < 0) {
return ret;
}
- return !!(ret & BDRV_BLOCK_ALLOCATED);
+ if (ret & BDRV_BLOCK_ALLOCATED) {
+ return depth;
+ }
+ return 0;
}
int coroutine_fn
diff --git a/block/commit.c b/block/commit.c
index 1e85c306cc41..71db7ba7472e 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -156,7 +156,7 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
/* Copy if allocated above the base */
ret = bdrv_is_allocated_above(blk_bs(s->top), s->base_overlay, true,
offset, COMMIT_BUFFER_SIZE, &n);
- copy = (ret == 1);
+ copy = (ret > 0);
trace_commit_one_iteration(s, offset, n, ret);
if (copy) {
assert(n < SIZE_MAX);
diff --git a/block/mirror.c b/block/mirror.c
index 26acf4af6fb7..8e1ad6eceb57 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -846,7 +846,7 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
}
assert(count);
- if (ret == 1) {
+ if (ret > 0) {
bdrv_set_dirty_bitmap(s->dirty_bitmap, offset, count);
}
offset += count;
diff --git a/block/stream.c b/block/stream.c
index 8ce6729a33da..236384f2f739 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -167,7 +167,7 @@ static int coroutine_fn stream_run(Job *job, Error **errp)
n = len - offset;
}
- copy = (ret == 1);
+ copy = (ret > 0);
}
trace_stream_one_iteration(s, offset, n, ret);
if (copy) {
--
2.29.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v6 09/11] nbd: Add new qemu:allocation-depth metadata context
2020-10-27 5:05 [PATCH v6 00/11] Exposing backing-chain allocation over NBD Eric Blake
` (7 preceding siblings ...)
2020-10-27 5:05 ` [PATCH v6 08/11] block: Return depth level during bdrv_is_allocated_above Eric Blake
@ 2020-10-27 5:05 ` Eric Blake
2020-10-27 10:53 ` Vladimir Sementsov-Ogievskiy
2020-10-27 5:05 ` [PATCH v6 10/11] nbd: Add 'qemu-nbd -A' to expose allocation depth Eric Blake
2020-10-27 5:05 ` [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible Eric Blake
10 siblings, 1 reply; 28+ messages in thread
From: Eric Blake @ 2020-10-27 5:05 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, pkrempa, qemu-block, armbru, rjones, vsementsov, stefanha,
Max Reitz
'qemu-img map' provides a way to determine which extents of an image
come from the top layer vs. inherited from a backing chain. This is
useful information worth exposing over NBD. There is a proposal to
add a QMP command block-dirty-bitmap-populate which can create a dirty
bitmap that reflects allocation information, at which point the
qemu:dirty-bitmap:NAME metadata context can expose that information
via the creation of a temporary bitmap, but we can shorten the effort
by adding a new qemu:allocation-depth metadata context that does the
same thing without an intermediate bitmap (this patch does not
eliminate the need for that proposal, as it will have other uses as
well).
While documenting things, remember that although the NBD protocol has
NBD_OPT_SET_META_CONTEXT, the rest of its documentation refers to
'metadata context', which is a more apt description of what is
actually being used by NBD_CMD_BLOCK_STATUS: the user is requesting
metadata by passing one or more context names. So I also touched up
some existing wording to prefer the term 'metadata context' where it
makes sense.
Note that this patch does not actually enable any way to request a
server to enable this context; that will come in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
---
docs/interop/nbd.txt | 23 +++++++++++----
include/block/nbd.h | 8 +++--
nbd/server.c | 70 +++++++++++++++++++++++++++++++++++++++++---
3 files changed, 89 insertions(+), 12 deletions(-)
diff --git a/docs/interop/nbd.txt b/docs/interop/nbd.txt
index f3b3cacc9621..10ce098a29bf 100644
--- a/docs/interop/nbd.txt
+++ b/docs/interop/nbd.txt
@@ -17,19 +17,31 @@ namespace "qemu".
== "qemu" namespace ==
-The "qemu" namespace currently contains only one type of context,
-related to exposing the contents of a dirty bitmap alongside the
-associated disk contents. That context has the following form:
+The "qemu" namespace currently contains two available metadata context
+types. The first is related to exposing the contents of a dirty
+bitmap alongside the associated disk contents. That metadata context
+is named with the following form:
qemu:dirty-bitmap:<dirty-bitmap-export-name>
Each dirty-bitmap metadata context defines only one flag for extents
in reply for NBD_CMD_BLOCK_STATUS:
- bit 0: NBD_STATE_DIRTY, means that the extent is "dirty"
+ bit 0: NBD_STATE_DIRTY, set when the extent is "dirty"
+
+The second is related to exposing the source of various extents within
+the image, with a single metadata context named:
+
+ qemu:allocation-depth
+
+In the allocation depth context, the entire 32-bit value represents a
+depth of which layer in a thin-provisioned backing chain provided the
+data (0 for unallocated, 1 for the active layer, 2 for the first
+backing layer, and so forth).
For NBD_OPT_LIST_META_CONTEXT the following queries are supported
-in addition to "qemu:dirty-bitmap:<dirty-bitmap-export-name>":
+in addition to the specific "qemu:allocation-depth" and
+"qemu:dirty-bitmap:<dirty-bitmap-export-name>":
* "qemu:" - returns list of all available metadata contexts in the
namespace.
@@ -55,3 +67,4 @@ the operation of that feature.
NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CACHE
* 4.2: NBD_FLAG_CAN_MULTI_CONN for shareable read-only exports,
NBD_CMD_FLAG_FAST_ZERO
+* 5.2: NBD_CMD_BLOCK_STATUS for "qemu:allocation-depth"
diff --git a/include/block/nbd.h b/include/block/nbd.h
index 3dd9a04546ec..4a52a43ef598 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2019 Red Hat, Inc.
+ * Copyright (C) 2016-2020 Red Hat, Inc.
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
*
* Network Block Device
@@ -47,7 +47,7 @@ typedef struct NBDOptionReply NBDOptionReply;
typedef struct NBDOptionReplyMetaContext {
NBDOptionReply h; /* h.type = NBD_REP_META_CONTEXT, h.length > 4 */
uint32_t context_id;
- /* meta context name follows */
+ /* metadata context name follows */
} QEMU_PACKED NBDOptionReplyMetaContext;
/* Transmission phase structs
@@ -229,7 +229,7 @@ enum {
#define NBD_MAX_BUFFER_SIZE (32 * 1024 * 1024)
/*
- * Maximum size of a protocol string (export name, meta context name,
+ * Maximum size of a protocol string (export name, metadata context name,
* etc.). Use malloc rather than stack allocation for storage of a
* string.
*/
@@ -259,6 +259,8 @@ enum {
/* Extent flags for qemu:dirty-bitmap in NBD_REPLY_TYPE_BLOCK_STATUS */
#define NBD_STATE_DIRTY (1 << 0)
+/* No flags needed for qemu:allocation-depth in NBD_REPLY_TYPE_BLOCK_STATUS */
+
static inline bool nbd_reply_type_is_error(int type)
{
return type & (1 << 15);
diff --git a/nbd/server.c b/nbd/server.c
index b6841e455414..ebbefcb6d3ec 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -27,8 +27,9 @@
#include "qemu/units.h"
#define NBD_META_ID_BASE_ALLOCATION 0
+#define NBD_META_ID_ALLOCATION_DEPTH 1
/* Dirty bitmaps use 'NBD_META_ID_DIRTY_BITMAP + i', so keep this id last. */
-#define NBD_META_ID_DIRTY_BITMAP 1
+#define NBD_META_ID_DIRTY_BITMAP 2
/*
* NBD_MAX_BLOCK_STATUS_EXTENTS: 1 MiB of extents data. An empirical
@@ -95,6 +96,7 @@ struct NBDExport {
BlockBackend *eject_notifier_blk;
Notifier eject_notifier;
+ bool allocation_depth;
BdrvDirtyBitmap **export_bitmaps;
size_t nr_export_bitmaps;
};
@@ -108,6 +110,7 @@ typedef struct NBDExportMetaContexts {
NBDExport *exp;
size_t count; /* number of negotiated contexts */
bool base_allocation; /* export base:allocation context (block status) */
+ bool allocation_depth; /* export qemu:allocation-depth */
bool *bitmaps; /*
* export qemu:dirty-bitmap:<export bitmap name>,
* sized by exp->nr_export_bitmaps
@@ -857,7 +860,8 @@ static bool nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta,
/* nbd_meta_qemu_query
*
* Handle queries to 'qemu' namespace. For now, only the qemu:dirty-bitmap:
- * context is available. Return true if @query has been handled.
+ * and qemu:allocation-depth contexts are available. Return true if @query
+ * has been handled.
*/
static bool nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta,
const char *query)
@@ -871,12 +875,19 @@ static bool nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta,
if (!*query) {
if (client->opt == NBD_OPT_LIST_META_CONTEXT) {
+ meta->allocation_depth = meta->exp->allocation_depth;
memset(meta->bitmaps, 1, meta->exp->nr_export_bitmaps);
}
trace_nbd_negotiate_meta_query_parse("empty");
return true;
}
+ if (strcmp(query, "allocation-depth") == 0) {
+ trace_nbd_negotiate_meta_query_parse("allocation-depth");
+ meta->allocation_depth = meta->exp->allocation_depth;
+ return true;
+ }
+
if (nbd_strshift(&query, "dirty-bitmap:")) {
trace_nbd_negotiate_meta_query_parse("dirty-bitmap:");
if (!*query) {
@@ -901,7 +912,7 @@ static bool nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta,
return true;
}
- trace_nbd_negotiate_meta_query_skip("not dirty-bitmap");
+ trace_nbd_negotiate_meta_query_skip("unknown qemu context");
return true;
}
@@ -1008,6 +1019,7 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
if (client->opt == NBD_OPT_LIST_META_CONTEXT && !nb_queries) {
/* enable all known contexts */
meta->base_allocation = true;
+ meta->allocation_depth = meta->exp->allocation_depth;
memset(meta->bitmaps, 1, meta->exp->nr_export_bitmaps);
} else {
for (i = 0; i < nb_queries; ++i) {
@@ -1028,6 +1040,16 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
count++;
}
+ if (meta->allocation_depth) {
+ ret = nbd_negotiate_send_meta_context(client, "qemu:allocation-depth",
+ NBD_META_ID_ALLOCATION_DEPTH,
+ errp);
+ if (ret < 0) {
+ return ret;
+ }
+ count++;
+ }
+
for (i = 0; i < meta->exp->nr_export_bitmaps; i++) {
const char *bm_name;
g_autofree char *context = NULL;
@@ -2005,6 +2027,29 @@ static int blockstatus_to_extents(BlockDriverState *bs, uint64_t offset,
return 0;
}
+static int blockalloc_to_extents(BlockDriverState *bs, uint64_t offset,
+ uint64_t bytes, NBDExtentArray *ea)
+{
+ while (bytes) {
+ int64_t num;
+ int ret = bdrv_is_allocated_above(bs, NULL, false, offset, bytes,
+ &num);
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (nbd_extent_array_add(ea, num, ret) < 0) {
+ return 0;
+ }
+
+ offset += num;
+ bytes -= num;
+ }
+
+ return 0;
+}
+
/*
* nbd_co_send_extents
*
@@ -2044,7 +2089,11 @@ static int nbd_co_send_block_status(NBDClient *client, uint64_t handle,
unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_EXTENTS;
g_autoptr(NBDExtentArray) ea = nbd_extent_array_new(nb_extents);
- ret = blockstatus_to_extents(bs, offset, length, ea);
+ if (context_id == NBD_META_ID_BASE_ALLOCATION) {
+ ret = blockstatus_to_extents(bs, offset, length, ea);
+ } else {
+ ret = blockalloc_to_extents(bs, offset, length, ea);
+ }
if (ret < 0) {
return nbd_co_send_structured_error(
client, handle, -ret, "can't get block status", errp);
@@ -2395,6 +2444,19 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
}
}
+ if (client->export_meta.allocation_depth) {
+ ret = nbd_co_send_block_status(client, request->handle,
+ blk_bs(exp->common.blk),
+ request->from, request->len,
+ dont_fragment,
+ !--contexts_remaining,
+ NBD_META_ID_ALLOCATION_DEPTH,
+ errp);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
for (i = 0; i < client->exp->nr_export_bitmaps; i++) {
if (!client->export_meta.bitmaps[i]) {
continue;
--
2.29.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v6 10/11] nbd: Add 'qemu-nbd -A' to expose allocation depth
2020-10-27 5:05 [PATCH v6 00/11] Exposing backing-chain allocation over NBD Eric Blake
` (8 preceding siblings ...)
2020-10-27 5:05 ` [PATCH v6 09/11] nbd: Add new qemu:allocation-depth metadata context Eric Blake
@ 2020-10-27 5:05 ` Eric Blake
2020-10-27 11:03 ` Vladimir Sementsov-Ogievskiy
2020-10-27 5:05 ` [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible Eric Blake
10 siblings, 1 reply; 28+ messages in thread
From: Eric Blake @ 2020-10-27 5:05 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, pkrempa, qemu-block, armbru, rjones, vsementsov, stefanha,
Max Reitz
Allow the server to expose an additional metacontext to be requested
by savvy clients. qemu-nbd adds a new option -A to expose the
qemu:allocation-depth metacontext through NBD_CMD_BLOCK_STATUS; this
can also be set via QMP when using block-export-add.
qemu as client is hacked into viewing the key aspects of this new
context by abusing the already-experimental x-dirty-bitmap option to
collapse all depths greater than 2, which results in a tri-state value
visible in the output of 'qemu-img map --output=json' (yes, that means
x-dirty-bitmap is now a bit of a misnomer, but I didn't feel like
renaming it as it would introduce a needless break of back-compat,
even though we make no compat guarantees with x- members):
unallocated (depth 0) => "zero":false, "data":true
local (depth 1) => "zero":false, "data":false
backing (depth 2+) => "zero":true, "data":true
libnbd as client is probably a nicer way to get at the information
without having to decipher such hacks in qemu as client. ;)
Signed-off-by: Eric Blake <eblake@redhat.com>
---
docs/tools/qemu-nbd.rst | 8 +++-
qapi/block-core.json | 7 +++-
qapi/block-export.json | 7 +++-
block/nbd.c | 26 ++++++++++---
nbd/server.c | 2 +
qemu-nbd.c | 12 +++++-
tests/qemu-iotests/309 | 77 ++++++++++++++++++++++++++++++++++++++
tests/qemu-iotests/309.out | 22 +++++++++++
tests/qemu-iotests/group | 1 +
9 files changed, 151 insertions(+), 11 deletions(-)
create mode 100755 tests/qemu-iotests/309
create mode 100644 tests/qemu-iotests/309.out
diff --git a/docs/tools/qemu-nbd.rst b/docs/tools/qemu-nbd.rst
index 667861cb22e9..fe41336dc550 100644
--- a/docs/tools/qemu-nbd.rst
+++ b/docs/tools/qemu-nbd.rst
@@ -72,10 +72,16 @@ driver options if ``--image-opts`` is specified.
Export the disk as read-only.
+.. option:: -A, --allocation-depth
+
+ Expose allocation depth information via the
+ ``qemu:allocation-depth`` metadata context accessible through
+ NBD_OPT_SET_META_CONTEXT.
+
.. option:: -B, --bitmap=NAME
If *filename* has a qcow2 persistent bitmap *NAME*, expose
- that bitmap via the ``qemu:dirty-bitmap:NAME`` context
+ that bitmap via the ``qemu:dirty-bitmap:NAME`` metadata context
accessible through NBD_OPT_SET_META_CONTEXT.
.. option:: -s, --snapshot
diff --git a/qapi/block-core.json b/qapi/block-core.json
index e00fc27b5ea4..1b8b4156b4b9 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3905,9 +3905,12 @@
#
# @tls-creds: TLS credentials ID
#
-# @x-dirty-bitmap: A "qemu:dirty-bitmap:NAME" string to query in place of
+# @x-dirty-bitmap: A metadata context name such as "qemu:dirty-bitmap:NAME"
+# or "qemu:allocation-depth" to query in place of the
# traditional "base:allocation" block status (see
-# NBD_OPT_LIST_META_CONTEXT in the NBD protocol) (since 3.0)
+# NBD_OPT_LIST_META_CONTEXT in the NBD protocol; and
+# yes, naming this option x-context would have made
+# more sense) (since 3.0)
#
# @reconnect-delay: On an unexpected disconnect, the nbd client tries to
# connect again until succeeding or encountering a serious
diff --git a/qapi/block-export.json b/qapi/block-export.json
index c4125f4d2104..a9f488f99c1a 100644
--- a/qapi/block-export.json
+++ b/qapi/block-export.json
@@ -90,11 +90,16 @@
# the metadata context name "qemu:dirty-bitmap:BITMAP" to inspect
# each bitmap.
#
+# @allocation-depth: Also export the allocation depth map for @device, so
+# the NBD client can use NBD_OPT_SET_META_CONTEXT with
+# the metadata context name "qemu:allocation-depth" to
+# inspect allocation details. (since 5.2)
+#
# Since: 5.2
##
{ 'struct': 'BlockExportOptionsNbd',
'base': 'BlockExportOptionsNbdBase',
- 'data': { '*bitmaps': ['str'] } }
+ 'data': { '*bitmaps': ['str'], '*allocation-depth': 'bool' } }
##
# @BlockExportOptionsVhostUserBlk:
diff --git a/block/nbd.c b/block/nbd.c
index 4548046cd7cd..42536702b6f9 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -135,6 +135,7 @@ typedef struct BDRVNBDState {
QCryptoTLSCreds *tlscreds;
const char *hostname;
char *x_dirty_bitmap;
+ bool alloc_depth;
bool wait_connect;
NBDConnectThread *connect_thread;
@@ -961,6 +962,16 @@ static int nbd_parse_blockstatus_payload(BDRVNBDState *s,
trace_nbd_parse_blockstatus_compliance("extent length too large");
}
+ /*
+ * HACK: if we are using x-dirty-bitmaps to access
+ * qemu:allocation-depth, treat all depths > 2 the same as 2,
+ * since nbd_client_co_block_status is only expecting the low two
+ * bits to be set.
+ */
+ if (s->alloc_depth && extent->flags > 2) {
+ extent->flags = 2;
+ }
+
return 0;
}
@@ -1795,11 +1806,16 @@ static int nbd_client_handshake(BlockDriverState *bs, QIOChannelSocket *sioc,
s->sioc = NULL;
return ret;
}
- if (s->x_dirty_bitmap && !s->info.base_allocation) {
- error_setg(errp, "requested x-dirty-bitmap %s not found",
- s->x_dirty_bitmap);
- ret = -EINVAL;
- goto fail;
+ if (s->x_dirty_bitmap) {
+ if (!s->info.base_allocation) {
+ error_setg(errp, "requested x-dirty-bitmap %s not found",
+ s->x_dirty_bitmap);
+ ret = -EINVAL;
+ goto fail;
+ }
+ if (strcmp(s->x_dirty_bitmap, "qemu:allocation-depth") == 0) {
+ s->alloc_depth = true;
+ }
}
if (s->info.flags & NBD_FLAG_READ_ONLY) {
ret = bdrv_apply_auto_read_only(bs, "NBD export is read-only", errp);
diff --git a/nbd/server.c b/nbd/server.c
index ebbefcb6d3ec..d145e1a69083 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -1641,6 +1641,8 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
bdrv_dirty_bitmap_set_busy(exp->export_bitmaps[i], true);
}
+ exp->allocation_depth = arg->allocation_depth;
+
blk_add_aio_context_notifier(blk, blk_aio_attached, blk_aio_detach, exp);
QTAILQ_INSERT_TAIL(&exports, exp, next);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 4b7825c44093..808db07fca70 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -100,6 +100,7 @@ static void usage(const char *name)
"\n"
"Exposing part of the image:\n"
" -o, --offset=OFFSET offset into the image\n"
+" -A, --allocation-depth expose the allocation depth\n"
" -B, --bitmap=NAME expose a persistent dirty bitmap\n"
"\n"
"General purpose options:\n"
@@ -524,7 +525,7 @@ int main(int argc, char **argv)
char *device = NULL;
QemuOpts *sn_opts = NULL;
const char *sn_id_or_name = NULL;
- const char *sopt = "hVb:o:p:rsnc:dvk:e:f:tl:x:T:D:B:L";
+ const char *sopt = "hVb:o:p:rsnc:dvk:e:f:tl:x:T:D:AB:L";
struct option lopt[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
@@ -533,6 +534,7 @@ int main(int argc, char **argv)
{ "socket", required_argument, NULL, 'k' },
{ "offset", required_argument, NULL, 'o' },
{ "read-only", no_argument, NULL, 'r' },
+ { "allocation-depth", no_argument, NULL, 'A' },
{ "bitmap", required_argument, NULL, 'B' },
{ "connect", required_argument, NULL, 'c' },
{ "disconnect", no_argument, NULL, 'd' },
@@ -575,6 +577,7 @@ int main(int argc, char **argv)
const char *export_name = NULL; /* defaults to "" later for server mode */
const char *export_description = NULL;
strList *bitmaps = NULL;
+ bool alloc_depth = false;
const char *tlscredsid = NULL;
bool imageOpts = false;
bool writethrough = true;
@@ -689,6 +692,9 @@ int main(int argc, char **argv)
readonly = true;
flags &= ~BDRV_O_RDWR;
break;
+ case 'A':
+ alloc_depth = true;
+ break;
case 'B':
QAPI_LIST_ADD(bitmaps, g_strdup(optarg));
break;
@@ -787,7 +793,7 @@ int main(int argc, char **argv)
}
if (export_name || export_description || dev_offset ||
device || disconnect || fmt || sn_id_or_name || bitmaps ||
- seen_aio || seen_discard || seen_cache) {
+ alloc_depth || seen_aio || seen_discard || seen_cache) {
error_report("List mode is incompatible with per-device settings");
exit(EXIT_FAILURE);
}
@@ -1073,6 +1079,8 @@ int main(int argc, char **argv)
.description = g_strdup(export_description),
.has_bitmaps = !!bitmaps,
.bitmaps = bitmaps,
+ .has_allocation_depth = alloc_depth,
+ .allocation_depth = alloc_depth,
},
};
blk_exp_add(export_opts, &error_fatal);
diff --git a/tests/qemu-iotests/309 b/tests/qemu-iotests/309
new file mode 100755
index 000000000000..fb61157c2e1d
--- /dev/null
+++ b/tests/qemu-iotests/309
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+#
+# Test qemu-nbd -A
+#
+# Copyright (C) 2018-2020 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+ nbd_server_stop
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.nbd
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+_require_command QEMU_NBD
+
+echo
+echo "=== Initial image setup ==="
+echo
+
+TEST_IMG="$TEST_IMG.base" _make_test_img 4M
+$QEMU_IO -c 'w 0 2M' -f $IMGFMT "$TEST_IMG.base" | _filter_qemu_io
+_make_test_img -b "$TEST_IMG.base" -F $IMGFMT 4M
+$QEMU_IO -c 'w 1M 2M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
+
+echo
+echo "=== Check allocation over NBD ==="
+echo
+
+$QEMU_IMG map --output=json -f qcow2 "$TEST_IMG"
+IMG="driver=nbd,server.type=unix,server.path=$nbd_unix_socket"
+nbd_server_start_unix_socket -r -f qcow2 -A "$TEST_IMG"
+# Normal -f raw NBD block status loses access to allocation information
+$QEMU_IMG map --output=json --image-opts \
+ "$IMG" | _filter_qemu_img_map
+# But when we use -A, coupled with x-dirty-bitmap in the client for feeding
+# 2-bit block status from an alternative NBD metadata context (note that
+# the client code for x-dirty-bitmap intentionally collapses all depths
+# beyond 2 into a single value), we can determine:
+# unallocated (depth 0) => "zero":false, "data":true
+# local (depth 1) => "zero":false, "data":false
+# backing (depth 2+) => "zero":true, "data":true
+$QEMU_IMG map --output=json --image-opts \
+ "$IMG,x-dirty-bitmap=qemu:allocation-depth" | _filter_qemu_img_map
+# More accurate results can be obtained by other NBD clients such as
+# libnbd, but this test works without such external dependencies.
+
+# success, all done
+echo '*** done'
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/309.out b/tests/qemu-iotests/309.out
new file mode 100644
index 000000000000..db75bb6b0df9
--- /dev/null
+++ b/tests/qemu-iotests/309.out
@@ -0,0 +1,22 @@
+QA output created by 309
+
+=== Initial image setup ===
+
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=4194304
+wrote 2097152/2097152 bytes at offset 0
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
+wrote 2097152/2097152 bytes at offset 1048576
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Check allocation over NBD ===
+
+[{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680},
+{ "start": 1048576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680},
+{ "start": 3145728, "length": 1048576, "depth": 1, "zero": true, "data": false}]
+[{ "start": 0, "length": 3145728, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 3145728, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": true, "offset": OFFSET},
+{ "start": 1048576, "length": 2097152, "depth": 0, "zero": false, "data": false},
+{ "start": 3145728, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 343298928350..2960dff72864 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -315,3 +315,4 @@
304 rw quick
305 rw quick
307 rw quick export
+309 rw auto quick
--
2.29.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible
2020-10-27 5:05 [PATCH v6 00/11] Exposing backing-chain allocation over NBD Eric Blake
` (9 preceding siblings ...)
2020-10-27 5:05 ` [PATCH v6 10/11] nbd: Add 'qemu-nbd -A' to expose allocation depth Eric Blake
@ 2020-10-27 5:05 ` Eric Blake
2020-10-27 5:53 ` Thomas Huth
` (4 more replies)
10 siblings, 5 replies; 28+ messages in thread
From: Eric Blake @ 2020-10-27 5:05 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, pkrempa, Michael S. Tsirkin, Jason Wang,
Thomas Huth, Jiaxun Yang, rjones, Gerd Hoffmann, Michael Roth,
qemu-block, Juan Quintela, David Hildenbrand, armbru, Halil Pasic,
Christian Borntraeger, Marc-André Lureau, David Gibson,
Aleksandar Rikalo, Jiri Pirko, Eduardo Habkost,
Dr. David Alan Gilbert, open list:S390 KVM CPUs,
open list:GLUSTER, stefanha, Richard Henderson, kwolf, vsementsov,
Daniel P. Berrangé, Cornelia Huck,
Philippe Mathieu-Daudé, Max Reitz, open list:ARM TCG CPUs,
open list:PowerPC TCG CPUs, Paolo Bonzini, Aurelien Jarno
Anywhere we create a list of just one item or by prepending items
(typically because order doesn't matter), we can use the now-public
macro. But places where we must keep the list in order by appending
remain open-coded.
Signed-off-by: Eric Blake <eblake@redhat.com>
---
docs/devel/writing-qmp-commands.txt | 13 +++------
hw/net/rocker/rocker_fp.h | 2 +-
block/gluster.c | 19 +++++--------
chardev/char.c | 21 +++++++--------
hw/core/machine.c | 6 +----
hw/net/rocker/rocker.c | 8 +++---
hw/net/rocker/rocker_fp.c | 14 +++++-----
hw/net/virtio-net.c | 21 +++++----------
migration/migration.c | 7 ++---
migration/postcopy-ram.c | 7 ++---
monitor/hmp-cmds.c | 11 ++++----
qemu-img.c | 5 ++--
qga/commands-posix.c | 13 +++------
qga/commands-win32.c | 17 +++---------
qga/commands.c | 6 +----
qom/qom-qmp-cmds.c | 29 ++++++--------------
target/arm/helper.c | 6 +----
target/arm/monitor.c | 13 ++-------
target/i386/cpu.c | 6 +----
target/mips/helper.c | 6 +----
target/s390x/cpu_models.c | 12 ++-------
tests/test-clone-visitor.c | 7 ++---
tests/test-qobject-output-visitor.c | 42 ++++++++++++++---------------
tests/test-visitor-serialization.c | 5 +---
trace/qmp.c | 22 +++++++--------
ui/vnc.c | 21 +++++----------
util/qemu-config.c | 14 +++-------
target/ppc/translate_init.c.inc | 12 ++-------
28 files changed, 119 insertions(+), 246 deletions(-)
diff --git a/docs/devel/writing-qmp-commands.txt b/docs/devel/writing-qmp-commands.txt
index 46a6c48683f5..3e11eeaa1893 100644
--- a/docs/devel/writing-qmp-commands.txt
+++ b/docs/devel/writing-qmp-commands.txt
@@ -531,15 +531,10 @@ TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
bool current = true;
for (p = alarm_timers; p->name; p++) {
- TimerAlarmMethodList *info = g_malloc0(sizeof(*info));
- info->value = g_malloc0(sizeof(*info->value));
- info->value->method_name = g_strdup(p->name);
- info->value->current = current;
-
- current = false;
-
- info->next = method_list;
- method_list = info;
+ TimerAlarmMethod *value = g_new0(TimerAlarmMethod, 1);
+ value->method_name = g_strdup(p->name);
+ value->current = current;
+ QAPI_LIST_ADD(method_list, value);
}
return method_list;
diff --git a/hw/net/rocker/rocker_fp.h b/hw/net/rocker/rocker_fp.h
index dbe1dd329a4b..4cb0bb9ccf81 100644
--- a/hw/net/rocker/rocker_fp.h
+++ b/hw/net/rocker/rocker_fp.h
@@ -28,7 +28,7 @@ int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt);
char *fp_port_get_name(FpPort *port);
bool fp_port_get_link_up(FpPort *port);
-void fp_port_get_info(FpPort *port, RockerPortList *info);
+void fp_port_get_info(FpPort *port, RockerPort *info);
void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr);
void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr);
uint8_t fp_port_get_learning(FpPort *port);
diff --git a/block/gluster.c b/block/gluster.c
index 4f1448e2bc88..cf446c23f85d 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -359,8 +359,8 @@ static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
return -EINVAL;
}
- gconf->server = g_new0(SocketAddressList, 1);
- gconf->server->value = gsconf = g_new0(SocketAddress, 1);
+ gsconf = g_new0(SocketAddress, 1);
+ QAPI_LIST_ADD(gconf->server, gsconf);
/* transport */
if (!uri->scheme || !strcmp(uri->scheme, "gluster")) {
@@ -514,7 +514,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
{
QemuOpts *opts;
SocketAddress *gsconf = NULL;
- SocketAddressList *curr = NULL;
+ SocketAddressList **curr;
QDict *backing_options = NULL;
Error *local_err = NULL;
char *str = NULL;
@@ -547,6 +547,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
}
gconf->path = g_strdup(ptr);
qemu_opts_del(opts);
+ curr = &gconf->server;
for (i = 0; i < num_servers; i++) {
str = g_strdup_printf(GLUSTER_OPT_SERVER_PATTERN"%d.", i);
@@ -655,15 +656,9 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
qemu_opts_del(opts);
}
- if (gconf->server == NULL) {
- gconf->server = g_new0(SocketAddressList, 1);
- gconf->server->value = gsconf;
- curr = gconf->server;
- } else {
- curr->next = g_new0(SocketAddressList, 1);
- curr->next->value = gsconf;
- curr = curr->next;
- }
+ *curr = g_new0(SocketAddressList, 1);
+ (*curr)->value = gsconf;
+ curr = &(*curr)->next;
gsconf = NULL;
qobject_unref(backing_options);
diff --git a/chardev/char.c b/chardev/char.c
index 78553125d311..8dd7ef4c5935 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -776,15 +776,14 @@ static int qmp_query_chardev_foreach(Object *obj, void *data)
{
Chardev *chr = CHARDEV(obj);
ChardevInfoList **list = data;
- ChardevInfoList *info = g_malloc0(sizeof(*info));
+ ChardevInfo *value;
- info->value = g_malloc0(sizeof(*info->value));
- info->value->label = g_strdup(chr->label);
- info->value->filename = g_strdup(chr->filename);
- info->value->frontend_open = chr->be && chr->be->fe_open;
+ value = g_malloc0(sizeof(*value));
+ value->label = g_strdup(chr->label);
+ value->filename = g_strdup(chr->filename);
+ value->frontend_open = chr->be && chr->be->fe_open;
- info->next = *list;
- *list = info;
+ QAPI_LIST_ADD(*list, value);
return 0;
}
@@ -803,12 +802,10 @@ static void
qmp_prepend_backend(const char *name, void *opaque)
{
ChardevBackendInfoList **list = opaque;
- ChardevBackendInfoList *info = g_malloc0(sizeof(*info));
+ ChardevBackendInfo *value = g_new0(ChardevBackendInfo, 1);
- info->value = g_malloc0(sizeof(*info->value));
- info->value->name = g_strdup(name);
- info->next = *list;
- *list = info;
+ value->name = g_strdup(name);
+ QAPI_LIST_ADD(*list, value);
}
ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
diff --git a/hw/core/machine.c b/hw/core/machine.c
index c5e0e79e6dbc..a05c4739ca7a 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -492,11 +492,7 @@ static void machine_set_nvdimm_persistence(Object *obj, const char *value,
void machine_class_allow_dynamic_sysbus_dev(MachineClass *mc, const char *type)
{
- strList *item = g_new0(strList, 1);
-
- item->value = g_strdup(type);
- item->next = mc->allowed_dynamic_sysbus_devices;
- mc->allowed_dynamic_sysbus_devices = item;
+ QAPI_LIST_ADD(mc->allowed_dynamic_sysbus_devices, g_strdup(type));
}
static void validate_sysbus_device(SysBusDevice *sbdev, void *opaque)
diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c
index 1af1e6fa2f9b..a1137e11ff48 100644
--- a/hw/net/rocker/rocker.c
+++ b/hw/net/rocker/rocker.c
@@ -127,13 +127,11 @@ RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
}
for (i = r->fp_ports - 1; i >= 0; i--) {
- RockerPortList *info = g_malloc0(sizeof(*info));
- info->value = g_malloc0(sizeof(*info->value));
+ RockerPort *value = g_malloc0(sizeof(*value));
struct fp_port *port = r->fp_port[i];
- fp_port_get_info(port, info);
- info->next = list;
- list = info;
+ fp_port_get_info(port, value);
+ QAPI_LIST_ADD(list, value);
}
return list;
diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c
index 4aa7da79b81d..a616e709292e 100644
--- a/hw/net/rocker/rocker_fp.c
+++ b/hw/net/rocker/rocker_fp.c
@@ -51,14 +51,14 @@ bool fp_port_get_link_up(FpPort *port)
return !qemu_get_queue(port->nic)->link_down;
}
-void fp_port_get_info(FpPort *port, RockerPortList *info)
+void fp_port_get_info(FpPort *port, RockerPort *value)
{
- info->value->name = g_strdup(port->name);
- info->value->enabled = port->enabled;
- info->value->link_up = fp_port_get_link_up(port);
- info->value->speed = port->speed;
- info->value->duplex = port->duplex;
- info->value->autoneg = port->autoneg;
+ value->name = g_strdup(port->name);
+ value->enabled = port->enabled;
+ value->link_up = fp_port_get_link_up(port);
+ value->speed = port->speed;
+ value->duplex = port->duplex;
+ value->autoneg = port->autoneg;
}
void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 277289d56e76..6b13d3ca3c8f 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -437,17 +437,14 @@ static void rxfilter_notify(NetClientState *nc)
static intList *get_vlan_table(VirtIONet *n)
{
- intList *list, *entry;
+ intList *list;
int i, j;
list = NULL;
for (i = 0; i < MAX_VLAN >> 5; i++) {
for (j = 0; n->vlans[i] && j <= 0x1f; j++) {
if (n->vlans[i] & (1U << j)) {
- entry = g_malloc0(sizeof(*entry));
- entry->value = (i << 5) + j;
- entry->next = list;
- list = entry;
+ QAPI_LIST_ADD(list, (i << 5) + j);
}
}
}
@@ -460,7 +457,7 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
VirtIONet *n = qemu_get_nic_opaque(nc);
VirtIODevice *vdev = VIRTIO_DEVICE(n);
RxFilterInfo *info;
- strList *str_list, *entry;
+ strList *str_list;
int i;
info = g_malloc0(sizeof(*info));
@@ -491,19 +488,15 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
str_list = NULL;
for (i = 0; i < n->mac_table.first_multi; i++) {
- entry = g_malloc0(sizeof(*entry));
- entry->value = qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN);
- entry->next = str_list;
- str_list = entry;
+ QAPI_LIST_ADD(str_list,
+ qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN));
}
info->unicast_table = str_list;
str_list = NULL;
for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
- entry = g_malloc0(sizeof(*entry));
- entry->value = qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN);
- entry->next = str_list;
- str_list = entry;
+ QAPI_LIST_ADD(str_list,
+ qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN));
}
info->multicast_table = str_list;
info->vlan_table = get_vlan_table(n);
diff --git a/migration/migration.c b/migration/migration.c
index deb6005b8d37..239a7e430214 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -368,12 +368,9 @@ int migration_incoming_enable_colo(void)
void migrate_add_address(SocketAddress *address)
{
MigrationIncomingState *mis = migration_incoming_get_current();
- SocketAddressList *addrs;
- addrs = g_new0(SocketAddressList, 1);
- addrs->next = mis->socket_address_list;
- mis->socket_address_list = addrs;
- addrs->value = QAPI_CLONE(SocketAddress, address);
+ QAPI_LIST_ADD(mis->socket_address_list,
+ QAPI_CLONE(SocketAddress, address));
}
void qemu_start_incoming_migration(const char *uri, Error **errp)
diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
index 0a2f88a87d06..18ac7e06c581 100644
--- a/migration/postcopy-ram.c
+++ b/migration/postcopy-ram.c
@@ -145,14 +145,11 @@ static struct PostcopyBlocktimeContext *blocktime_context_new(void)
static uint32List *get_vcpu_blocktime_list(PostcopyBlocktimeContext *ctx)
{
MachineState *ms = MACHINE(qdev_get_machine());
- uint32List *list = NULL, *entry = NULL;
+ uint32List *list = NULL;
int i;
for (i = ms->smp.cpus - 1; i >= 0; i--) {
- entry = g_new0(uint32List, 1);
- entry->value = ctx->vcpu_blocktime[i];
- entry->next = list;
- list = entry;
+ QAPI_LIST_ADD(list, ctx->vcpu_blocktime[i]);
}
return list;
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 9789f4277f50..629c3d1bf741 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -1248,7 +1248,8 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
const char *cap = qdict_get_str(qdict, "capability");
bool state = qdict_get_bool(qdict, "state");
Error *err = NULL;
- MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
+ MigrationCapabilityStatusList *caps = NULL;
+ MigrationCapabilityStatus *value = NULL;
int val;
val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err);
@@ -1256,10 +1257,10 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
goto end;
}
- caps->value = g_malloc0(sizeof(*caps->value));
- caps->value->capability = val;
- caps->value->state = state;
- caps->next = NULL;
+ value = g_malloc0(sizeof(*value));
+ value->capability = val;
+ value->state = state;
+ QAPI_LIST_ADD(caps, value);
qmp_migrate_set_capabilities(caps, &err);
end:
diff --git a/qemu-img.c b/qemu-img.c
index 2103507936ea..4cfa8bccc5e7 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1643,14 +1643,13 @@ static void do_dirty_bitmap_merge(const char *dst_node, const char *dst_name,
Error **errp)
{
BlockDirtyBitmapMergeSource *merge_src;
- BlockDirtyBitmapMergeSourceList *list;
+ BlockDirtyBitmapMergeSourceList *list = NULL;
merge_src = g_new0(BlockDirtyBitmapMergeSource, 1);
merge_src->type = QTYPE_QDICT;
merge_src->u.external.node = g_strdup(src_node);
merge_src->u.external.name = g_strdup(src_name);
- list = g_new0(BlockDirtyBitmapMergeSourceList, 1);
- list->value = merge_src;
+ QAPI_LIST_ADD(list, merge_src);
qmp_block_dirty_bitmap_merge(dst_node, dst_name, list, errp);
qapi_free_BlockDirtyBitmapMergeSourceList(list);
}
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 3bffee99d4c9..06540425ded2 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1211,7 +1211,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
{
FsMountList mounts;
struct FsMount *mount;
- GuestFilesystemInfoList *new, *ret = NULL;
+ GuestFilesystemInfoList *ret = NULL;
Error *local_err = NULL;
QTAILQ_INIT(&mounts);
@@ -1224,10 +1224,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
QTAILQ_FOREACH(mount, &mounts, next) {
g_debug("Building guest fsinfo for '%s'", mount->dirname);
- new = g_malloc0(sizeof(*ret));
- new->value = build_guest_fsinfo(mount, &local_err);
- new->next = ret;
- ret = new;
+ QAPI_LIST_ADD(ret, build_guest_fsinfo(mount, &local_err));
if (local_err) {
error_propagate(errp, local_err);
qapi_free_GuestFilesystemInfoList(ret);
@@ -1493,7 +1490,6 @@ GuestFilesystemTrimResponse *
qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
{
GuestFilesystemTrimResponse *response;
- GuestFilesystemTrimResultList *list;
GuestFilesystemTrimResult *result;
int ret = 0;
FsMountList mounts;
@@ -1517,10 +1513,7 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
result = g_malloc0(sizeof(*result));
result->path = g_strdup(mount->dirname);
- list = g_malloc0(sizeof(*list));
- list->value = result;
- list->next = response->paths;
- response->paths = list;
+ QAPI_LIST_ADD(response->paths, result);
fd = qemu_open_old(mount->dirname, O_RDONLY);
if (fd == -1) {
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 0c3c05484f5f..cc5736c3bba8 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -926,10 +926,8 @@ static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
error_free(local_err);
goto out;
}
- list = g_malloc0(sizeof(*list));
- list->value = disk;
+ QAPI_LIST_ADD(list, disk);
disk = NULL;
- list->next = NULL;
goto out;
} else {
error_setg_win32(errp, GetLastError(),
@@ -1064,7 +1062,7 @@ free:
GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
{
HANDLE vol_h;
- GuestFilesystemInfoList *new, *ret = NULL;
+ GuestFilesystemInfoList *ret = NULL;
char guid[256];
vol_h = FindFirstVolume(guid, sizeof(guid));
@@ -1082,10 +1080,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
error_free(local_err);
continue;
}
- new = g_malloc(sizeof(*ret));
- new->value = info;
- new->next = ret;
- ret = new;
+ QAPI_LIST_ADD(ret, info);
} while (FindNextVolume(vol_h, guid, sizeof(guid)));
if (GetLastError() != ERROR_NO_MORE_FILES) {
@@ -1268,11 +1263,7 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
res->path = path;
- list = g_new0(GuestFilesystemTrimResultList, 1);
- list->value = res;
- list->next = resp->paths;
-
- resp->paths = list;
+ QAPI_LIST_ADD(resp->paths, res);
memset(argv, 0, sizeof(argv));
argv[0] = (gchar *)"defrag.exe";
diff --git a/qga/commands.c b/qga/commands.c
index 3dcd5fbe5c4d..27118df6caea 100644
--- a/qga/commands.c
+++ b/qga/commands.c
@@ -66,17 +66,13 @@ static void qmp_command_info(const QmpCommand *cmd, void *opaque)
{
GuestAgentInfo *info = opaque;
GuestAgentCommandInfo *cmd_info;
- GuestAgentCommandInfoList *cmd_info_list;
cmd_info = g_new0(GuestAgentCommandInfo, 1);
cmd_info->name = g_strdup(qmp_command_name(cmd));
cmd_info->enabled = qmp_command_is_enabled(cmd);
cmd_info->success_response = qmp_has_success_response(cmd);
- cmd_info_list = g_new0(GuestAgentCommandInfoList, 1);
- cmd_info_list->value = cmd_info;
- cmd_info_list->next = info->supported_commands;
- info->supported_commands = cmd_info_list;
+ QAPI_LIST_ADD(info->supported_commands, cmd_info);
}
struct GuestAgentInfo *qmp_guest_info(Error **errp)
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
index 310ab2d0481d..5ac9272ffeea 100644
--- a/qom/qom-qmp-cmds.c
+++ b/qom/qom-qmp-cmds.c
@@ -46,14 +46,12 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
object_property_iter_init(&iter, obj);
while ((prop = object_property_iter_next(&iter))) {
- ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
+ ObjectPropertyInfo *value = g_malloc0(sizeof(ObjectPropertyInfo));
- entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
- entry->next = props;
- props = entry;
+ QAPI_LIST_ADD(props, value);
- entry->value->name = g_strdup(prop->name);
- entry->value->type = g_strdup(prop->type);
+ value->name = g_strdup(prop->name);
+ value->type = g_strdup(prop->type);
}
return props;
@@ -90,7 +88,7 @@ QObject *qmp_qom_get(const char *path, const char *property, Error **errp)
static void qom_list_types_tramp(ObjectClass *klass, void *data)
{
- ObjectTypeInfoList *e, **pret = data;
+ ObjectTypeInfoList **pret = data;
ObjectTypeInfo *info;
ObjectClass *parent = object_class_get_parent(klass);
@@ -102,10 +100,7 @@ static void qom_list_types_tramp(ObjectClass *klass, void *data)
info->parent = g_strdup(object_class_get_name(parent));
}
- e = g_malloc0(sizeof(*e));
- e->value = info;
- e->next = *pret;
- *pret = e;
+ QAPI_LIST_ADD(*pret, info);
}
ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
@@ -155,7 +150,6 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
object_property_iter_init(&iter, obj);
while ((prop = object_property_iter_next(&iter))) {
ObjectPropertyInfo *info;
- ObjectPropertyInfoList *entry;
/* Skip Object and DeviceState properties */
if (strcmp(prop->name, "type") == 0 ||
@@ -181,10 +175,7 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
info->default_value = qobject_ref(prop->defval);
info->has_default_value = !!info->default_value;
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = prop_list;
- prop_list = entry;
+ QAPI_LIST_ADD(prop_list, info);
}
object_unref(obj);
@@ -222,7 +213,6 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
}
while ((prop = object_property_iter_next(&iter))) {
ObjectPropertyInfo *info;
- ObjectPropertyInfoList *entry;
info = g_malloc0(sizeof(*info));
info->name = g_strdup(prop->name);
@@ -230,10 +220,7 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
info->has_description = !!prop->description;
info->description = g_strdup(prop->description);
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = prop_list;
- prop_list = entry;
+ QAPI_LIST_ADD(prop_list, info);
}
object_unref(obj);
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 97bb6b8c01b4..df150f3c3eeb 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -8293,7 +8293,6 @@ static void arm_cpu_add_definition(gpointer data, gpointer user_data)
{
ObjectClass *oc = data;
CpuDefinitionInfoList **cpu_list = user_data;
- CpuDefinitionInfoList *entry;
CpuDefinitionInfo *info;
const char *typename;
@@ -8303,10 +8302,7 @@ static void arm_cpu_add_definition(gpointer data, gpointer user_data)
strlen(typename) - strlen("-" TYPE_ARM_CPU));
info->q_typename = g_strdup(typename);
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = *cpu_list;
- *cpu_list = entry;
+ QAPI_LIST_ADD(*cpu_list, info);
}
CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
diff --git a/target/arm/monitor.c b/target/arm/monitor.c
index 169d8a64b651..771101656535 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -42,15 +42,6 @@ static GICCapability *gic_cap_new(int version)
return cap;
}
-static GICCapabilityList *gic_cap_list_add(GICCapabilityList *head,
- GICCapability *cap)
-{
- GICCapabilityList *item = g_new0(GICCapabilityList, 1);
- item->value = cap;
- item->next = head;
- return item;
-}
-
static inline void gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3)
{
#ifdef CONFIG_KVM
@@ -84,8 +75,8 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
gic_cap_kvm_probe(v2, v3);
- head = gic_cap_list_add(head, v2);
- head = gic_cap_list_add(head, v3);
+ QAPI_LIST_ADD(head, v2);
+ QAPI_LIST_ADD(head, v3);
return head;
}
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 0d8606958e9e..9ae6661f97e3 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -4984,7 +4984,6 @@ static void x86_cpu_definition_entry(gpointer data, gpointer user_data)
ObjectClass *oc = data;
X86CPUClass *cc = X86_CPU_CLASS(oc);
CpuDefinitionInfoList **cpu_list = user_data;
- CpuDefinitionInfoList *entry;
CpuDefinitionInfo *info;
info = g_malloc0(sizeof(*info));
@@ -5009,10 +5008,7 @@ static void x86_cpu_definition_entry(gpointer data, gpointer user_data)
info->has_alias_of = !!info->alias_of;
}
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = *cpu_list;
- *cpu_list = entry;
+ QAPI_LIST_ADD(*cpu_list, info);
}
CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
diff --git a/target/mips/helper.c b/target/mips/helper.c
index afd78b1990be..036bacc24b22 100644
--- a/target/mips/helper.c
+++ b/target/mips/helper.c
@@ -1502,7 +1502,6 @@ static void mips_cpu_add_definition(gpointer data, gpointer user_data)
{
ObjectClass *oc = data;
CpuDefinitionInfoList **cpu_list = user_data;
- CpuDefinitionInfoList *entry;
CpuDefinitionInfo *info;
const char *typename;
@@ -1512,10 +1511,7 @@ static void mips_cpu_add_definition(gpointer data, gpointer user_data)
strlen(typename) - strlen("-" TYPE_MIPS_CPU));
info->q_typename = g_strdup(typename);
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = *cpu_list;
- *cpu_list = entry;
+ QAPI_LIST_ADD(*cpu_list, info);
}
CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 461e0b8f4a8d..a837ac66c9c8 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -427,7 +427,6 @@ static void create_cpu_model_list(ObjectClass *klass, void *opaque)
{
struct CpuDefinitionInfoListData *cpu_list_data = opaque;
CpuDefinitionInfoList **cpu_list = &cpu_list_data->list;
- CpuDefinitionInfoList *entry;
CpuDefinitionInfo *info;
char *name = g_strdup(object_class_get_name(klass));
S390CPUClass *scc = S390_CPU_CLASS(klass);
@@ -454,10 +453,7 @@ static void create_cpu_model_list(ObjectClass *klass, void *opaque)
object_unref(obj);
}
- entry = g_new0(CpuDefinitionInfoList, 1);
- entry->value = info;
- entry->next = *cpu_list;
- *cpu_list = entry;
+ QAPI_LIST_ADD(*cpu_list, info);
}
CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
@@ -624,12 +620,8 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
static void list_add_feat(const char *name, void *opaque)
{
strList **last = (strList **) opaque;
- strList *entry;
- entry = g_new0(strList, 1);
- entry->value = g_strdup(name);
- entry->next = *last;
- *last = entry;
+ QAPI_LIST_ADD(*last, g_strdup(name));
}
CpuModelCompareInfo *qmp_query_cpu_model_comparison(CpuModelInfo *infoa,
diff --git a/tests/test-clone-visitor.c b/tests/test-clone-visitor.c
index 5e1e8b2f5e8a..03788d355130 100644
--- a/tests/test-clone-visitor.c
+++ b/tests/test-clone-visitor.c
@@ -65,16 +65,13 @@ static void test_clone_alternate(void)
static void test_clone_list_union(void)
{
- uint8List *src, *dst;
+ uint8List *src = NULL, *dst;
uint8List *tmp = NULL;
int i;
/* Build list in reverse */
for (i = 10; i; i--) {
- src = g_new0(uint8List, 1);
- src->next = tmp;
- src->value = i;
- tmp = src;
+ QAPI_LIST_ADD(src, i);
}
dst = QAPI_CLONE(uint8List, src);
diff --git a/tests/test-qobject-output-visitor.c b/tests/test-qobject-output-visitor.c
index 1c856d9bd20a..95487b139801 100644
--- a/tests/test-qobject-output-visitor.c
+++ b/tests/test-qobject-output-visitor.c
@@ -223,7 +223,8 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
const void *unused)
{
const char *value_str = "list value";
- TestStructList *p, *head = NULL;
+ TestStruct *value;
+ TestStructList *head = NULL;
const int max_items = 10;
bool value_bool = true;
int value_int = 10;
@@ -233,14 +234,12 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
/* Build the list in reverse order... */
for (i = 0; i < max_items; i++) {
- p = g_malloc0(sizeof(*p));
- p->value = g_malloc0(sizeof(*p->value));
- p->value->integer = value_int + (max_items - i - 1);
- p->value->boolean = value_bool;
- p->value->string = g_strdup(value_str);
+ value = g_malloc0(sizeof(*value));
+ value->integer = value_int + (max_items - i - 1);
+ value->boolean = value_bool;
+ value->string = g_strdup(value_str);
- p->next = head;
- head = p;
+ QAPI_LIST_ADD(head, value);
}
visit_type_TestStructList(data->ov, NULL, &head, &error_abort);
@@ -270,26 +269,25 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data,
const void *unused)
{
- UserDefTwoList *p, *head = NULL;
+ UserDefTwo *value;
+ UserDefTwoList *head = NULL;
const char string[] = "foo bar";
int i, max_count = 1024;
for (i = 0; i < max_count; i++) {
- p = g_malloc0(sizeof(*p));
- p->value = g_malloc0(sizeof(*p->value));
+ value = g_malloc0(sizeof(*value));
- p->value->string0 = g_strdup(string);
- p->value->dict1 = g_new0(UserDefTwoDict, 1);
- p->value->dict1->string1 = g_strdup(string);
- p->value->dict1->dict2 = g_new0(UserDefTwoDictDict, 1);
- p->value->dict1->dict2->userdef = g_new0(UserDefOne, 1);
- p->value->dict1->dict2->userdef->string = g_strdup(string);
- p->value->dict1->dict2->userdef->integer = 42;
- p->value->dict1->dict2->string = g_strdup(string);
- p->value->dict1->has_dict3 = false;
+ value->string0 = g_strdup(string);
+ value->dict1 = g_new0(UserDefTwoDict, 1);
+ value->dict1->string1 = g_strdup(string);
+ value->dict1->dict2 = g_new0(UserDefTwoDictDict, 1);
+ value->dict1->dict2->userdef = g_new0(UserDefOne, 1);
+ value->dict1->dict2->userdef->string = g_strdup(string);
+ value->dict1->dict2->userdef->integer = 42;
+ value->dict1->dict2->string = g_strdup(string);
+ value->dict1->has_dict3 = false;
- p->next = head;
- head = p;
+ QAPI_LIST_ADD(head, value);
}
qapi_free_UserDefTwoList(head);
diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c
index 1c5a8b94ea87..efbf744fcf25 100644
--- a/tests/test-visitor-serialization.c
+++ b/tests/test-visitor-serialization.c
@@ -704,10 +704,7 @@ static void test_nested_struct_list(gconstpointer opaque)
int i = 0;
for (i = 0; i < 8; i++) {
- tmp = g_new0(UserDefTwoList, 1);
- tmp->value = nested_struct_create();
- tmp->next = listp;
- listp = tmp;
+ QAPI_LIST_ADD(listp, nested_struct_create());
}
ops->serialize(listp, &serialize_data, visit_nested_struct_list,
diff --git a/trace/qmp.c b/trace/qmp.c
index 38246e1aa692..8755835edabc 100644
--- a/trace/qmp.c
+++ b/trace/qmp.c
@@ -92,39 +92,37 @@ TraceEventInfoList *qmp_trace_event_get_state(const char *name,
/* Get states (all errors checked above) */
trace_event_iter_init(&iter, name);
while ((ev = trace_event_iter_next(&iter)) != NULL) {
- TraceEventInfoList *elem;
+ TraceEventInfo *value;
bool is_vcpu = trace_event_is_vcpu(ev);
if (has_vcpu && !is_vcpu) {
continue;
}
- elem = g_new(TraceEventInfoList, 1);
- elem->value = g_new(TraceEventInfo, 1);
- elem->value->vcpu = is_vcpu;
- elem->value->name = g_strdup(trace_event_get_name(ev));
+ value = g_new(TraceEventInfo, 1);
+ value->vcpu = is_vcpu;
+ value->name = g_strdup(trace_event_get_name(ev));
if (!trace_event_get_state_static(ev)) {
- elem->value->state = TRACE_EVENT_STATE_UNAVAILABLE;
+ value->state = TRACE_EVENT_STATE_UNAVAILABLE;
} else {
if (has_vcpu) {
if (is_vcpu) {
if (trace_event_get_vcpu_state_dynamic(cpu, ev)) {
- elem->value->state = TRACE_EVENT_STATE_ENABLED;
+ value->state = TRACE_EVENT_STATE_ENABLED;
} else {
- elem->value->state = TRACE_EVENT_STATE_DISABLED;
+ value->state = TRACE_EVENT_STATE_DISABLED;
}
}
/* else: already skipped above */
} else {
if (trace_event_get_state_dynamic(ev)) {
- elem->value->state = TRACE_EVENT_STATE_ENABLED;
+ value->state = TRACE_EVENT_STATE_ENABLED;
} else {
- elem->value->state = TRACE_EVENT_STATE_DISABLED;
+ value->state = TRACE_EVENT_STATE_DISABLED;
}
}
}
- elem->next = events;
- events = elem;
+ QAPI_LIST_ADD(events, value);
}
return events;
diff --git a/ui/vnc.c b/ui/vnc.c
index f006aa1afdb2..f39cfc952906 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -365,14 +365,11 @@ static VncDisplay *vnc_display_find(const char *id)
static VncClientInfoList *qmp_query_client_list(VncDisplay *vd)
{
- VncClientInfoList *cinfo, *prev = NULL;
+ VncClientInfoList *prev = NULL;
VncState *client;
QTAILQ_FOREACH(client, &vd->clients, next) {
- cinfo = g_new0(VncClientInfoList, 1);
- cinfo->value = qmp_query_vnc_client(client);
- cinfo->next = prev;
- prev = cinfo;
+ QAPI_LIST_ADD(prev, qmp_query_vnc_client(client));
}
return prev;
}
@@ -453,7 +450,6 @@ static VncServerInfo2List *qmp_query_server_entry(QIOChannelSocket *ioc,
int subauth,
VncServerInfo2List *prev)
{
- VncServerInfo2List *list;
VncServerInfo2 *info;
Error *err = NULL;
SocketAddress *addr;
@@ -476,10 +472,8 @@ static VncServerInfo2List *qmp_query_server_entry(QIOChannelSocket *ioc,
qmp_query_auth(auth, subauth, &info->auth,
&info->vencrypt, &info->has_vencrypt);
- list = g_new0(VncServerInfo2List, 1);
- list->value = info;
- list->next = prev;
- return list;
+ QAPI_LIST_ADD(prev, info);
+ return prev;
}
static void qmp_query_auth(int auth, int subauth,
@@ -554,7 +548,7 @@ static void qmp_query_auth(int auth, int subauth,
VncInfo2List *qmp_query_vnc_servers(Error **errp)
{
- VncInfo2List *item, *prev = NULL;
+ VncInfo2List *prev = NULL;
VncInfo2 *info;
VncDisplay *vd;
DeviceState *dev;
@@ -583,10 +577,7 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp)
vd->ws_subauth, info->server);
}
- item = g_new0(VncInfo2List, 1);
- item->value = info;
- item->next = prev;
- prev = item;
+ QAPI_LIST_ADD(prev, info);
}
return prev;
}
diff --git a/util/qemu-config.c b/util/qemu-config.c
index 660f47b0050f..495ada45f3df 100644
--- a/util/qemu-config.c
+++ b/util/qemu-config.c
@@ -55,7 +55,7 @@ QemuOpts *qemu_find_opts_singleton(const char *group)
static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
{
- CommandLineParameterInfoList *param_list = NULL, *entry;
+ CommandLineParameterInfoList *param_list = NULL;
CommandLineParameterInfo *info;
int i;
@@ -87,10 +87,7 @@ static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
info->q_default = g_strdup(desc[i].def_value_str);
}
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = param_list;
- param_list = entry;
+ QAPI_LIST_ADD(param_list, info);
}
return param_list;
@@ -246,7 +243,7 @@ CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
const char *option,
Error **errp)
{
- CommandLineOptionInfoList *conf_list = NULL, *entry;
+ CommandLineOptionInfoList *conf_list = NULL;
CommandLineOptionInfo *info;
int i;
@@ -262,10 +259,7 @@ CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
info->parameters =
query_option_descs(vm_config_groups[i]->desc);
}
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = conf_list;
- conf_list = entry;
+ QAPI_LIST_ADD(conf_list, info);
}
}
diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc
index bb66526280ef..5795d0e5af2c 100644
--- a/target/ppc/translate_init.c.inc
+++ b/target/ppc/translate_init.c.inc
@@ -10621,7 +10621,6 @@ static void ppc_cpu_defs_entry(gpointer data, gpointer user_data)
ObjectClass *oc = data;
CpuDefinitionInfoList **first = user_data;
const char *typename;
- CpuDefinitionInfoList *entry;
CpuDefinitionInfo *info;
typename = object_class_get_name(oc);
@@ -10629,10 +10628,7 @@ static void ppc_cpu_defs_entry(gpointer data, gpointer user_data)
info->name = g_strndup(typename,
strlen(typename) - strlen(POWERPC_CPU_TYPE_SUFFIX));
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = *first;
- *first = entry;
+ QAPI_LIST_ADD(*first, info);
}
CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
@@ -10648,7 +10644,6 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) {
PowerPCCPUAlias *alias = &ppc_cpu_aliases[i];
ObjectClass *oc;
- CpuDefinitionInfoList *entry;
CpuDefinitionInfo *info;
oc = ppc_cpu_class_by_name(alias->model);
@@ -10660,10 +10655,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
info->name = g_strdup(alias->alias);
info->q_typename = g_strdup(object_class_get_name(oc));
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = cpu_list;
- cpu_list = entry;
+ QAPI_LIST_ADD(cpu_list, info);
}
return cpu_list;
--
2.29.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible
2020-10-27 5:05 ` [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible Eric Blake
@ 2020-10-27 5:53 ` Thomas Huth
2020-10-27 6:39 ` David Gibson
` (3 subsequent siblings)
4 siblings, 0 replies; 28+ messages in thread
From: Thomas Huth @ 2020-10-27 5:53 UTC (permalink / raw)
To: Eric Blake, qemu-devel
Cc: Peter Maydell, pkrempa, Michael S. Tsirkin, Jason Wang,
Jiaxun Yang, rjones, Gerd Hoffmann, Michael Roth, qemu-block,
Juan Quintela, David Hildenbrand, armbru, Halil Pasic,
Christian Borntraeger, Marc-André Lureau, David Gibson,
Aleksandar Rikalo, Jiri Pirko, Eduardo Habkost,
Dr. David Alan Gilbert, open list:S390 KVM CPUs,
open list:GLUSTER, stefanha, Richard Henderson, kwolf, vsementsov,
Daniel P. Berrangé, Cornelia Huck,
Philippe Mathieu-Daudé, Max Reitz, open list:ARM TCG CPUs,
open list:PowerPC TCG CPUs, Paolo Bonzini, Aurelien Jarno
On 27/10/2020 06.05, Eric Blake wrote:
> Anywhere we create a list of just one item or by prepending items
> (typically because order doesn't matter), we can use the now-public
> macro. But places where we must keep the list in order by appending
> remain open-coded.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
> ---
> docs/devel/writing-qmp-commands.txt | 13 +++------
> hw/net/rocker/rocker_fp.h | 2 +-
> block/gluster.c | 19 +++++--------
> chardev/char.c | 21 +++++++--------
> hw/core/machine.c | 6 +----
> hw/net/rocker/rocker.c | 8 +++---
> hw/net/rocker/rocker_fp.c | 14 +++++-----
> hw/net/virtio-net.c | 21 +++++----------
> migration/migration.c | 7 ++---
> migration/postcopy-ram.c | 7 ++---
> monitor/hmp-cmds.c | 11 ++++----
> qemu-img.c | 5 ++--
> qga/commands-posix.c | 13 +++------
> qga/commands-win32.c | 17 +++---------
> qga/commands.c | 6 +----
> qom/qom-qmp-cmds.c | 29 ++++++--------------
> target/arm/helper.c | 6 +----
> target/arm/monitor.c | 13 ++-------
> target/i386/cpu.c | 6 +----
> target/mips/helper.c | 6 +----
> target/s390x/cpu_models.c | 12 ++-------
> tests/test-clone-visitor.c | 7 ++---
> tests/test-qobject-output-visitor.c | 42 ++++++++++++++---------------
> tests/test-visitor-serialization.c | 5 +---
> trace/qmp.c | 22 +++++++--------
> ui/vnc.c | 21 +++++----------
> util/qemu-config.c | 14 +++-------
> target/ppc/translate_init.c.inc | 12 ++-------
> 28 files changed, 119 insertions(+), 246 deletions(-)
>
> diff --git a/docs/devel/writing-qmp-commands.txt b/docs/devel/writing-qmp-commands.txt
> index 46a6c48683f5..3e11eeaa1893 100644
> --- a/docs/devel/writing-qmp-commands.txt
> +++ b/docs/devel/writing-qmp-commands.txt
> @@ -531,15 +531,10 @@ TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
> bool current = true;
>
> for (p = alarm_timers; p->name; p++) {
> - TimerAlarmMethodList *info = g_malloc0(sizeof(*info));
> - info->value = g_malloc0(sizeof(*info->value));
> - info->value->method_name = g_strdup(p->name);
> - info->value->current = current;
> -
> - current = false;
> -
> - info->next = method_list;
> - method_list = info;
> + TimerAlarmMethod *value = g_new0(TimerAlarmMethod, 1);
White space damage - please replace the TAB with spaces.
> + value->method_name = g_strdup(p->name);
> + value->current = current;
> + QAPI_LIST_ADD(method_list, value);
> }
Thomas
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible
2020-10-27 5:05 ` [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible Eric Blake
2020-10-27 5:53 ` Thomas Huth
@ 2020-10-27 6:39 ` David Gibson
2020-10-27 10:09 ` Markus Armbruster
` (2 subsequent siblings)
4 siblings, 0 replies; 28+ messages in thread
From: David Gibson @ 2020-10-27 6:39 UTC (permalink / raw)
To: Eric Blake
Cc: Peter Maydell, pkrempa, Michael S. Tsirkin, Jason Wang,
qemu-devel, Jiaxun Yang, Michael Roth, Gerd Hoffmann, qemu-block,
Juan Quintela, David Hildenbrand, armbru, Halil Pasic,
Christian Borntraeger, Thomas Huth, Marc-André Lureau,
Aleksandar Rikalo, Jiri Pirko, Eduardo Habkost,
Dr. David Alan Gilbert, open list:S390 KVM CPUs,
open list:GLUSTER, stefanha, Richard Henderson, kwolf, vsementsov,
Daniel P. Berrangé, Cornelia Huck, rjones, Max Reitz,
open list:ARM TCG CPUs, open list:PowerPC TCG CPUs, Paolo Bonzini,
Aurelien Jarno, Philippe Mathieu-Daudé
[-- Attachment #1: Type: text/plain, Size: 41570 bytes --]
On Tue, Oct 27, 2020 at 12:05:56AM -0500, Eric Blake wrote:
> Anywhere we create a list of just one item or by prepending items
> (typically because order doesn't matter), we can use the now-public
> macro. But places where we must keep the list in order by appending
> remain open-coded.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
> ---
> docs/devel/writing-qmp-commands.txt | 13 +++------
> hw/net/rocker/rocker_fp.h | 2 +-
> block/gluster.c | 19 +++++--------
> chardev/char.c | 21 +++++++--------
> hw/core/machine.c | 6 +----
> hw/net/rocker/rocker.c | 8 +++---
> hw/net/rocker/rocker_fp.c | 14 +++++-----
> hw/net/virtio-net.c | 21 +++++----------
> migration/migration.c | 7 ++---
> migration/postcopy-ram.c | 7 ++---
> monitor/hmp-cmds.c | 11 ++++----
> qemu-img.c | 5 ++--
> qga/commands-posix.c | 13 +++------
> qga/commands-win32.c | 17 +++---------
> qga/commands.c | 6 +----
> qom/qom-qmp-cmds.c | 29 ++++++--------------
> target/arm/helper.c | 6 +----
> target/arm/monitor.c | 13 ++-------
> target/i386/cpu.c | 6 +----
> target/mips/helper.c | 6 +----
> target/s390x/cpu_models.c | 12 ++-------
> tests/test-clone-visitor.c | 7 ++---
> tests/test-qobject-output-visitor.c | 42 ++++++++++++++---------------
> tests/test-visitor-serialization.c | 5 +---
> trace/qmp.c | 22 +++++++--------
> ui/vnc.c | 21 +++++----------
> util/qemu-config.c | 14 +++-------
> target/ppc/translate_init.c.inc | 12 ++-------
ppc parts
Acked-by: David Gibson <david@gibson.dropbear.id.au>
> 28 files changed, 119 insertions(+), 246 deletions(-)
>
> diff --git a/docs/devel/writing-qmp-commands.txt b/docs/devel/writing-qmp-commands.txt
> index 46a6c48683f5..3e11eeaa1893 100644
> --- a/docs/devel/writing-qmp-commands.txt
> +++ b/docs/devel/writing-qmp-commands.txt
> @@ -531,15 +531,10 @@ TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
> bool current = true;
>
> for (p = alarm_timers; p->name; p++) {
> - TimerAlarmMethodList *info = g_malloc0(sizeof(*info));
> - info->value = g_malloc0(sizeof(*info->value));
> - info->value->method_name = g_strdup(p->name);
> - info->value->current = current;
> -
> - current = false;
> -
> - info->next = method_list;
> - method_list = info;
> + TimerAlarmMethod *value = g_new0(TimerAlarmMethod, 1);
> + value->method_name = g_strdup(p->name);
> + value->current = current;
> + QAPI_LIST_ADD(method_list, value);
> }
>
> return method_list;
> diff --git a/hw/net/rocker/rocker_fp.h b/hw/net/rocker/rocker_fp.h
> index dbe1dd329a4b..4cb0bb9ccf81 100644
> --- a/hw/net/rocker/rocker_fp.h
> +++ b/hw/net/rocker/rocker_fp.h
> @@ -28,7 +28,7 @@ int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt);
>
> char *fp_port_get_name(FpPort *port);
> bool fp_port_get_link_up(FpPort *port);
> -void fp_port_get_info(FpPort *port, RockerPortList *info);
> +void fp_port_get_info(FpPort *port, RockerPort *info);
> void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr);
> void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr);
> uint8_t fp_port_get_learning(FpPort *port);
> diff --git a/block/gluster.c b/block/gluster.c
> index 4f1448e2bc88..cf446c23f85d 100644
> --- a/block/gluster.c
> +++ b/block/gluster.c
> @@ -359,8 +359,8 @@ static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
> return -EINVAL;
> }
>
> - gconf->server = g_new0(SocketAddressList, 1);
> - gconf->server->value = gsconf = g_new0(SocketAddress, 1);
> + gsconf = g_new0(SocketAddress, 1);
> + QAPI_LIST_ADD(gconf->server, gsconf);
>
> /* transport */
> if (!uri->scheme || !strcmp(uri->scheme, "gluster")) {
> @@ -514,7 +514,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
> {
> QemuOpts *opts;
> SocketAddress *gsconf = NULL;
> - SocketAddressList *curr = NULL;
> + SocketAddressList **curr;
> QDict *backing_options = NULL;
> Error *local_err = NULL;
> char *str = NULL;
> @@ -547,6 +547,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
> }
> gconf->path = g_strdup(ptr);
> qemu_opts_del(opts);
> + curr = &gconf->server;
>
> for (i = 0; i < num_servers; i++) {
> str = g_strdup_printf(GLUSTER_OPT_SERVER_PATTERN"%d.", i);
> @@ -655,15 +656,9 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
> qemu_opts_del(opts);
> }
>
> - if (gconf->server == NULL) {
> - gconf->server = g_new0(SocketAddressList, 1);
> - gconf->server->value = gsconf;
> - curr = gconf->server;
> - } else {
> - curr->next = g_new0(SocketAddressList, 1);
> - curr->next->value = gsconf;
> - curr = curr->next;
> - }
> + *curr = g_new0(SocketAddressList, 1);
> + (*curr)->value = gsconf;
> + curr = &(*curr)->next;
> gsconf = NULL;
>
> qobject_unref(backing_options);
> diff --git a/chardev/char.c b/chardev/char.c
> index 78553125d311..8dd7ef4c5935 100644
> --- a/chardev/char.c
> +++ b/chardev/char.c
> @@ -776,15 +776,14 @@ static int qmp_query_chardev_foreach(Object *obj, void *data)
> {
> Chardev *chr = CHARDEV(obj);
> ChardevInfoList **list = data;
> - ChardevInfoList *info = g_malloc0(sizeof(*info));
> + ChardevInfo *value;
>
> - info->value = g_malloc0(sizeof(*info->value));
> - info->value->label = g_strdup(chr->label);
> - info->value->filename = g_strdup(chr->filename);
> - info->value->frontend_open = chr->be && chr->be->fe_open;
> + value = g_malloc0(sizeof(*value));
> + value->label = g_strdup(chr->label);
> + value->filename = g_strdup(chr->filename);
> + value->frontend_open = chr->be && chr->be->fe_open;
>
> - info->next = *list;
> - *list = info;
> + QAPI_LIST_ADD(*list, value);
>
> return 0;
> }
> @@ -803,12 +802,10 @@ static void
> qmp_prepend_backend(const char *name, void *opaque)
> {
> ChardevBackendInfoList **list = opaque;
> - ChardevBackendInfoList *info = g_malloc0(sizeof(*info));
> + ChardevBackendInfo *value = g_new0(ChardevBackendInfo, 1);
>
> - info->value = g_malloc0(sizeof(*info->value));
> - info->value->name = g_strdup(name);
> - info->next = *list;
> - *list = info;
> + value->name = g_strdup(name);
> + QAPI_LIST_ADD(*list, value);
> }
>
> ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
> diff --git a/hw/core/machine.c b/hw/core/machine.c
> index c5e0e79e6dbc..a05c4739ca7a 100644
> --- a/hw/core/machine.c
> +++ b/hw/core/machine.c
> @@ -492,11 +492,7 @@ static void machine_set_nvdimm_persistence(Object *obj, const char *value,
>
> void machine_class_allow_dynamic_sysbus_dev(MachineClass *mc, const char *type)
> {
> - strList *item = g_new0(strList, 1);
> -
> - item->value = g_strdup(type);
> - item->next = mc->allowed_dynamic_sysbus_devices;
> - mc->allowed_dynamic_sysbus_devices = item;
> + QAPI_LIST_ADD(mc->allowed_dynamic_sysbus_devices, g_strdup(type));
> }
>
> static void validate_sysbus_device(SysBusDevice *sbdev, void *opaque)
> diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c
> index 1af1e6fa2f9b..a1137e11ff48 100644
> --- a/hw/net/rocker/rocker.c
> +++ b/hw/net/rocker/rocker.c
> @@ -127,13 +127,11 @@ RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
> }
>
> for (i = r->fp_ports - 1; i >= 0; i--) {
> - RockerPortList *info = g_malloc0(sizeof(*info));
> - info->value = g_malloc0(sizeof(*info->value));
> + RockerPort *value = g_malloc0(sizeof(*value));
> struct fp_port *port = r->fp_port[i];
>
> - fp_port_get_info(port, info);
> - info->next = list;
> - list = info;
> + fp_port_get_info(port, value);
> + QAPI_LIST_ADD(list, value);
> }
>
> return list;
> diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c
> index 4aa7da79b81d..a616e709292e 100644
> --- a/hw/net/rocker/rocker_fp.c
> +++ b/hw/net/rocker/rocker_fp.c
> @@ -51,14 +51,14 @@ bool fp_port_get_link_up(FpPort *port)
> return !qemu_get_queue(port->nic)->link_down;
> }
>
> -void fp_port_get_info(FpPort *port, RockerPortList *info)
> +void fp_port_get_info(FpPort *port, RockerPort *value)
> {
> - info->value->name = g_strdup(port->name);
> - info->value->enabled = port->enabled;
> - info->value->link_up = fp_port_get_link_up(port);
> - info->value->speed = port->speed;
> - info->value->duplex = port->duplex;
> - info->value->autoneg = port->autoneg;
> + value->name = g_strdup(port->name);
> + value->enabled = port->enabled;
> + value->link_up = fp_port_get_link_up(port);
> + value->speed = port->speed;
> + value->duplex = port->duplex;
> + value->autoneg = port->autoneg;
> }
>
> void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr)
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index 277289d56e76..6b13d3ca3c8f 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -437,17 +437,14 @@ static void rxfilter_notify(NetClientState *nc)
>
> static intList *get_vlan_table(VirtIONet *n)
> {
> - intList *list, *entry;
> + intList *list;
> int i, j;
>
> list = NULL;
> for (i = 0; i < MAX_VLAN >> 5; i++) {
> for (j = 0; n->vlans[i] && j <= 0x1f; j++) {
> if (n->vlans[i] & (1U << j)) {
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = (i << 5) + j;
> - entry->next = list;
> - list = entry;
> + QAPI_LIST_ADD(list, (i << 5) + j);
> }
> }
> }
> @@ -460,7 +457,7 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
> VirtIONet *n = qemu_get_nic_opaque(nc);
> VirtIODevice *vdev = VIRTIO_DEVICE(n);
> RxFilterInfo *info;
> - strList *str_list, *entry;
> + strList *str_list;
> int i;
>
> info = g_malloc0(sizeof(*info));
> @@ -491,19 +488,15 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
>
> str_list = NULL;
> for (i = 0; i < n->mac_table.first_multi; i++) {
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN);
> - entry->next = str_list;
> - str_list = entry;
> + QAPI_LIST_ADD(str_list,
> + qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN));
> }
> info->unicast_table = str_list;
>
> str_list = NULL;
> for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN);
> - entry->next = str_list;
> - str_list = entry;
> + QAPI_LIST_ADD(str_list,
> + qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN));
> }
> info->multicast_table = str_list;
> info->vlan_table = get_vlan_table(n);
> diff --git a/migration/migration.c b/migration/migration.c
> index deb6005b8d37..239a7e430214 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -368,12 +368,9 @@ int migration_incoming_enable_colo(void)
> void migrate_add_address(SocketAddress *address)
> {
> MigrationIncomingState *mis = migration_incoming_get_current();
> - SocketAddressList *addrs;
>
> - addrs = g_new0(SocketAddressList, 1);
> - addrs->next = mis->socket_address_list;
> - mis->socket_address_list = addrs;
> - addrs->value = QAPI_CLONE(SocketAddress, address);
> + QAPI_LIST_ADD(mis->socket_address_list,
> + QAPI_CLONE(SocketAddress, address));
> }
>
> void qemu_start_incoming_migration(const char *uri, Error **errp)
> diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
> index 0a2f88a87d06..18ac7e06c581 100644
> --- a/migration/postcopy-ram.c
> +++ b/migration/postcopy-ram.c
> @@ -145,14 +145,11 @@ static struct PostcopyBlocktimeContext *blocktime_context_new(void)
> static uint32List *get_vcpu_blocktime_list(PostcopyBlocktimeContext *ctx)
> {
> MachineState *ms = MACHINE(qdev_get_machine());
> - uint32List *list = NULL, *entry = NULL;
> + uint32List *list = NULL;
> int i;
>
> for (i = ms->smp.cpus - 1; i >= 0; i--) {
> - entry = g_new0(uint32List, 1);
> - entry->value = ctx->vcpu_blocktime[i];
> - entry->next = list;
> - list = entry;
> + QAPI_LIST_ADD(list, ctx->vcpu_blocktime[i]);
> }
>
> return list;
> diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
> index 9789f4277f50..629c3d1bf741 100644
> --- a/monitor/hmp-cmds.c
> +++ b/monitor/hmp-cmds.c
> @@ -1248,7 +1248,8 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
> const char *cap = qdict_get_str(qdict, "capability");
> bool state = qdict_get_bool(qdict, "state");
> Error *err = NULL;
> - MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
> + MigrationCapabilityStatusList *caps = NULL;
> + MigrationCapabilityStatus *value = NULL;
> int val;
>
> val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err);
> @@ -1256,10 +1257,10 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
> goto end;
> }
>
> - caps->value = g_malloc0(sizeof(*caps->value));
> - caps->value->capability = val;
> - caps->value->state = state;
> - caps->next = NULL;
> + value = g_malloc0(sizeof(*value));
> + value->capability = val;
> + value->state = state;
> + QAPI_LIST_ADD(caps, value);
> qmp_migrate_set_capabilities(caps, &err);
>
> end:
> diff --git a/qemu-img.c b/qemu-img.c
> index 2103507936ea..4cfa8bccc5e7 100644
> --- a/qemu-img.c
> +++ b/qemu-img.c
> @@ -1643,14 +1643,13 @@ static void do_dirty_bitmap_merge(const char *dst_node, const char *dst_name,
> Error **errp)
> {
> BlockDirtyBitmapMergeSource *merge_src;
> - BlockDirtyBitmapMergeSourceList *list;
> + BlockDirtyBitmapMergeSourceList *list = NULL;
>
> merge_src = g_new0(BlockDirtyBitmapMergeSource, 1);
> merge_src->type = QTYPE_QDICT;
> merge_src->u.external.node = g_strdup(src_node);
> merge_src->u.external.name = g_strdup(src_name);
> - list = g_new0(BlockDirtyBitmapMergeSourceList, 1);
> - list->value = merge_src;
> + QAPI_LIST_ADD(list, merge_src);
> qmp_block_dirty_bitmap_merge(dst_node, dst_name, list, errp);
> qapi_free_BlockDirtyBitmapMergeSourceList(list);
> }
> diff --git a/qga/commands-posix.c b/qga/commands-posix.c
> index 3bffee99d4c9..06540425ded2 100644
> --- a/qga/commands-posix.c
> +++ b/qga/commands-posix.c
> @@ -1211,7 +1211,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
> {
> FsMountList mounts;
> struct FsMount *mount;
> - GuestFilesystemInfoList *new, *ret = NULL;
> + GuestFilesystemInfoList *ret = NULL;
> Error *local_err = NULL;
>
> QTAILQ_INIT(&mounts);
> @@ -1224,10 +1224,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
> QTAILQ_FOREACH(mount, &mounts, next) {
> g_debug("Building guest fsinfo for '%s'", mount->dirname);
>
> - new = g_malloc0(sizeof(*ret));
> - new->value = build_guest_fsinfo(mount, &local_err);
> - new->next = ret;
> - ret = new;
> + QAPI_LIST_ADD(ret, build_guest_fsinfo(mount, &local_err));
> if (local_err) {
> error_propagate(errp, local_err);
> qapi_free_GuestFilesystemInfoList(ret);
> @@ -1493,7 +1490,6 @@ GuestFilesystemTrimResponse *
> qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
> {
> GuestFilesystemTrimResponse *response;
> - GuestFilesystemTrimResultList *list;
> GuestFilesystemTrimResult *result;
> int ret = 0;
> FsMountList mounts;
> @@ -1517,10 +1513,7 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
> result = g_malloc0(sizeof(*result));
> result->path = g_strdup(mount->dirname);
>
> - list = g_malloc0(sizeof(*list));
> - list->value = result;
> - list->next = response->paths;
> - response->paths = list;
> + QAPI_LIST_ADD(response->paths, result);
>
> fd = qemu_open_old(mount->dirname, O_RDONLY);
> if (fd == -1) {
> diff --git a/qga/commands-win32.c b/qga/commands-win32.c
> index 0c3c05484f5f..cc5736c3bba8 100644
> --- a/qga/commands-win32.c
> +++ b/qga/commands-win32.c
> @@ -926,10 +926,8 @@ static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
> error_free(local_err);
> goto out;
> }
> - list = g_malloc0(sizeof(*list));
> - list->value = disk;
> + QAPI_LIST_ADD(list, disk);
> disk = NULL;
> - list->next = NULL;
> goto out;
> } else {
> error_setg_win32(errp, GetLastError(),
> @@ -1064,7 +1062,7 @@ free:
> GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
> {
> HANDLE vol_h;
> - GuestFilesystemInfoList *new, *ret = NULL;
> + GuestFilesystemInfoList *ret = NULL;
> char guid[256];
>
> vol_h = FindFirstVolume(guid, sizeof(guid));
> @@ -1082,10 +1080,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
> error_free(local_err);
> continue;
> }
> - new = g_malloc(sizeof(*ret));
> - new->value = info;
> - new->next = ret;
> - ret = new;
> + QAPI_LIST_ADD(ret, info);
> } while (FindNextVolume(vol_h, guid, sizeof(guid)));
>
> if (GetLastError() != ERROR_NO_MORE_FILES) {
> @@ -1268,11 +1263,7 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
>
> res->path = path;
>
> - list = g_new0(GuestFilesystemTrimResultList, 1);
> - list->value = res;
> - list->next = resp->paths;
> -
> - resp->paths = list;
> + QAPI_LIST_ADD(resp->paths, res);
>
> memset(argv, 0, sizeof(argv));
> argv[0] = (gchar *)"defrag.exe";
> diff --git a/qga/commands.c b/qga/commands.c
> index 3dcd5fbe5c4d..27118df6caea 100644
> --- a/qga/commands.c
> +++ b/qga/commands.c
> @@ -66,17 +66,13 @@ static void qmp_command_info(const QmpCommand *cmd, void *opaque)
> {
> GuestAgentInfo *info = opaque;
> GuestAgentCommandInfo *cmd_info;
> - GuestAgentCommandInfoList *cmd_info_list;
>
> cmd_info = g_new0(GuestAgentCommandInfo, 1);
> cmd_info->name = g_strdup(qmp_command_name(cmd));
> cmd_info->enabled = qmp_command_is_enabled(cmd);
> cmd_info->success_response = qmp_has_success_response(cmd);
>
> - cmd_info_list = g_new0(GuestAgentCommandInfoList, 1);
> - cmd_info_list->value = cmd_info;
> - cmd_info_list->next = info->supported_commands;
> - info->supported_commands = cmd_info_list;
> + QAPI_LIST_ADD(info->supported_commands, cmd_info);
> }
>
> struct GuestAgentInfo *qmp_guest_info(Error **errp)
> diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
> index 310ab2d0481d..5ac9272ffeea 100644
> --- a/qom/qom-qmp-cmds.c
> +++ b/qom/qom-qmp-cmds.c
> @@ -46,14 +46,12 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
>
> object_property_iter_init(&iter, obj);
> while ((prop = object_property_iter_next(&iter))) {
> - ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
> + ObjectPropertyInfo *value = g_malloc0(sizeof(ObjectPropertyInfo));
>
> - entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
> - entry->next = props;
> - props = entry;
> + QAPI_LIST_ADD(props, value);
>
> - entry->value->name = g_strdup(prop->name);
> - entry->value->type = g_strdup(prop->type);
> + value->name = g_strdup(prop->name);
> + value->type = g_strdup(prop->type);
> }
>
> return props;
> @@ -90,7 +88,7 @@ QObject *qmp_qom_get(const char *path, const char *property, Error **errp)
>
> static void qom_list_types_tramp(ObjectClass *klass, void *data)
> {
> - ObjectTypeInfoList *e, **pret = data;
> + ObjectTypeInfoList **pret = data;
> ObjectTypeInfo *info;
> ObjectClass *parent = object_class_get_parent(klass);
>
> @@ -102,10 +100,7 @@ static void qom_list_types_tramp(ObjectClass *klass, void *data)
> info->parent = g_strdup(object_class_get_name(parent));
> }
>
> - e = g_malloc0(sizeof(*e));
> - e->value = info;
> - e->next = *pret;
> - *pret = e;
> + QAPI_LIST_ADD(*pret, info);
> }
>
> ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
> @@ -155,7 +150,6 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
> object_property_iter_init(&iter, obj);
> while ((prop = object_property_iter_next(&iter))) {
> ObjectPropertyInfo *info;
> - ObjectPropertyInfoList *entry;
>
> /* Skip Object and DeviceState properties */
> if (strcmp(prop->name, "type") == 0 ||
> @@ -181,10 +175,7 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
> info->default_value = qobject_ref(prop->defval);
> info->has_default_value = !!info->default_value;
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = prop_list;
> - prop_list = entry;
> + QAPI_LIST_ADD(prop_list, info);
> }
>
> object_unref(obj);
> @@ -222,7 +213,6 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
> }
> while ((prop = object_property_iter_next(&iter))) {
> ObjectPropertyInfo *info;
> - ObjectPropertyInfoList *entry;
>
> info = g_malloc0(sizeof(*info));
> info->name = g_strdup(prop->name);
> @@ -230,10 +220,7 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
> info->has_description = !!prop->description;
> info->description = g_strdup(prop->description);
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = prop_list;
> - prop_list = entry;
> + QAPI_LIST_ADD(prop_list, info);
> }
>
> object_unref(obj);
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 97bb6b8c01b4..df150f3c3eeb 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -8293,7 +8293,6 @@ static void arm_cpu_add_definition(gpointer data, gpointer user_data)
> {
> ObjectClass *oc = data;
> CpuDefinitionInfoList **cpu_list = user_data;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
> const char *typename;
>
> @@ -8303,10 +8302,7 @@ static void arm_cpu_add_definition(gpointer data, gpointer user_data)
> strlen(typename) - strlen("-" TYPE_ARM_CPU));
> info->q_typename = g_strdup(typename);
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = *cpu_list;
> - *cpu_list = entry;
> + QAPI_LIST_ADD(*cpu_list, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> diff --git a/target/arm/monitor.c b/target/arm/monitor.c
> index 169d8a64b651..771101656535 100644
> --- a/target/arm/monitor.c
> +++ b/target/arm/monitor.c
> @@ -42,15 +42,6 @@ static GICCapability *gic_cap_new(int version)
> return cap;
> }
>
> -static GICCapabilityList *gic_cap_list_add(GICCapabilityList *head,
> - GICCapability *cap)
> -{
> - GICCapabilityList *item = g_new0(GICCapabilityList, 1);
> - item->value = cap;
> - item->next = head;
> - return item;
> -}
> -
> static inline void gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3)
> {
> #ifdef CONFIG_KVM
> @@ -84,8 +75,8 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
>
> gic_cap_kvm_probe(v2, v3);
>
> - head = gic_cap_list_add(head, v2);
> - head = gic_cap_list_add(head, v3);
> + QAPI_LIST_ADD(head, v2);
> + QAPI_LIST_ADD(head, v3);
>
> return head;
> }
> diff --git a/target/i386/cpu.c b/target/i386/cpu.c
> index 0d8606958e9e..9ae6661f97e3 100644
> --- a/target/i386/cpu.c
> +++ b/target/i386/cpu.c
> @@ -4984,7 +4984,6 @@ static void x86_cpu_definition_entry(gpointer data, gpointer user_data)
> ObjectClass *oc = data;
> X86CPUClass *cc = X86_CPU_CLASS(oc);
> CpuDefinitionInfoList **cpu_list = user_data;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
>
> info = g_malloc0(sizeof(*info));
> @@ -5009,10 +5008,7 @@ static void x86_cpu_definition_entry(gpointer data, gpointer user_data)
> info->has_alias_of = !!info->alias_of;
> }
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = *cpu_list;
> - *cpu_list = entry;
> + QAPI_LIST_ADD(*cpu_list, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> diff --git a/target/mips/helper.c b/target/mips/helper.c
> index afd78b1990be..036bacc24b22 100644
> --- a/target/mips/helper.c
> +++ b/target/mips/helper.c
> @@ -1502,7 +1502,6 @@ static void mips_cpu_add_definition(gpointer data, gpointer user_data)
> {
> ObjectClass *oc = data;
> CpuDefinitionInfoList **cpu_list = user_data;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
> const char *typename;
>
> @@ -1512,10 +1511,7 @@ static void mips_cpu_add_definition(gpointer data, gpointer user_data)
> strlen(typename) - strlen("-" TYPE_MIPS_CPU));
> info->q_typename = g_strdup(typename);
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = *cpu_list;
> - *cpu_list = entry;
> + QAPI_LIST_ADD(*cpu_list, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
> index 461e0b8f4a8d..a837ac66c9c8 100644
> --- a/target/s390x/cpu_models.c
> +++ b/target/s390x/cpu_models.c
> @@ -427,7 +427,6 @@ static void create_cpu_model_list(ObjectClass *klass, void *opaque)
> {
> struct CpuDefinitionInfoListData *cpu_list_data = opaque;
> CpuDefinitionInfoList **cpu_list = &cpu_list_data->list;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
> char *name = g_strdup(object_class_get_name(klass));
> S390CPUClass *scc = S390_CPU_CLASS(klass);
> @@ -454,10 +453,7 @@ static void create_cpu_model_list(ObjectClass *klass, void *opaque)
> object_unref(obj);
> }
>
> - entry = g_new0(CpuDefinitionInfoList, 1);
> - entry->value = info;
> - entry->next = *cpu_list;
> - *cpu_list = entry;
> + QAPI_LIST_ADD(*cpu_list, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> @@ -624,12 +620,8 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
> static void list_add_feat(const char *name, void *opaque)
> {
> strList **last = (strList **) opaque;
> - strList *entry;
>
> - entry = g_new0(strList, 1);
> - entry->value = g_strdup(name);
> - entry->next = *last;
> - *last = entry;
> + QAPI_LIST_ADD(*last, g_strdup(name));
> }
>
> CpuModelCompareInfo *qmp_query_cpu_model_comparison(CpuModelInfo *infoa,
> diff --git a/tests/test-clone-visitor.c b/tests/test-clone-visitor.c
> index 5e1e8b2f5e8a..03788d355130 100644
> --- a/tests/test-clone-visitor.c
> +++ b/tests/test-clone-visitor.c
> @@ -65,16 +65,13 @@ static void test_clone_alternate(void)
>
> static void test_clone_list_union(void)
> {
> - uint8List *src, *dst;
> + uint8List *src = NULL, *dst;
> uint8List *tmp = NULL;
> int i;
>
> /* Build list in reverse */
> for (i = 10; i; i--) {
> - src = g_new0(uint8List, 1);
> - src->next = tmp;
> - src->value = i;
> - tmp = src;
> + QAPI_LIST_ADD(src, i);
> }
>
> dst = QAPI_CLONE(uint8List, src);
> diff --git a/tests/test-qobject-output-visitor.c b/tests/test-qobject-output-visitor.c
> index 1c856d9bd20a..95487b139801 100644
> --- a/tests/test-qobject-output-visitor.c
> +++ b/tests/test-qobject-output-visitor.c
> @@ -223,7 +223,8 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
> const void *unused)
> {
> const char *value_str = "list value";
> - TestStructList *p, *head = NULL;
> + TestStruct *value;
> + TestStructList *head = NULL;
> const int max_items = 10;
> bool value_bool = true;
> int value_int = 10;
> @@ -233,14 +234,12 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
>
> /* Build the list in reverse order... */
> for (i = 0; i < max_items; i++) {
> - p = g_malloc0(sizeof(*p));
> - p->value = g_malloc0(sizeof(*p->value));
> - p->value->integer = value_int + (max_items - i - 1);
> - p->value->boolean = value_bool;
> - p->value->string = g_strdup(value_str);
> + value = g_malloc0(sizeof(*value));
> + value->integer = value_int + (max_items - i - 1);
> + value->boolean = value_bool;
> + value->string = g_strdup(value_str);
>
> - p->next = head;
> - head = p;
> + QAPI_LIST_ADD(head, value);
> }
>
> visit_type_TestStructList(data->ov, NULL, &head, &error_abort);
> @@ -270,26 +269,25 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
> static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data,
> const void *unused)
> {
> - UserDefTwoList *p, *head = NULL;
> + UserDefTwo *value;
> + UserDefTwoList *head = NULL;
> const char string[] = "foo bar";
> int i, max_count = 1024;
>
> for (i = 0; i < max_count; i++) {
> - p = g_malloc0(sizeof(*p));
> - p->value = g_malloc0(sizeof(*p->value));
> + value = g_malloc0(sizeof(*value));
>
> - p->value->string0 = g_strdup(string);
> - p->value->dict1 = g_new0(UserDefTwoDict, 1);
> - p->value->dict1->string1 = g_strdup(string);
> - p->value->dict1->dict2 = g_new0(UserDefTwoDictDict, 1);
> - p->value->dict1->dict2->userdef = g_new0(UserDefOne, 1);
> - p->value->dict1->dict2->userdef->string = g_strdup(string);
> - p->value->dict1->dict2->userdef->integer = 42;
> - p->value->dict1->dict2->string = g_strdup(string);
> - p->value->dict1->has_dict3 = false;
> + value->string0 = g_strdup(string);
> + value->dict1 = g_new0(UserDefTwoDict, 1);
> + value->dict1->string1 = g_strdup(string);
> + value->dict1->dict2 = g_new0(UserDefTwoDictDict, 1);
> + value->dict1->dict2->userdef = g_new0(UserDefOne, 1);
> + value->dict1->dict2->userdef->string = g_strdup(string);
> + value->dict1->dict2->userdef->integer = 42;
> + value->dict1->dict2->string = g_strdup(string);
> + value->dict1->has_dict3 = false;
>
> - p->next = head;
> - head = p;
> + QAPI_LIST_ADD(head, value);
> }
>
> qapi_free_UserDefTwoList(head);
> diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c
> index 1c5a8b94ea87..efbf744fcf25 100644
> --- a/tests/test-visitor-serialization.c
> +++ b/tests/test-visitor-serialization.c
> @@ -704,10 +704,7 @@ static void test_nested_struct_list(gconstpointer opaque)
> int i = 0;
>
> for (i = 0; i < 8; i++) {
> - tmp = g_new0(UserDefTwoList, 1);
> - tmp->value = nested_struct_create();
> - tmp->next = listp;
> - listp = tmp;
> + QAPI_LIST_ADD(listp, nested_struct_create());
> }
>
> ops->serialize(listp, &serialize_data, visit_nested_struct_list,
> diff --git a/trace/qmp.c b/trace/qmp.c
> index 38246e1aa692..8755835edabc 100644
> --- a/trace/qmp.c
> +++ b/trace/qmp.c
> @@ -92,39 +92,37 @@ TraceEventInfoList *qmp_trace_event_get_state(const char *name,
> /* Get states (all errors checked above) */
> trace_event_iter_init(&iter, name);
> while ((ev = trace_event_iter_next(&iter)) != NULL) {
> - TraceEventInfoList *elem;
> + TraceEventInfo *value;
> bool is_vcpu = trace_event_is_vcpu(ev);
> if (has_vcpu && !is_vcpu) {
> continue;
> }
>
> - elem = g_new(TraceEventInfoList, 1);
> - elem->value = g_new(TraceEventInfo, 1);
> - elem->value->vcpu = is_vcpu;
> - elem->value->name = g_strdup(trace_event_get_name(ev));
> + value = g_new(TraceEventInfo, 1);
> + value->vcpu = is_vcpu;
> + value->name = g_strdup(trace_event_get_name(ev));
>
> if (!trace_event_get_state_static(ev)) {
> - elem->value->state = TRACE_EVENT_STATE_UNAVAILABLE;
> + value->state = TRACE_EVENT_STATE_UNAVAILABLE;
> } else {
> if (has_vcpu) {
> if (is_vcpu) {
> if (trace_event_get_vcpu_state_dynamic(cpu, ev)) {
> - elem->value->state = TRACE_EVENT_STATE_ENABLED;
> + value->state = TRACE_EVENT_STATE_ENABLED;
> } else {
> - elem->value->state = TRACE_EVENT_STATE_DISABLED;
> + value->state = TRACE_EVENT_STATE_DISABLED;
> }
> }
> /* else: already skipped above */
> } else {
> if (trace_event_get_state_dynamic(ev)) {
> - elem->value->state = TRACE_EVENT_STATE_ENABLED;
> + value->state = TRACE_EVENT_STATE_ENABLED;
> } else {
> - elem->value->state = TRACE_EVENT_STATE_DISABLED;
> + value->state = TRACE_EVENT_STATE_DISABLED;
> }
> }
> }
> - elem->next = events;
> - events = elem;
> + QAPI_LIST_ADD(events, value);
> }
>
> return events;
> diff --git a/ui/vnc.c b/ui/vnc.c
> index f006aa1afdb2..f39cfc952906 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -365,14 +365,11 @@ static VncDisplay *vnc_display_find(const char *id)
>
> static VncClientInfoList *qmp_query_client_list(VncDisplay *vd)
> {
> - VncClientInfoList *cinfo, *prev = NULL;
> + VncClientInfoList *prev = NULL;
> VncState *client;
>
> QTAILQ_FOREACH(client, &vd->clients, next) {
> - cinfo = g_new0(VncClientInfoList, 1);
> - cinfo->value = qmp_query_vnc_client(client);
> - cinfo->next = prev;
> - prev = cinfo;
> + QAPI_LIST_ADD(prev, qmp_query_vnc_client(client));
> }
> return prev;
> }
> @@ -453,7 +450,6 @@ static VncServerInfo2List *qmp_query_server_entry(QIOChannelSocket *ioc,
> int subauth,
> VncServerInfo2List *prev)
> {
> - VncServerInfo2List *list;
> VncServerInfo2 *info;
> Error *err = NULL;
> SocketAddress *addr;
> @@ -476,10 +472,8 @@ static VncServerInfo2List *qmp_query_server_entry(QIOChannelSocket *ioc,
> qmp_query_auth(auth, subauth, &info->auth,
> &info->vencrypt, &info->has_vencrypt);
>
> - list = g_new0(VncServerInfo2List, 1);
> - list->value = info;
> - list->next = prev;
> - return list;
> + QAPI_LIST_ADD(prev, info);
> + return prev;
> }
>
> static void qmp_query_auth(int auth, int subauth,
> @@ -554,7 +548,7 @@ static void qmp_query_auth(int auth, int subauth,
>
> VncInfo2List *qmp_query_vnc_servers(Error **errp)
> {
> - VncInfo2List *item, *prev = NULL;
> + VncInfo2List *prev = NULL;
> VncInfo2 *info;
> VncDisplay *vd;
> DeviceState *dev;
> @@ -583,10 +577,7 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp)
> vd->ws_subauth, info->server);
> }
>
> - item = g_new0(VncInfo2List, 1);
> - item->value = info;
> - item->next = prev;
> - prev = item;
> + QAPI_LIST_ADD(prev, info);
> }
> return prev;
> }
> diff --git a/util/qemu-config.c b/util/qemu-config.c
> index 660f47b0050f..495ada45f3df 100644
> --- a/util/qemu-config.c
> +++ b/util/qemu-config.c
> @@ -55,7 +55,7 @@ QemuOpts *qemu_find_opts_singleton(const char *group)
>
> static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
> {
> - CommandLineParameterInfoList *param_list = NULL, *entry;
> + CommandLineParameterInfoList *param_list = NULL;
> CommandLineParameterInfo *info;
> int i;
>
> @@ -87,10 +87,7 @@ static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
> info->q_default = g_strdup(desc[i].def_value_str);
> }
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = param_list;
> - param_list = entry;
> + QAPI_LIST_ADD(param_list, info);
> }
>
> return param_list;
> @@ -246,7 +243,7 @@ CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
> const char *option,
> Error **errp)
> {
> - CommandLineOptionInfoList *conf_list = NULL, *entry;
> + CommandLineOptionInfoList *conf_list = NULL;
> CommandLineOptionInfo *info;
> int i;
>
> @@ -262,10 +259,7 @@ CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
> info->parameters =
> query_option_descs(vm_config_groups[i]->desc);
> }
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = conf_list;
> - conf_list = entry;
> + QAPI_LIST_ADD(conf_list, info);
> }
> }
>
> diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc
> index bb66526280ef..5795d0e5af2c 100644
> --- a/target/ppc/translate_init.c.inc
> +++ b/target/ppc/translate_init.c.inc
> @@ -10621,7 +10621,6 @@ static void ppc_cpu_defs_entry(gpointer data, gpointer user_data)
> ObjectClass *oc = data;
> CpuDefinitionInfoList **first = user_data;
> const char *typename;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
>
> typename = object_class_get_name(oc);
> @@ -10629,10 +10628,7 @@ static void ppc_cpu_defs_entry(gpointer data, gpointer user_data)
> info->name = g_strndup(typename,
> strlen(typename) - strlen(POWERPC_CPU_TYPE_SUFFIX));
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = *first;
> - *first = entry;
> + QAPI_LIST_ADD(*first, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> @@ -10648,7 +10644,6 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) {
> PowerPCCPUAlias *alias = &ppc_cpu_aliases[i];
> ObjectClass *oc;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
>
> oc = ppc_cpu_class_by_name(alias->model);
> @@ -10660,10 +10655,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> info->name = g_strdup(alias->alias);
> info->q_typename = g_strdup(object_class_get_name(oc));
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = cpu_list;
> - cpu_list = entry;
> + QAPI_LIST_ADD(cpu_list, info);
> }
>
> return cpu_list;
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 01/11] block: Simplify QAPI_LIST_ADD
2020-10-27 5:05 ` [PATCH v6 01/11] block: Simplify QAPI_LIST_ADD Eric Blake
@ 2020-10-27 10:06 ` Vladimir Sementsov-Ogievskiy
2020-10-27 12:58 ` Markus Armbruster
1 sibling, 0 replies; 28+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-10-27 10:06 UTC (permalink / raw)
To: Eric Blake, qemu-devel
Cc: kwolf, stefanha, armbru, rjones, pkrempa, qemu-block, Max Reitz
27.10.2020 08:05, Eric Blake wrote:
> There is no need to rely on the verbosity of the gcc/clang compiler
> extension of g_new(typeof(X), 1) when we can instead use the standard
> g_malloc(sizeof(X)). In general, we like g_new over g_malloc for
> returning type X rather than void* to let the compiler catch more
> potential typing mistakes, but in this particular macro, our other use
> of typeof on the same line already ensures we are getting correct
> results.
>
> Suggested-by: Markus Armbruster<armbru@redhat.com>
> Signed-off-by: Eric Blake<eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
--
Best regards,
Vladimir
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible
2020-10-27 5:05 ` [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible Eric Blake
2020-10-27 5:53 ` Thomas Huth
2020-10-27 6:39 ` David Gibson
@ 2020-10-27 10:09 ` Markus Armbruster
2020-10-27 12:28 ` Eric Blake
2020-10-27 11:26 ` Dr. David Alan Gilbert
2020-10-27 13:42 ` Vladimir Sementsov-Ogievskiy
4 siblings, 1 reply; 28+ messages in thread
From: Markus Armbruster @ 2020-10-27 10:09 UTC (permalink / raw)
To: Eric Blake
Cc: Peter Maydell, pkrempa, Michael S. Tsirkin, Jason Wang,
qemu-devel, Jiaxun Yang, armbru, Gerd Hoffmann, qemu-block,
Juan Quintela, David Hildenbrand, Michael Roth, Halil Pasic,
Christian Borntraeger, Marc-André Lureau, Richard Henderson,
Thomas Huth, Jiri Pirko, Eduardo Habkost, Dr. David Alan Gilbert,
open list:S390 KVM CPUs, vsementsov, stefanha, David Gibson,
kwolf, open list:GLUSTER, Daniel P. Berrangé, Cornelia Huck,
rjones, Max Reitz, open list:ARM TCG CPUs,
open list:PowerPC TCG CPUs, Paolo Bonzini, Aleksandar Rikalo,
Aurelien Jarno, Philippe Mathieu-Daudé
Eric Blake <eblake@redhat.com> writes:
> Anywhere we create a list of just one item or by prepending items
> (typically because order doesn't matter), we can use the now-public
> macro. But places where we must keep the list in order by appending
> remain open-coded.
Should we rename the macro to QAPI_LIST_PREPEND()?
How many places append? If it's more than just a few, an attempt to
factor out the common code is in order. Not in this patch, of course.
Not even in this series.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
> ---
> docs/devel/writing-qmp-commands.txt | 13 +++------
> hw/net/rocker/rocker_fp.h | 2 +-
> block/gluster.c | 19 +++++--------
> chardev/char.c | 21 +++++++--------
> hw/core/machine.c | 6 +----
> hw/net/rocker/rocker.c | 8 +++---
> hw/net/rocker/rocker_fp.c | 14 +++++-----
> hw/net/virtio-net.c | 21 +++++----------
> migration/migration.c | 7 ++---
> migration/postcopy-ram.c | 7 ++---
> monitor/hmp-cmds.c | 11 ++++----
> qemu-img.c | 5 ++--
> qga/commands-posix.c | 13 +++------
> qga/commands-win32.c | 17 +++---------
> qga/commands.c | 6 +----
> qom/qom-qmp-cmds.c | 29 ++++++--------------
> target/arm/helper.c | 6 +----
> target/arm/monitor.c | 13 ++-------
> target/i386/cpu.c | 6 +----
> target/mips/helper.c | 6 +----
> target/s390x/cpu_models.c | 12 ++-------
> tests/test-clone-visitor.c | 7 ++---
> tests/test-qobject-output-visitor.c | 42 ++++++++++++++---------------
> tests/test-visitor-serialization.c | 5 +---
> trace/qmp.c | 22 +++++++--------
> ui/vnc.c | 21 +++++----------
> util/qemu-config.c | 14 +++-------
> target/ppc/translate_init.c.inc | 12 ++-------
> 28 files changed, 119 insertions(+), 246 deletions(-)
Nice diffstat.
>
> diff --git a/docs/devel/writing-qmp-commands.txt b/docs/devel/writing-qmp-commands.txt
> index 46a6c48683f5..3e11eeaa1893 100644
> --- a/docs/devel/writing-qmp-commands.txt
> +++ b/docs/devel/writing-qmp-commands.txt
> @@ -531,15 +531,10 @@ TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
> bool current = true;
>
> for (p = alarm_timers; p->name; p++) {
> - TimerAlarmMethodList *info = g_malloc0(sizeof(*info));
> - info->value = g_malloc0(sizeof(*info->value));
> - info->value->method_name = g_strdup(p->name);
> - info->value->current = current;
> -
> - current = false;
> -
> - info->next = method_list;
> - method_list = info;
> + TimerAlarmMethod *value = g_new0(TimerAlarmMethod, 1);
Can just as well use g_new(), as QAPI_LIST_ADD() will set both members
of @value. Same elsewhere.
> + value->method_name = g_strdup(p->name);
> + value->current = current;
> + QAPI_LIST_ADD(method_list, value);
> }
>
> return method_list;
> diff --git a/hw/net/rocker/rocker_fp.h b/hw/net/rocker/rocker_fp.h
> index dbe1dd329a4b..4cb0bb9ccf81 100644
> --- a/hw/net/rocker/rocker_fp.h
> +++ b/hw/net/rocker/rocker_fp.h
> @@ -28,7 +28,7 @@ int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt);
>
> char *fp_port_get_name(FpPort *port);
> bool fp_port_get_link_up(FpPort *port);
> -void fp_port_get_info(FpPort *port, RockerPortList *info);
> +void fp_port_get_info(FpPort *port, RockerPort *info);
> void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr);
> void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr);
> uint8_t fp_port_get_learning(FpPort *port);
> diff --git a/block/gluster.c b/block/gluster.c
> index 4f1448e2bc88..cf446c23f85d 100644
> --- a/block/gluster.c
> +++ b/block/gluster.c
> @@ -359,8 +359,8 @@ static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
> return -EINVAL;
> }
>
> - gconf->server = g_new0(SocketAddressList, 1);
> - gconf->server->value = gsconf = g_new0(SocketAddress, 1);
> + gsconf = g_new0(SocketAddress, 1);
> + QAPI_LIST_ADD(gconf->server, gsconf);
>
> /* transport */
> if (!uri->scheme || !strcmp(uri->scheme, "gluster")) {
> @@ -514,7 +514,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
> {
> QemuOpts *opts;
> SocketAddress *gsconf = NULL;
> - SocketAddressList *curr = NULL;
> + SocketAddressList **curr;
> QDict *backing_options = NULL;
> Error *local_err = NULL;
> char *str = NULL;
> @@ -547,6 +547,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
> }
> gconf->path = g_strdup(ptr);
> qemu_opts_del(opts);
> + curr = &gconf->server;
>
> for (i = 0; i < num_servers; i++) {
> str = g_strdup_printf(GLUSTER_OPT_SERVER_PATTERN"%d.", i);
> @@ -655,15 +656,9 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
> qemu_opts_del(opts);
> }
>
> - if (gconf->server == NULL) {
> - gconf->server = g_new0(SocketAddressList, 1);
> - gconf->server->value = gsconf;
> - curr = gconf->server;
> - } else {
> - curr->next = g_new0(SocketAddressList, 1);
> - curr->next->value = gsconf;
> - curr = curr->next;
> - }
> + *curr = g_new0(SocketAddressList, 1);
> + (*curr)->value = gsconf;
> + curr = &(*curr)->next;
> gsconf = NULL;
>
> qobject_unref(backing_options);
The change to qemu_gluster_parse_json() looks unrelated.
> diff --git a/chardev/char.c b/chardev/char.c
> index 78553125d311..8dd7ef4c5935 100644
> --- a/chardev/char.c
> +++ b/chardev/char.c
> @@ -776,15 +776,14 @@ static int qmp_query_chardev_foreach(Object *obj, void *data)
> {
> Chardev *chr = CHARDEV(obj);
> ChardevInfoList **list = data;
> - ChardevInfoList *info = g_malloc0(sizeof(*info));
> + ChardevInfo *value;
>
> - info->value = g_malloc0(sizeof(*info->value));
> - info->value->label = g_strdup(chr->label);
> - info->value->filename = g_strdup(chr->filename);
> - info->value->frontend_open = chr->be && chr->be->fe_open;
> + value = g_malloc0(sizeof(*value));
You could use an initializer instead, like you do in the next hunk. Up
to you.
> + value->label = g_strdup(chr->label);
> + value->filename = g_strdup(chr->filename);
> + value->frontend_open = chr->be && chr->be->fe_open;
>
> - info->next = *list;
> - *list = info;
> + QAPI_LIST_ADD(*list, value);
>
> return 0;
> }
> @@ -803,12 +802,10 @@ static void
> qmp_prepend_backend(const char *name, void *opaque)
> {
> ChardevBackendInfoList **list = opaque;
> - ChardevBackendInfoList *info = g_malloc0(sizeof(*info));
> + ChardevBackendInfo *value = g_new0(ChardevBackendInfo, 1);
>
> - info->value = g_malloc0(sizeof(*info->value));
> - info->value->name = g_strdup(name);
> - info->next = *list;
> - *list = info;
> + value->name = g_strdup(name);
> + QAPI_LIST_ADD(*list, value);
> }
>
> ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
> diff --git a/hw/core/machine.c b/hw/core/machine.c
> index c5e0e79e6dbc..a05c4739ca7a 100644
> --- a/hw/core/machine.c
> +++ b/hw/core/machine.c
> @@ -492,11 +492,7 @@ static void machine_set_nvdimm_persistence(Object *obj, const char *value,
>
> void machine_class_allow_dynamic_sysbus_dev(MachineClass *mc, const char *type)
> {
> - strList *item = g_new0(strList, 1);
> -
> - item->value = g_strdup(type);
> - item->next = mc->allowed_dynamic_sysbus_devices;
> - mc->allowed_dynamic_sysbus_devices = item;
> + QAPI_LIST_ADD(mc->allowed_dynamic_sysbus_devices, g_strdup(type));
Side effect in a macro argument. Works, because QAPI_LIST_ADD() expands
@element exactly once. Sure we want to rely on it?
If yes, please add a contract to QAPI_LIST_ADD() that documents it.
More instances below.
> }
>
> static void validate_sysbus_device(SysBusDevice *sbdev, void *opaque)
> diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c
> index 1af1e6fa2f9b..a1137e11ff48 100644
> --- a/hw/net/rocker/rocker.c
> +++ b/hw/net/rocker/rocker.c
> @@ -127,13 +127,11 @@ RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
> }
>
> for (i = r->fp_ports - 1; i >= 0; i--) {
> - RockerPortList *info = g_malloc0(sizeof(*info));
> - info->value = g_malloc0(sizeof(*info->value));
> + RockerPort *value = g_malloc0(sizeof(*value));
> struct fp_port *port = r->fp_port[i];
>
> - fp_port_get_info(port, info);
> - info->next = list;
> - list = info;
> + fp_port_get_info(port, value);
> + QAPI_LIST_ADD(list, value);
> }
>
> return list;
> diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c
> index 4aa7da79b81d..a616e709292e 100644
> --- a/hw/net/rocker/rocker_fp.c
> +++ b/hw/net/rocker/rocker_fp.c
> @@ -51,14 +51,14 @@ bool fp_port_get_link_up(FpPort *port)
> return !qemu_get_queue(port->nic)->link_down;
> }
>
> -void fp_port_get_info(FpPort *port, RockerPortList *info)
> +void fp_port_get_info(FpPort *port, RockerPort *value)
> {
> - info->value->name = g_strdup(port->name);
> - info->value->enabled = port->enabled;
> - info->value->link_up = fp_port_get_link_up(port);
> - info->value->speed = port->speed;
> - info->value->duplex = port->duplex;
> - info->value->autoneg = port->autoneg;
> + value->name = g_strdup(port->name);
> + value->enabled = port->enabled;
> + value->link_up = fp_port_get_link_up(port);
> + value->speed = port->speed;
> + value->duplex = port->duplex;
> + value->autoneg = port->autoneg;
> }
This cleanup of fp_port_get_info() could be a separate patch. Up to
you.
You could move the allocation into fp_port_get_info(), like this:
RockerPort *fp_port_get_info(FpPort *port)
{
RockerPort *value = g_malloc0(sizeof(*value));
value->name = g_strdup(port->name);
value->enabled = port->enabled;
value->link_up = fp_port_get_link_up(port);
value->speed = port->speed;
value->duplex = port->duplex;
value->autoneg = port->autoneg;
return value;
}
Also up to you.
>
> void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr)
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index 277289d56e76..6b13d3ca3c8f 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -437,17 +437,14 @@ static void rxfilter_notify(NetClientState *nc)
>
> static intList *get_vlan_table(VirtIONet *n)
> {
> - intList *list, *entry;
> + intList *list;
> int i, j;
>
> list = NULL;
> for (i = 0; i < MAX_VLAN >> 5; i++) {
> for (j = 0; n->vlans[i] && j <= 0x1f; j++) {
> if (n->vlans[i] & (1U << j)) {
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = (i << 5) + j;
> - entry->next = list;
> - list = entry;
> + QAPI_LIST_ADD(list, (i << 5) + j);
> }
> }
> }
> @@ -460,7 +457,7 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
> VirtIONet *n = qemu_get_nic_opaque(nc);
> VirtIODevice *vdev = VIRTIO_DEVICE(n);
> RxFilterInfo *info;
> - strList *str_list, *entry;
> + strList *str_list;
> int i;
>
> info = g_malloc0(sizeof(*info));
> @@ -491,19 +488,15 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
>
> str_list = NULL;
> for (i = 0; i < n->mac_table.first_multi; i++) {
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN);
> - entry->next = str_list;
> - str_list = entry;
> + QAPI_LIST_ADD(str_list,
> + qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN));
Side effect in a macro argument.
> }
> info->unicast_table = str_list;
>
> str_list = NULL;
> for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN);
> - entry->next = str_list;
> - str_list = entry;
> + QAPI_LIST_ADD(str_list,
> + qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN));
Side effect in a macro argument.
> }
> info->multicast_table = str_list;
> info->vlan_table = get_vlan_table(n);
> diff --git a/migration/migration.c b/migration/migration.c
> index deb6005b8d37..239a7e430214 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -368,12 +368,9 @@ int migration_incoming_enable_colo(void)
> void migrate_add_address(SocketAddress *address)
> {
> MigrationIncomingState *mis = migration_incoming_get_current();
> - SocketAddressList *addrs;
>
> - addrs = g_new0(SocketAddressList, 1);
> - addrs->next = mis->socket_address_list;
> - mis->socket_address_list = addrs;
> - addrs->value = QAPI_CLONE(SocketAddress, address);
> + QAPI_LIST_ADD(mis->socket_address_list,
> + QAPI_CLONE(SocketAddress, address));
Side effect in a macro argument.
> }
>
> void qemu_start_incoming_migration(const char *uri, Error **errp)
> diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
> index 0a2f88a87d06..18ac7e06c581 100644
> --- a/migration/postcopy-ram.c
> +++ b/migration/postcopy-ram.c
> @@ -145,14 +145,11 @@ static struct PostcopyBlocktimeContext *blocktime_context_new(void)
> static uint32List *get_vcpu_blocktime_list(PostcopyBlocktimeContext *ctx)
> {
> MachineState *ms = MACHINE(qdev_get_machine());
> - uint32List *list = NULL, *entry = NULL;
> + uint32List *list = NULL;
> int i;
>
> for (i = ms->smp.cpus - 1; i >= 0; i--) {
> - entry = g_new0(uint32List, 1);
> - entry->value = ctx->vcpu_blocktime[i];
> - entry->next = list;
> - list = entry;
> + QAPI_LIST_ADD(list, ctx->vcpu_blocktime[i]);
> }
>
> return list;
> diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
> index 9789f4277f50..629c3d1bf741 100644
> --- a/monitor/hmp-cmds.c
> +++ b/monitor/hmp-cmds.c
> @@ -1248,7 +1248,8 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
> const char *cap = qdict_get_str(qdict, "capability");
> bool state = qdict_get_bool(qdict, "state");
> Error *err = NULL;
> - MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
> + MigrationCapabilityStatusList *caps = NULL;
> + MigrationCapabilityStatus *value = NULL;
No need to initialize @value.
> int val;
>
> val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err);
> @@ -1256,10 +1257,10 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
> goto end;
> }
>
> - caps->value = g_malloc0(sizeof(*caps->value));
> - caps->value->capability = val;
> - caps->value->state = state;
> - caps->next = NULL;
> + value = g_malloc0(sizeof(*value));
> + value->capability = val;
> + value->state = state;
> + QAPI_LIST_ADD(caps, value);
> qmp_migrate_set_capabilities(caps, &err);
>
> end:
qapi_free_MigrationCapabilityStatusList(caps);
This could be moved before the label now. No need to initialize @caps
to null then. Up to you.
hmp_handle_error(mon, err);
}
> diff --git a/qemu-img.c b/qemu-img.c
> index 2103507936ea..4cfa8bccc5e7 100644
> --- a/qemu-img.c
> +++ b/qemu-img.c
> @@ -1643,14 +1643,13 @@ static void do_dirty_bitmap_merge(const char *dst_node, const char *dst_name,
> Error **errp)
> {
> BlockDirtyBitmapMergeSource *merge_src;
> - BlockDirtyBitmapMergeSourceList *list;
> + BlockDirtyBitmapMergeSourceList *list = NULL;
>
> merge_src = g_new0(BlockDirtyBitmapMergeSource, 1);
> merge_src->type = QTYPE_QDICT;
> merge_src->u.external.node = g_strdup(src_node);
> merge_src->u.external.name = g_strdup(src_name);
> - list = g_new0(BlockDirtyBitmapMergeSourceList, 1);
> - list->value = merge_src;
> + QAPI_LIST_ADD(list, merge_src);
> qmp_block_dirty_bitmap_merge(dst_node, dst_name, list, errp);
> qapi_free_BlockDirtyBitmapMergeSourceList(list);
> }
> diff --git a/qga/commands-posix.c b/qga/commands-posix.c
> index 3bffee99d4c9..06540425ded2 100644
> --- a/qga/commands-posix.c
> +++ b/qga/commands-posix.c
> @@ -1211,7 +1211,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
> {
> FsMountList mounts;
> struct FsMount *mount;
> - GuestFilesystemInfoList *new, *ret = NULL;
> + GuestFilesystemInfoList *ret = NULL;
> Error *local_err = NULL;
>
> QTAILQ_INIT(&mounts);
> @@ -1224,10 +1224,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
> QTAILQ_FOREACH(mount, &mounts, next) {
> g_debug("Building guest fsinfo for '%s'", mount->dirname);
>
> - new = g_malloc0(sizeof(*ret));
Ugh! Glad you get rid of this.
> - new->value = build_guest_fsinfo(mount, &local_err);
> - new->next = ret;
> - ret = new;
> + QAPI_LIST_ADD(ret, build_guest_fsinfo(mount, &local_err));
Side effect in a macro argument.
> if (local_err) {
> error_propagate(errp, local_err);
> qapi_free_GuestFilesystemInfoList(ret);
> @@ -1493,7 +1490,6 @@ GuestFilesystemTrimResponse *
> qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
> {
> GuestFilesystemTrimResponse *response;
> - GuestFilesystemTrimResultList *list;
> GuestFilesystemTrimResult *result;
> int ret = 0;
> FsMountList mounts;
> @@ -1517,10 +1513,7 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
> result = g_malloc0(sizeof(*result));
> result->path = g_strdup(mount->dirname);
>
> - list = g_malloc0(sizeof(*list));
> - list->value = result;
> - list->next = response->paths;
> - response->paths = list;
> + QAPI_LIST_ADD(response->paths, result);
>
> fd = qemu_open_old(mount->dirname, O_RDONLY);
> if (fd == -1) {
> diff --git a/qga/commands-win32.c b/qga/commands-win32.c
> index 0c3c05484f5f..cc5736c3bba8 100644
> --- a/qga/commands-win32.c
> +++ b/qga/commands-win32.c
> @@ -926,10 +926,8 @@ static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
> error_free(local_err);
> goto out;
> }
> - list = g_malloc0(sizeof(*list));
> - list->value = disk;
> + QAPI_LIST_ADD(list, disk);
> disk = NULL;
> - list->next = NULL;
> goto out;
Both old and new code tacitly rely on @list being empty. Okay.
> } else {
> error_setg_win32(errp, GetLastError(),
Did you miss the spot where we add to this list?
/* Go through each extent */
for (i = 0; i < extents->NumberOfDiskExtents; i++) {
disk = g_malloc0(sizeof(GuestDiskAddress));
/* Disk numbers directly correspond to numbers used in UNCs
*
* See documentation for DISK_EXTENT:
* https://docs.microsoft.com/en-us/windows/desktop/api/winioctl/ns-winioctl-_disk_extent
*
* See also Naming Files, Paths and Namespaces:
* https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#win32-device-namespaces
*/
disk->has_dev = true;
disk->dev = g_strdup_printf("\\\\.\\PhysicalDrive%lu",
extents->Extents[i].DiskNumber);
get_single_disk_info(extents->Extents[i].DiskNumber, disk, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto out;
}
cur_item = g_malloc0(sizeof(*list));
cur_item->value = disk;
disk = NULL;
cur_item->next = list;
---> list = cur_item;
}
> @@ -1064,7 +1062,7 @@ free:
> GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
> {
> HANDLE vol_h;
> - GuestFilesystemInfoList *new, *ret = NULL;
> + GuestFilesystemInfoList *ret = NULL;
> char guid[256];
>
> vol_h = FindFirstVolume(guid, sizeof(guid));
> @@ -1082,10 +1080,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
> error_free(local_err);
> continue;
> }
> - new = g_malloc(sizeof(*ret));
> - new->value = info;
> - new->next = ret;
> - ret = new;
> + QAPI_LIST_ADD(ret, info);
> } while (FindNextVolume(vol_h, guid, sizeof(guid)));
>
> if (GetLastError() != ERROR_NO_MORE_FILES) {
> @@ -1268,11 +1263,7 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
>
> res->path = path;
>
> - list = g_new0(GuestFilesystemTrimResultList, 1);
> - list->value = res;
> - list->next = resp->paths;
> -
> - resp->paths = list;
> + QAPI_LIST_ADD(resp->paths, res);
>
> memset(argv, 0, sizeof(argv));
> argv[0] = (gchar *)"defrag.exe";
> diff --git a/qga/commands.c b/qga/commands.c
> index 3dcd5fbe5c4d..27118df6caea 100644
> --- a/qga/commands.c
> +++ b/qga/commands.c
> @@ -66,17 +66,13 @@ static void qmp_command_info(const QmpCommand *cmd, void *opaque)
> {
> GuestAgentInfo *info = opaque;
> GuestAgentCommandInfo *cmd_info;
> - GuestAgentCommandInfoList *cmd_info_list;
>
> cmd_info = g_new0(GuestAgentCommandInfo, 1);
> cmd_info->name = g_strdup(qmp_command_name(cmd));
> cmd_info->enabled = qmp_command_is_enabled(cmd);
> cmd_info->success_response = qmp_has_success_response(cmd);
>
> - cmd_info_list = g_new0(GuestAgentCommandInfoList, 1);
> - cmd_info_list->value = cmd_info;
> - cmd_info_list->next = info->supported_commands;
> - info->supported_commands = cmd_info_list;
> + QAPI_LIST_ADD(info->supported_commands, cmd_info);
> }
>
> struct GuestAgentInfo *qmp_guest_info(Error **errp)
> diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
> index 310ab2d0481d..5ac9272ffeea 100644
> --- a/qom/qom-qmp-cmds.c
> +++ b/qom/qom-qmp-cmds.c
> @@ -46,14 +46,12 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
>
> object_property_iter_init(&iter, obj);
> while ((prop = object_property_iter_next(&iter))) {
> - ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
> + ObjectPropertyInfo *value = g_malloc0(sizeof(ObjectPropertyInfo));
>
> - entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
> - entry->next = props;
> - props = entry;
> + QAPI_LIST_ADD(props, value);
>
> - entry->value->name = g_strdup(prop->name);
> - entry->value->type = g_strdup(prop->type);
> + value->name = g_strdup(prop->name);
> + value->type = g_strdup(prop->type);
This is the minimally invasive patch. Best to stick to minimal in a big
series like this one, to ease review as much as possible.
If that wasn't an issue, I'd suggest finishing the list element before
inserting it into the list:
ObjectPropertyInfo *value = g_malloc0(sizeof(ObjectPropertyInfo));
value->name = g_strdup(prop->name);
value->type = g_strdup(prop->type);
QAPI_LIST_ADD(props, value);
There might be more instances.
> }
>
> return props;
> @@ -90,7 +88,7 @@ QObject *qmp_qom_get(const char *path, const char *property, Error **errp)
>
> static void qom_list_types_tramp(ObjectClass *klass, void *data)
> {
> - ObjectTypeInfoList *e, **pret = data;
> + ObjectTypeInfoList **pret = data;
> ObjectTypeInfo *info;
> ObjectClass *parent = object_class_get_parent(klass);
>
> @@ -102,10 +100,7 @@ static void qom_list_types_tramp(ObjectClass *klass, void *data)
> info->parent = g_strdup(object_class_get_name(parent));
> }
>
> - e = g_malloc0(sizeof(*e));
> - e->value = info;
> - e->next = *pret;
> - *pret = e;
> + QAPI_LIST_ADD(*pret, info);
> }
>
> ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
> @@ -155,7 +150,6 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
> object_property_iter_init(&iter, obj);
> while ((prop = object_property_iter_next(&iter))) {
> ObjectPropertyInfo *info;
> - ObjectPropertyInfoList *entry;
>
> /* Skip Object and DeviceState properties */
> if (strcmp(prop->name, "type") == 0 ||
> @@ -181,10 +175,7 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
> info->default_value = qobject_ref(prop->defval);
> info->has_default_value = !!info->default_value;
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = prop_list;
> - prop_list = entry;
> + QAPI_LIST_ADD(prop_list, info);
> }
>
> object_unref(obj);
> @@ -222,7 +213,6 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
> }
> while ((prop = object_property_iter_next(&iter))) {
> ObjectPropertyInfo *info;
> - ObjectPropertyInfoList *entry;
>
> info = g_malloc0(sizeof(*info));
> info->name = g_strdup(prop->name);
> @@ -230,10 +220,7 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
> info->has_description = !!prop->description;
> info->description = g_strdup(prop->description);
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = prop_list;
> - prop_list = entry;
> + QAPI_LIST_ADD(prop_list, info);
> }
>
> object_unref(obj);
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 97bb6b8c01b4..df150f3c3eeb 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -8293,7 +8293,6 @@ static void arm_cpu_add_definition(gpointer data, gpointer user_data)
> {
> ObjectClass *oc = data;
> CpuDefinitionInfoList **cpu_list = user_data;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
> const char *typename;
>
> @@ -8303,10 +8302,7 @@ static void arm_cpu_add_definition(gpointer data, gpointer user_data)
> strlen(typename) - strlen("-" TYPE_ARM_CPU));
> info->q_typename = g_strdup(typename);
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = *cpu_list;
> - *cpu_list = entry;
> + QAPI_LIST_ADD(*cpu_list, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> diff --git a/target/arm/monitor.c b/target/arm/monitor.c
> index 169d8a64b651..771101656535 100644
> --- a/target/arm/monitor.c
> +++ b/target/arm/monitor.c
> @@ -42,15 +42,6 @@ static GICCapability *gic_cap_new(int version)
> return cap;
> }
>
> -static GICCapabilityList *gic_cap_list_add(GICCapabilityList *head,
> - GICCapability *cap)
> -{
> - GICCapabilityList *item = g_new0(GICCapabilityList, 1);
> - item->value = cap;
> - item->next = head;
> - return item;
> -}
> -
> static inline void gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3)
> {
> #ifdef CONFIG_KVM
> @@ -84,8 +75,8 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
>
> gic_cap_kvm_probe(v2, v3);
>
> - head = gic_cap_list_add(head, v2);
> - head = gic_cap_list_add(head, v3);
> + QAPI_LIST_ADD(head, v2);
> + QAPI_LIST_ADD(head, v3);
>
> return head;
> }
> diff --git a/target/i386/cpu.c b/target/i386/cpu.c
> index 0d8606958e9e..9ae6661f97e3 100644
> --- a/target/i386/cpu.c
> +++ b/target/i386/cpu.c
> @@ -4984,7 +4984,6 @@ static void x86_cpu_definition_entry(gpointer data, gpointer user_data)
> ObjectClass *oc = data;
> X86CPUClass *cc = X86_CPU_CLASS(oc);
> CpuDefinitionInfoList **cpu_list = user_data;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
>
> info = g_malloc0(sizeof(*info));
> @@ -5009,10 +5008,7 @@ static void x86_cpu_definition_entry(gpointer data, gpointer user_data)
> info->has_alias_of = !!info->alias_of;
> }
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = *cpu_list;
> - *cpu_list = entry;
> + QAPI_LIST_ADD(*cpu_list, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> diff --git a/target/mips/helper.c b/target/mips/helper.c
> index afd78b1990be..036bacc24b22 100644
> --- a/target/mips/helper.c
> +++ b/target/mips/helper.c
> @@ -1502,7 +1502,6 @@ static void mips_cpu_add_definition(gpointer data, gpointer user_data)
> {
> ObjectClass *oc = data;
> CpuDefinitionInfoList **cpu_list = user_data;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
> const char *typename;
>
> @@ -1512,10 +1511,7 @@ static void mips_cpu_add_definition(gpointer data, gpointer user_data)
> strlen(typename) - strlen("-" TYPE_MIPS_CPU));
> info->q_typename = g_strdup(typename);
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = *cpu_list;
> - *cpu_list = entry;
> + QAPI_LIST_ADD(*cpu_list, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
> index 461e0b8f4a8d..a837ac66c9c8 100644
> --- a/target/s390x/cpu_models.c
> +++ b/target/s390x/cpu_models.c
> @@ -427,7 +427,6 @@ static void create_cpu_model_list(ObjectClass *klass, void *opaque)
> {
> struct CpuDefinitionInfoListData *cpu_list_data = opaque;
> CpuDefinitionInfoList **cpu_list = &cpu_list_data->list;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
> char *name = g_strdup(object_class_get_name(klass));
> S390CPUClass *scc = S390_CPU_CLASS(klass);
> @@ -454,10 +453,7 @@ static void create_cpu_model_list(ObjectClass *klass, void *opaque)
> object_unref(obj);
> }
>
> - entry = g_new0(CpuDefinitionInfoList, 1);
> - entry->value = info;
> - entry->next = *cpu_list;
> - *cpu_list = entry;
> + QAPI_LIST_ADD(*cpu_list, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> @@ -624,12 +620,8 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
> static void list_add_feat(const char *name, void *opaque)
> {
> strList **last = (strList **) opaque;
> - strList *entry;
>
> - entry = g_new0(strList, 1);
> - entry->value = g_strdup(name);
> - entry->next = *last;
> - *last = entry;
> + QAPI_LIST_ADD(*last, g_strdup(name));
Side effect in a macro argument.
> }
>
> CpuModelCompareInfo *qmp_query_cpu_model_comparison(CpuModelInfo *infoa,
> diff --git a/tests/test-clone-visitor.c b/tests/test-clone-visitor.c
> index 5e1e8b2f5e8a..03788d355130 100644
> --- a/tests/test-clone-visitor.c
> +++ b/tests/test-clone-visitor.c
> @@ -65,16 +65,13 @@ static void test_clone_alternate(void)
>
> static void test_clone_list_union(void)
> {
> - uint8List *src, *dst;
> + uint8List *src = NULL, *dst;
> uint8List *tmp = NULL;
> int i;
>
> /* Build list in reverse */
> for (i = 10; i; i--) {
> - src = g_new0(uint8List, 1);
> - src->next = tmp;
> - src->value = i;
> - tmp = src;
> + QAPI_LIST_ADD(src, i);
> }
>
> dst = QAPI_CLONE(uint8List, src);
> diff --git a/tests/test-qobject-output-visitor.c b/tests/test-qobject-output-visitor.c
> index 1c856d9bd20a..95487b139801 100644
> --- a/tests/test-qobject-output-visitor.c
> +++ b/tests/test-qobject-output-visitor.c
> @@ -223,7 +223,8 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
> const void *unused)
> {
> const char *value_str = "list value";
> - TestStructList *p, *head = NULL;
> + TestStruct *value;
> + TestStructList *head = NULL;
> const int max_items = 10;
> bool value_bool = true;
> int value_int = 10;
> @@ -233,14 +234,12 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
>
> /* Build the list in reverse order... */
> for (i = 0; i < max_items; i++) {
> - p = g_malloc0(sizeof(*p));
> - p->value = g_malloc0(sizeof(*p->value));
> - p->value->integer = value_int + (max_items - i - 1);
> - p->value->boolean = value_bool;
> - p->value->string = g_strdup(value_str);
> + value = g_malloc0(sizeof(*value));
> + value->integer = value_int + (max_items - i - 1);
> + value->boolean = value_bool;
> + value->string = g_strdup(value_str);
>
> - p->next = head;
> - head = p;
> + QAPI_LIST_ADD(head, value);
> }
>
> visit_type_TestStructList(data->ov, NULL, &head, &error_abort);
> @@ -270,26 +269,25 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
> static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data,
> const void *unused)
> {
> - UserDefTwoList *p, *head = NULL;
> + UserDefTwo *value;
> + UserDefTwoList *head = NULL;
> const char string[] = "foo bar";
> int i, max_count = 1024;
>
> for (i = 0; i < max_count; i++) {
> - p = g_malloc0(sizeof(*p));
> - p->value = g_malloc0(sizeof(*p->value));
> + value = g_malloc0(sizeof(*value));
>
> - p->value->string0 = g_strdup(string);
> - p->value->dict1 = g_new0(UserDefTwoDict, 1);
> - p->value->dict1->string1 = g_strdup(string);
> - p->value->dict1->dict2 = g_new0(UserDefTwoDictDict, 1);
> - p->value->dict1->dict2->userdef = g_new0(UserDefOne, 1);
> - p->value->dict1->dict2->userdef->string = g_strdup(string);
> - p->value->dict1->dict2->userdef->integer = 42;
> - p->value->dict1->dict2->string = g_strdup(string);
> - p->value->dict1->has_dict3 = false;
> + value->string0 = g_strdup(string);
> + value->dict1 = g_new0(UserDefTwoDict, 1);
> + value->dict1->string1 = g_strdup(string);
> + value->dict1->dict2 = g_new0(UserDefTwoDictDict, 1);
> + value->dict1->dict2->userdef = g_new0(UserDefOne, 1);
> + value->dict1->dict2->userdef->string = g_strdup(string);
> + value->dict1->dict2->userdef->integer = 42;
> + value->dict1->dict2->string = g_strdup(string);
> + value->dict1->has_dict3 = false;
>
> - p->next = head;
> - head = p;
> + QAPI_LIST_ADD(head, value);
> }
>
> qapi_free_UserDefTwoList(head);
> diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c
> index 1c5a8b94ea87..efbf744fcf25 100644
> --- a/tests/test-visitor-serialization.c
> +++ b/tests/test-visitor-serialization.c
> @@ -704,10 +704,7 @@ static void test_nested_struct_list(gconstpointer opaque)
> int i = 0;
>
> for (i = 0; i < 8; i++) {
> - tmp = g_new0(UserDefTwoList, 1);
> - tmp->value = nested_struct_create();
> - tmp->next = listp;
> - listp = tmp;
> + QAPI_LIST_ADD(listp, nested_struct_create());
Side effect in a macro argument.
> }
>
> ops->serialize(listp, &serialize_data, visit_nested_struct_list,
> diff --git a/trace/qmp.c b/trace/qmp.c
> index 38246e1aa692..8755835edabc 100644
> --- a/trace/qmp.c
> +++ b/trace/qmp.c
> @@ -92,39 +92,37 @@ TraceEventInfoList *qmp_trace_event_get_state(const char *name,
> /* Get states (all errors checked above) */
> trace_event_iter_init(&iter, name);
> while ((ev = trace_event_iter_next(&iter)) != NULL) {
> - TraceEventInfoList *elem;
> + TraceEventInfo *value;
> bool is_vcpu = trace_event_is_vcpu(ev);
> if (has_vcpu && !is_vcpu) {
> continue;
> }
>
> - elem = g_new(TraceEventInfoList, 1);
> - elem->value = g_new(TraceEventInfo, 1);
> - elem->value->vcpu = is_vcpu;
> - elem->value->name = g_strdup(trace_event_get_name(ev));
> + value = g_new(TraceEventInfo, 1);
> + value->vcpu = is_vcpu;
> + value->name = g_strdup(trace_event_get_name(ev));
>
> if (!trace_event_get_state_static(ev)) {
> - elem->value->state = TRACE_EVENT_STATE_UNAVAILABLE;
> + value->state = TRACE_EVENT_STATE_UNAVAILABLE;
> } else {
> if (has_vcpu) {
> if (is_vcpu) {
> if (trace_event_get_vcpu_state_dynamic(cpu, ev)) {
> - elem->value->state = TRACE_EVENT_STATE_ENABLED;
> + value->state = TRACE_EVENT_STATE_ENABLED;
> } else {
> - elem->value->state = TRACE_EVENT_STATE_DISABLED;
> + value->state = TRACE_EVENT_STATE_DISABLED;
> }
> }
> /* else: already skipped above */
> } else {
> if (trace_event_get_state_dynamic(ev)) {
> - elem->value->state = TRACE_EVENT_STATE_ENABLED;
> + value->state = TRACE_EVENT_STATE_ENABLED;
> } else {
> - elem->value->state = TRACE_EVENT_STATE_DISABLED;
> + value->state = TRACE_EVENT_STATE_DISABLED;
> }
> }
> }
> - elem->next = events;
> - events = elem;
> + QAPI_LIST_ADD(events, value);
> }
>
> return events;
> diff --git a/ui/vnc.c b/ui/vnc.c
> index f006aa1afdb2..f39cfc952906 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -365,14 +365,11 @@ static VncDisplay *vnc_display_find(const char *id)
>
> static VncClientInfoList *qmp_query_client_list(VncDisplay *vd)
> {
> - VncClientInfoList *cinfo, *prev = NULL;
> + VncClientInfoList *prev = NULL;
> VncState *client;
>
> QTAILQ_FOREACH(client, &vd->clients, next) {
> - cinfo = g_new0(VncClientInfoList, 1);
> - cinfo->value = qmp_query_vnc_client(client);
> - cinfo->next = prev;
> - prev = cinfo;
> + QAPI_LIST_ADD(prev, qmp_query_vnc_client(client));
Side effect in a macro argument.
> }
> return prev;
> }
> @@ -453,7 +450,6 @@ static VncServerInfo2List *qmp_query_server_entry(QIOChannelSocket *ioc,
> int subauth,
> VncServerInfo2List *prev)
> {
> - VncServerInfo2List *list;
> VncServerInfo2 *info;
> Error *err = NULL;
> SocketAddress *addr;
> @@ -476,10 +472,8 @@ static VncServerInfo2List *qmp_query_server_entry(QIOChannelSocket *ioc,
> qmp_query_auth(auth, subauth, &info->auth,
> &info->vencrypt, &info->has_vencrypt);
>
> - list = g_new0(VncServerInfo2List, 1);
> - list->value = info;
> - list->next = prev;
> - return list;
> + QAPI_LIST_ADD(prev, info);
> + return prev;
> }
>
> static void qmp_query_auth(int auth, int subauth,
> @@ -554,7 +548,7 @@ static void qmp_query_auth(int auth, int subauth,
>
> VncInfo2List *qmp_query_vnc_servers(Error **errp)
> {
> - VncInfo2List *item, *prev = NULL;
> + VncInfo2List *prev = NULL;
> VncInfo2 *info;
> VncDisplay *vd;
> DeviceState *dev;
> @@ -583,10 +577,7 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp)
> vd->ws_subauth, info->server);
> }
>
> - item = g_new0(VncInfo2List, 1);
> - item->value = info;
> - item->next = prev;
> - prev = item;
> + QAPI_LIST_ADD(prev, info);
> }
> return prev;
> }
> diff --git a/util/qemu-config.c b/util/qemu-config.c
> index 660f47b0050f..495ada45f3df 100644
> --- a/util/qemu-config.c
> +++ b/util/qemu-config.c
> @@ -55,7 +55,7 @@ QemuOpts *qemu_find_opts_singleton(const char *group)
>
> static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
> {
> - CommandLineParameterInfoList *param_list = NULL, *entry;
> + CommandLineParameterInfoList *param_list = NULL;
> CommandLineParameterInfo *info;
> int i;
>
> @@ -87,10 +87,7 @@ static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
> info->q_default = g_strdup(desc[i].def_value_str);
> }
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = param_list;
> - param_list = entry;
> + QAPI_LIST_ADD(param_list, info);
> }
>
> return param_list;
> @@ -246,7 +243,7 @@ CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
> const char *option,
> Error **errp)
> {
> - CommandLineOptionInfoList *conf_list = NULL, *entry;
> + CommandLineOptionInfoList *conf_list = NULL;
> CommandLineOptionInfo *info;
> int i;
>
> @@ -262,10 +259,7 @@ CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
> info->parameters =
> query_option_descs(vm_config_groups[i]->desc);
> }
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = conf_list;
> - conf_list = entry;
> + QAPI_LIST_ADD(conf_list, info);
> }
> }
>
> diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc
> index bb66526280ef..5795d0e5af2c 100644
> --- a/target/ppc/translate_init.c.inc
> +++ b/target/ppc/translate_init.c.inc
> @@ -10621,7 +10621,6 @@ static void ppc_cpu_defs_entry(gpointer data, gpointer user_data)
> ObjectClass *oc = data;
> CpuDefinitionInfoList **first = user_data;
> const char *typename;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
>
> typename = object_class_get_name(oc);
> @@ -10629,10 +10628,7 @@ static void ppc_cpu_defs_entry(gpointer data, gpointer user_data)
> info->name = g_strndup(typename,
> strlen(typename) - strlen(POWERPC_CPU_TYPE_SUFFIX));
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = *first;
> - *first = entry;
> + QAPI_LIST_ADD(*first, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> @@ -10648,7 +10644,6 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) {
> PowerPCCPUAlias *alias = &ppc_cpu_aliases[i];
> ObjectClass *oc;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
>
> oc = ppc_cpu_class_by_name(alias->model);
> @@ -10660,10 +10655,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> info->name = g_strdup(alias->alias);
> info->q_typename = g_strdup(object_class_get_name(oc));
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = cpu_list;
> - cpu_list = entry;
> + QAPI_LIST_ADD(cpu_list, info);
> }
>
> return cpu_list;
The macro definitely makes the code easier to read. Yes, please!
The patch feels almost ready.
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 04/11] nbd: Update qapi to support exporting multiple bitmaps
2020-10-27 5:05 ` [PATCH v6 04/11] nbd: Update qapi to support exporting multiple bitmaps Eric Blake
@ 2020-10-27 10:29 ` Vladimir Sementsov-Ogievskiy
2020-10-27 12:37 ` Peter Krempa
1 sibling, 0 replies; 28+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-10-27 10:29 UTC (permalink / raw)
To: Eric Blake, qemu-devel
Cc: kwolf, stefanha, armbru, rjones, pkrempa, qemu-block, Max Reitz,
reviewer:Incompatible changes
27.10.2020 08:05, Eric Blake wrote:
> Since 'block-export-add' is new to 5.2, we can still tweak the
> interface; there, allowing 'bitmaps':['str'] is nicer than
> 'bitmap':'str'. This wires up the qapi and qemu-nbd changes to permit
> passing multiple bitmaps as distinct metadata contexts that the NBD
> client may request, but the actual support for more than one will
> require a further patch to the server.
>
> Note that there are no changes made to the existing deprecated
> 'nbd-server-add' command; this required splitting the QAPI type
> BlockExportOptionsNbd, which fortunately does not affect QMP
> introspection.
>
> Signed-off-by: Eric Blake<eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
--
Best regards,
Vladimir
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 06/11] nbd: Refactor counting of metadata contexts
2020-10-27 5:05 ` [PATCH v6 06/11] nbd: Refactor counting of metadata contexts Eric Blake
@ 2020-10-27 10:33 ` Vladimir Sementsov-Ogievskiy
0 siblings, 0 replies; 28+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-10-27 10:33 UTC (permalink / raw)
To: Eric Blake, qemu-devel
Cc: kwolf, stefanha, armbru, rjones, pkrempa, qemu-block
27.10.2020 08:05, Eric Blake wrote:
> Rather than open-code the count of negotiated contexts at several
> sites, embed it directly into the struct. This will make it easier
> for upcoming commits to support even more simultaneous contexts.
>
> Signed-off-by: Eric Blake<eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
--
Best regards,
Vladimir
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 09/11] nbd: Add new qemu:allocation-depth metadata context
2020-10-27 5:05 ` [PATCH v6 09/11] nbd: Add new qemu:allocation-depth metadata context Eric Blake
@ 2020-10-27 10:53 ` Vladimir Sementsov-Ogievskiy
0 siblings, 0 replies; 28+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-10-27 10:53 UTC (permalink / raw)
To: Eric Blake, qemu-devel
Cc: kwolf, stefanha, armbru, rjones, pkrempa, qemu-block, Max Reitz
27.10.2020 08:05, Eric Blake wrote:
> 'qemu-img map' provides a way to determine which extents of an image
> come from the top layer vs. inherited from a backing chain. This is
> useful information worth exposing over NBD. There is a proposal to
> add a QMP command block-dirty-bitmap-populate which can create a dirty
> bitmap that reflects allocation information, at which point the
> qemu:dirty-bitmap:NAME metadata context can expose that information
> via the creation of a temporary bitmap, but we can shorten the effort
> by adding a new qemu:allocation-depth metadata context that does the
> same thing without an intermediate bitmap (this patch does not
> eliminate the need for that proposal, as it will have other uses as
> well).
>
> While documenting things, remember that although the NBD protocol has
> NBD_OPT_SET_META_CONTEXT, the rest of its documentation refers to
> 'metadata context', which is a more apt description of what is
> actually being used by NBD_CMD_BLOCK_STATUS: the user is requesting
> metadata by passing one or more context names. So I also touched up
> some existing wording to prefer the term 'metadata context' where it
> makes sense.
>
> Note that this patch does not actually enable any way to request a
> server to enable this context; that will come in the next patch.
>
> Signed-off-by: Eric Blake<eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
--
Best regards,
Vladimir
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 10/11] nbd: Add 'qemu-nbd -A' to expose allocation depth
2020-10-27 5:05 ` [PATCH v6 10/11] nbd: Add 'qemu-nbd -A' to expose allocation depth Eric Blake
@ 2020-10-27 11:03 ` Vladimir Sementsov-Ogievskiy
0 siblings, 0 replies; 28+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-10-27 11:03 UTC (permalink / raw)
To: Eric Blake, qemu-devel
Cc: kwolf, stefanha, armbru, rjones, pkrempa, qemu-block, Max Reitz
27.10.2020 08:05, Eric Blake wrote:
> Allow the server to expose an additional metacontext to be requested
> by savvy clients. qemu-nbd adds a new option -A to expose the
> qemu:allocation-depth metacontext through NBD_CMD_BLOCK_STATUS; this
> can also be set via QMP when using block-export-add.
>
> qemu as client is hacked into viewing the key aspects of this new
> context by abusing the already-experimental x-dirty-bitmap option to
> collapse all depths greater than 2, which results in a tri-state value
> visible in the output of 'qemu-img map --output=json' (yes, that means
> x-dirty-bitmap is now a bit of a misnomer, but I didn't feel like
> renaming it as it would introduce a needless break of back-compat,
> even though we make no compat guarantees with x- members):
>
> unallocated (depth 0) => "zero":false, "data":true
> local (depth 1) => "zero":false, "data":false
> backing (depth 2+) => "zero":true, "data":true
>
> libnbd as client is probably a nicer way to get at the information
> without having to decipher such hacks in qemu as client.;)
>
> Signed-off-by: Eric Blake<eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
--
Best regards,
Vladimir
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible
2020-10-27 5:05 ` [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible Eric Blake
` (2 preceding siblings ...)
2020-10-27 10:09 ` Markus Armbruster
@ 2020-10-27 11:26 ` Dr. David Alan Gilbert
2020-10-27 13:42 ` Vladimir Sementsov-Ogievskiy
4 siblings, 0 replies; 28+ messages in thread
From: Dr. David Alan Gilbert @ 2020-10-27 11:26 UTC (permalink / raw)
To: Eric Blake
Cc: Peter Maydell, pkrempa, Michael S. Tsirkin, Jason Wang,
qemu-devel, Jiaxun Yang, Philippe Mathieu-Daudé,
Gerd Hoffmann, Michael Roth, qemu-block, Juan Quintela,
David Hildenbrand, armbru, Halil Pasic, Christian Borntraeger,
Thomas Huth, Marc-André Lureau, David Gibson,
Aleksandar Rikalo, Jiri Pirko, Eduardo Habkost,
open list:S390 KVM CPUs, open list:GLUSTER, stefanha,
Richard Henderson, kwolf, vsementsov, Daniel P. Berrangé,
Cornelia Huck, rjones, Max Reitz, open list:ARM TCG CPUs,
open list:PowerPC TCG CPUs, Paolo Bonzini, Aurelien Jarno
* Eric Blake (eblake@redhat.com) wrote:
> Anywhere we create a list of just one item or by prepending items
> (typically because order doesn't matter), we can use the now-public
> macro. But places where we must keep the list in order by appending
> remain open-coded.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
> ---
> docs/devel/writing-qmp-commands.txt | 13 +++------
> hw/net/rocker/rocker_fp.h | 2 +-
> block/gluster.c | 19 +++++--------
> chardev/char.c | 21 +++++++--------
> hw/core/machine.c | 6 +----
> hw/net/rocker/rocker.c | 8 +++---
> hw/net/rocker/rocker_fp.c | 14 +++++-----
> hw/net/virtio-net.c | 21 +++++----------
> migration/migration.c | 7 ++---
> migration/postcopy-ram.c | 7 ++---
> monitor/hmp-cmds.c | 11 ++++----
> qemu-img.c | 5 ++--
> qga/commands-posix.c | 13 +++------
> qga/commands-win32.c | 17 +++---------
> qga/commands.c | 6 +----
> qom/qom-qmp-cmds.c | 29 ++++++--------------
> target/arm/helper.c | 6 +----
> target/arm/monitor.c | 13 ++-------
> target/i386/cpu.c | 6 +----
> target/mips/helper.c | 6 +----
> target/s390x/cpu_models.c | 12 ++-------
> tests/test-clone-visitor.c | 7 ++---
> tests/test-qobject-output-visitor.c | 42 ++++++++++++++---------------
> tests/test-visitor-serialization.c | 5 +---
> trace/qmp.c | 22 +++++++--------
> ui/vnc.c | 21 +++++----------
> util/qemu-config.c | 14 +++-------
> target/ppc/translate_init.c.inc | 12 ++-------
> 28 files changed, 119 insertions(+), 246 deletions(-)
>
> diff --git a/docs/devel/writing-qmp-commands.txt b/docs/devel/writing-qmp-commands.txt
> index 46a6c48683f5..3e11eeaa1893 100644
> --- a/docs/devel/writing-qmp-commands.txt
> +++ b/docs/devel/writing-qmp-commands.txt
> @@ -531,15 +531,10 @@ TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
> bool current = true;
>
> for (p = alarm_timers; p->name; p++) {
> - TimerAlarmMethodList *info = g_malloc0(sizeof(*info));
> - info->value = g_malloc0(sizeof(*info->value));
> - info->value->method_name = g_strdup(p->name);
> - info->value->current = current;
> -
> - current = false;
> -
> - info->next = method_list;
> - method_list = info;
> + TimerAlarmMethod *value = g_new0(TimerAlarmMethod, 1);
> + value->method_name = g_strdup(p->name);
> + value->current = current;
> + QAPI_LIST_ADD(method_list, value);
> }
>
> return method_list;
> diff --git a/hw/net/rocker/rocker_fp.h b/hw/net/rocker/rocker_fp.h
> index dbe1dd329a4b..4cb0bb9ccf81 100644
> --- a/hw/net/rocker/rocker_fp.h
> +++ b/hw/net/rocker/rocker_fp.h
> @@ -28,7 +28,7 @@ int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt);
>
> char *fp_port_get_name(FpPort *port);
> bool fp_port_get_link_up(FpPort *port);
> -void fp_port_get_info(FpPort *port, RockerPortList *info);
> +void fp_port_get_info(FpPort *port, RockerPort *info);
> void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr);
> void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr);
> uint8_t fp_port_get_learning(FpPort *port);
> diff --git a/block/gluster.c b/block/gluster.c
> index 4f1448e2bc88..cf446c23f85d 100644
> --- a/block/gluster.c
> +++ b/block/gluster.c
> @@ -359,8 +359,8 @@ static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
> return -EINVAL;
> }
>
> - gconf->server = g_new0(SocketAddressList, 1);
> - gconf->server->value = gsconf = g_new0(SocketAddress, 1);
> + gsconf = g_new0(SocketAddress, 1);
> + QAPI_LIST_ADD(gconf->server, gsconf);
>
> /* transport */
> if (!uri->scheme || !strcmp(uri->scheme, "gluster")) {
> @@ -514,7 +514,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
> {
> QemuOpts *opts;
> SocketAddress *gsconf = NULL;
> - SocketAddressList *curr = NULL;
> + SocketAddressList **curr;
> QDict *backing_options = NULL;
> Error *local_err = NULL;
> char *str = NULL;
> @@ -547,6 +547,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
> }
> gconf->path = g_strdup(ptr);
> qemu_opts_del(opts);
> + curr = &gconf->server;
>
> for (i = 0; i < num_servers; i++) {
> str = g_strdup_printf(GLUSTER_OPT_SERVER_PATTERN"%d.", i);
> @@ -655,15 +656,9 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
> qemu_opts_del(opts);
> }
>
> - if (gconf->server == NULL) {
> - gconf->server = g_new0(SocketAddressList, 1);
> - gconf->server->value = gsconf;
> - curr = gconf->server;
> - } else {
> - curr->next = g_new0(SocketAddressList, 1);
> - curr->next->value = gsconf;
> - curr = curr->next;
> - }
> + *curr = g_new0(SocketAddressList, 1);
> + (*curr)->value = gsconf;
> + curr = &(*curr)->next;
> gsconf = NULL;
>
> qobject_unref(backing_options);
> diff --git a/chardev/char.c b/chardev/char.c
> index 78553125d311..8dd7ef4c5935 100644
> --- a/chardev/char.c
> +++ b/chardev/char.c
> @@ -776,15 +776,14 @@ static int qmp_query_chardev_foreach(Object *obj, void *data)
> {
> Chardev *chr = CHARDEV(obj);
> ChardevInfoList **list = data;
> - ChardevInfoList *info = g_malloc0(sizeof(*info));
> + ChardevInfo *value;
>
> - info->value = g_malloc0(sizeof(*info->value));
> - info->value->label = g_strdup(chr->label);
> - info->value->filename = g_strdup(chr->filename);
> - info->value->frontend_open = chr->be && chr->be->fe_open;
> + value = g_malloc0(sizeof(*value));
> + value->label = g_strdup(chr->label);
> + value->filename = g_strdup(chr->filename);
> + value->frontend_open = chr->be && chr->be->fe_open;
>
> - info->next = *list;
> - *list = info;
> + QAPI_LIST_ADD(*list, value);
>
> return 0;
> }
> @@ -803,12 +802,10 @@ static void
> qmp_prepend_backend(const char *name, void *opaque)
> {
> ChardevBackendInfoList **list = opaque;
> - ChardevBackendInfoList *info = g_malloc0(sizeof(*info));
> + ChardevBackendInfo *value = g_new0(ChardevBackendInfo, 1);
>
> - info->value = g_malloc0(sizeof(*info->value));
> - info->value->name = g_strdup(name);
> - info->next = *list;
> - *list = info;
> + value->name = g_strdup(name);
> + QAPI_LIST_ADD(*list, value);
> }
>
> ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
> diff --git a/hw/core/machine.c b/hw/core/machine.c
> index c5e0e79e6dbc..a05c4739ca7a 100644
> --- a/hw/core/machine.c
> +++ b/hw/core/machine.c
> @@ -492,11 +492,7 @@ static void machine_set_nvdimm_persistence(Object *obj, const char *value,
>
> void machine_class_allow_dynamic_sysbus_dev(MachineClass *mc, const char *type)
> {
> - strList *item = g_new0(strList, 1);
> -
> - item->value = g_strdup(type);
> - item->next = mc->allowed_dynamic_sysbus_devices;
> - mc->allowed_dynamic_sysbus_devices = item;
> + QAPI_LIST_ADD(mc->allowed_dynamic_sysbus_devices, g_strdup(type));
> }
>
> static void validate_sysbus_device(SysBusDevice *sbdev, void *opaque)
> diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c
> index 1af1e6fa2f9b..a1137e11ff48 100644
> --- a/hw/net/rocker/rocker.c
> +++ b/hw/net/rocker/rocker.c
> @@ -127,13 +127,11 @@ RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
> }
>
> for (i = r->fp_ports - 1; i >= 0; i--) {
> - RockerPortList *info = g_malloc0(sizeof(*info));
> - info->value = g_malloc0(sizeof(*info->value));
> + RockerPort *value = g_malloc0(sizeof(*value));
> struct fp_port *port = r->fp_port[i];
>
> - fp_port_get_info(port, info);
> - info->next = list;
> - list = info;
> + fp_port_get_info(port, value);
> + QAPI_LIST_ADD(list, value);
> }
>
> return list;
> diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c
> index 4aa7da79b81d..a616e709292e 100644
> --- a/hw/net/rocker/rocker_fp.c
> +++ b/hw/net/rocker/rocker_fp.c
> @@ -51,14 +51,14 @@ bool fp_port_get_link_up(FpPort *port)
> return !qemu_get_queue(port->nic)->link_down;
> }
>
> -void fp_port_get_info(FpPort *port, RockerPortList *info)
> +void fp_port_get_info(FpPort *port, RockerPort *value)
> {
> - info->value->name = g_strdup(port->name);
> - info->value->enabled = port->enabled;
> - info->value->link_up = fp_port_get_link_up(port);
> - info->value->speed = port->speed;
> - info->value->duplex = port->duplex;
> - info->value->autoneg = port->autoneg;
> + value->name = g_strdup(port->name);
> + value->enabled = port->enabled;
> + value->link_up = fp_port_get_link_up(port);
> + value->speed = port->speed;
> + value->duplex = port->duplex;
> + value->autoneg = port->autoneg;
> }
>
> void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr)
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index 277289d56e76..6b13d3ca3c8f 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -437,17 +437,14 @@ static void rxfilter_notify(NetClientState *nc)
>
> static intList *get_vlan_table(VirtIONet *n)
> {
> - intList *list, *entry;
> + intList *list;
> int i, j;
>
> list = NULL;
> for (i = 0; i < MAX_VLAN >> 5; i++) {
> for (j = 0; n->vlans[i] && j <= 0x1f; j++) {
> if (n->vlans[i] & (1U << j)) {
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = (i << 5) + j;
> - entry->next = list;
> - list = entry;
> + QAPI_LIST_ADD(list, (i << 5) + j);
> }
> }
> }
> @@ -460,7 +457,7 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
> VirtIONet *n = qemu_get_nic_opaque(nc);
> VirtIODevice *vdev = VIRTIO_DEVICE(n);
> RxFilterInfo *info;
> - strList *str_list, *entry;
> + strList *str_list;
> int i;
>
> info = g_malloc0(sizeof(*info));
> @@ -491,19 +488,15 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
>
> str_list = NULL;
> for (i = 0; i < n->mac_table.first_multi; i++) {
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN);
> - entry->next = str_list;
> - str_list = entry;
> + QAPI_LIST_ADD(str_list,
> + qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN));
> }
> info->unicast_table = str_list;
>
> str_list = NULL;
> for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN);
> - entry->next = str_list;
> - str_list = entry;
> + QAPI_LIST_ADD(str_list,
> + qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN));
> }
> info->multicast_table = str_list;
> info->vlan_table = get_vlan_table(n);
> diff --git a/migration/migration.c b/migration/migration.c
> index deb6005b8d37..239a7e430214 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -368,12 +368,9 @@ int migration_incoming_enable_colo(void)
> void migrate_add_address(SocketAddress *address)
> {
> MigrationIncomingState *mis = migration_incoming_get_current();
> - SocketAddressList *addrs;
>
> - addrs = g_new0(SocketAddressList, 1);
> - addrs->next = mis->socket_address_list;
> - mis->socket_address_list = addrs;
> - addrs->value = QAPI_CLONE(SocketAddress, address);
> + QAPI_LIST_ADD(mis->socket_address_list,
> + QAPI_CLONE(SocketAddress, address));
> }
>
> void qemu_start_incoming_migration(const char *uri, Error **errp)
> diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
> index 0a2f88a87d06..18ac7e06c581 100644
> --- a/migration/postcopy-ram.c
> +++ b/migration/postcopy-ram.c
> @@ -145,14 +145,11 @@ static struct PostcopyBlocktimeContext *blocktime_context_new(void)
> static uint32List *get_vcpu_blocktime_list(PostcopyBlocktimeContext *ctx)
> {
> MachineState *ms = MACHINE(qdev_get_machine());
> - uint32List *list = NULL, *entry = NULL;
> + uint32List *list = NULL;
> int i;
>
> for (i = ms->smp.cpus - 1; i >= 0; i--) {
> - entry = g_new0(uint32List, 1);
> - entry->value = ctx->vcpu_blocktime[i];
> - entry->next = list;
> - list = entry;
> + QAPI_LIST_ADD(list, ctx->vcpu_blocktime[i]);
> }
>
> return list;
> diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
> index 9789f4277f50..629c3d1bf741 100644
> --- a/monitor/hmp-cmds.c
> +++ b/monitor/hmp-cmds.c
> @@ -1248,7 +1248,8 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
> const char *cap = qdict_get_str(qdict, "capability");
> bool state = qdict_get_bool(qdict, "state");
> Error *err = NULL;
> - MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
> + MigrationCapabilityStatusList *caps = NULL;
> + MigrationCapabilityStatus *value = NULL;
> int val;
>
> val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err);
> @@ -1256,10 +1257,10 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
> goto end;
> }
>
> - caps->value = g_malloc0(sizeof(*caps->value));
> - caps->value->capability = val;
> - caps->value->state = state;
> - caps->next = NULL;
> + value = g_malloc0(sizeof(*value));
> + value->capability = val;
> + value->state = state;
> + QAPI_LIST_ADD(caps, value);
> qmp_migrate_set_capabilities(caps, &err);
Yes, you could have probably moved the qapi_free up before the end:, but
not a worry, so from migration and HMP:
Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> end:
> diff --git a/qemu-img.c b/qemu-img.c
> index 2103507936ea..4cfa8bccc5e7 100644
> --- a/qemu-img.c
> +++ b/qemu-img.c
> @@ -1643,14 +1643,13 @@ static void do_dirty_bitmap_merge(const char *dst_node, const char *dst_name,
> Error **errp)
> {
> BlockDirtyBitmapMergeSource *merge_src;
> - BlockDirtyBitmapMergeSourceList *list;
> + BlockDirtyBitmapMergeSourceList *list = NULL;
>
> merge_src = g_new0(BlockDirtyBitmapMergeSource, 1);
> merge_src->type = QTYPE_QDICT;
> merge_src->u.external.node = g_strdup(src_node);
> merge_src->u.external.name = g_strdup(src_name);
> - list = g_new0(BlockDirtyBitmapMergeSourceList, 1);
> - list->value = merge_src;
> + QAPI_LIST_ADD(list, merge_src);
> qmp_block_dirty_bitmap_merge(dst_node, dst_name, list, errp);
> qapi_free_BlockDirtyBitmapMergeSourceList(list);
> }
> diff --git a/qga/commands-posix.c b/qga/commands-posix.c
> index 3bffee99d4c9..06540425ded2 100644
> --- a/qga/commands-posix.c
> +++ b/qga/commands-posix.c
> @@ -1211,7 +1211,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
> {
> FsMountList mounts;
> struct FsMount *mount;
> - GuestFilesystemInfoList *new, *ret = NULL;
> + GuestFilesystemInfoList *ret = NULL;
> Error *local_err = NULL;
>
> QTAILQ_INIT(&mounts);
> @@ -1224,10 +1224,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
> QTAILQ_FOREACH(mount, &mounts, next) {
> g_debug("Building guest fsinfo for '%s'", mount->dirname);
>
> - new = g_malloc0(sizeof(*ret));
> - new->value = build_guest_fsinfo(mount, &local_err);
> - new->next = ret;
> - ret = new;
> + QAPI_LIST_ADD(ret, build_guest_fsinfo(mount, &local_err));
> if (local_err) {
> error_propagate(errp, local_err);
> qapi_free_GuestFilesystemInfoList(ret);
> @@ -1493,7 +1490,6 @@ GuestFilesystemTrimResponse *
> qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
> {
> GuestFilesystemTrimResponse *response;
> - GuestFilesystemTrimResultList *list;
> GuestFilesystemTrimResult *result;
> int ret = 0;
> FsMountList mounts;
> @@ -1517,10 +1513,7 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
> result = g_malloc0(sizeof(*result));
> result->path = g_strdup(mount->dirname);
>
> - list = g_malloc0(sizeof(*list));
> - list->value = result;
> - list->next = response->paths;
> - response->paths = list;
> + QAPI_LIST_ADD(response->paths, result);
>
> fd = qemu_open_old(mount->dirname, O_RDONLY);
> if (fd == -1) {
> diff --git a/qga/commands-win32.c b/qga/commands-win32.c
> index 0c3c05484f5f..cc5736c3bba8 100644
> --- a/qga/commands-win32.c
> +++ b/qga/commands-win32.c
> @@ -926,10 +926,8 @@ static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
> error_free(local_err);
> goto out;
> }
> - list = g_malloc0(sizeof(*list));
> - list->value = disk;
> + QAPI_LIST_ADD(list, disk);
> disk = NULL;
> - list->next = NULL;
> goto out;
> } else {
> error_setg_win32(errp, GetLastError(),
> @@ -1064,7 +1062,7 @@ free:
> GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
> {
> HANDLE vol_h;
> - GuestFilesystemInfoList *new, *ret = NULL;
> + GuestFilesystemInfoList *ret = NULL;
> char guid[256];
>
> vol_h = FindFirstVolume(guid, sizeof(guid));
> @@ -1082,10 +1080,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
> error_free(local_err);
> continue;
> }
> - new = g_malloc(sizeof(*ret));
> - new->value = info;
> - new->next = ret;
> - ret = new;
> + QAPI_LIST_ADD(ret, info);
> } while (FindNextVolume(vol_h, guid, sizeof(guid)));
>
> if (GetLastError() != ERROR_NO_MORE_FILES) {
> @@ -1268,11 +1263,7 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
>
> res->path = path;
>
> - list = g_new0(GuestFilesystemTrimResultList, 1);
> - list->value = res;
> - list->next = resp->paths;
> -
> - resp->paths = list;
> + QAPI_LIST_ADD(resp->paths, res);
>
> memset(argv, 0, sizeof(argv));
> argv[0] = (gchar *)"defrag.exe";
> diff --git a/qga/commands.c b/qga/commands.c
> index 3dcd5fbe5c4d..27118df6caea 100644
> --- a/qga/commands.c
> +++ b/qga/commands.c
> @@ -66,17 +66,13 @@ static void qmp_command_info(const QmpCommand *cmd, void *opaque)
> {
> GuestAgentInfo *info = opaque;
> GuestAgentCommandInfo *cmd_info;
> - GuestAgentCommandInfoList *cmd_info_list;
>
> cmd_info = g_new0(GuestAgentCommandInfo, 1);
> cmd_info->name = g_strdup(qmp_command_name(cmd));
> cmd_info->enabled = qmp_command_is_enabled(cmd);
> cmd_info->success_response = qmp_has_success_response(cmd);
>
> - cmd_info_list = g_new0(GuestAgentCommandInfoList, 1);
> - cmd_info_list->value = cmd_info;
> - cmd_info_list->next = info->supported_commands;
> - info->supported_commands = cmd_info_list;
> + QAPI_LIST_ADD(info->supported_commands, cmd_info);
> }
>
> struct GuestAgentInfo *qmp_guest_info(Error **errp)
> diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
> index 310ab2d0481d..5ac9272ffeea 100644
> --- a/qom/qom-qmp-cmds.c
> +++ b/qom/qom-qmp-cmds.c
> @@ -46,14 +46,12 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
>
> object_property_iter_init(&iter, obj);
> while ((prop = object_property_iter_next(&iter))) {
> - ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
> + ObjectPropertyInfo *value = g_malloc0(sizeof(ObjectPropertyInfo));
>
> - entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
> - entry->next = props;
> - props = entry;
> + QAPI_LIST_ADD(props, value);
>
> - entry->value->name = g_strdup(prop->name);
> - entry->value->type = g_strdup(prop->type);
> + value->name = g_strdup(prop->name);
> + value->type = g_strdup(prop->type);
> }
>
> return props;
> @@ -90,7 +88,7 @@ QObject *qmp_qom_get(const char *path, const char *property, Error **errp)
>
> static void qom_list_types_tramp(ObjectClass *klass, void *data)
> {
> - ObjectTypeInfoList *e, **pret = data;
> + ObjectTypeInfoList **pret = data;
> ObjectTypeInfo *info;
> ObjectClass *parent = object_class_get_parent(klass);
>
> @@ -102,10 +100,7 @@ static void qom_list_types_tramp(ObjectClass *klass, void *data)
> info->parent = g_strdup(object_class_get_name(parent));
> }
>
> - e = g_malloc0(sizeof(*e));
> - e->value = info;
> - e->next = *pret;
> - *pret = e;
> + QAPI_LIST_ADD(*pret, info);
> }
>
> ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
> @@ -155,7 +150,6 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
> object_property_iter_init(&iter, obj);
> while ((prop = object_property_iter_next(&iter))) {
> ObjectPropertyInfo *info;
> - ObjectPropertyInfoList *entry;
>
> /* Skip Object and DeviceState properties */
> if (strcmp(prop->name, "type") == 0 ||
> @@ -181,10 +175,7 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
> info->default_value = qobject_ref(prop->defval);
> info->has_default_value = !!info->default_value;
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = prop_list;
> - prop_list = entry;
> + QAPI_LIST_ADD(prop_list, info);
> }
>
> object_unref(obj);
> @@ -222,7 +213,6 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
> }
> while ((prop = object_property_iter_next(&iter))) {
> ObjectPropertyInfo *info;
> - ObjectPropertyInfoList *entry;
>
> info = g_malloc0(sizeof(*info));
> info->name = g_strdup(prop->name);
> @@ -230,10 +220,7 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
> info->has_description = !!prop->description;
> info->description = g_strdup(prop->description);
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = prop_list;
> - prop_list = entry;
> + QAPI_LIST_ADD(prop_list, info);
> }
>
> object_unref(obj);
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 97bb6b8c01b4..df150f3c3eeb 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -8293,7 +8293,6 @@ static void arm_cpu_add_definition(gpointer data, gpointer user_data)
> {
> ObjectClass *oc = data;
> CpuDefinitionInfoList **cpu_list = user_data;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
> const char *typename;
>
> @@ -8303,10 +8302,7 @@ static void arm_cpu_add_definition(gpointer data, gpointer user_data)
> strlen(typename) - strlen("-" TYPE_ARM_CPU));
> info->q_typename = g_strdup(typename);
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = *cpu_list;
> - *cpu_list = entry;
> + QAPI_LIST_ADD(*cpu_list, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> diff --git a/target/arm/monitor.c b/target/arm/monitor.c
> index 169d8a64b651..771101656535 100644
> --- a/target/arm/monitor.c
> +++ b/target/arm/monitor.c
> @@ -42,15 +42,6 @@ static GICCapability *gic_cap_new(int version)
> return cap;
> }
>
> -static GICCapabilityList *gic_cap_list_add(GICCapabilityList *head,
> - GICCapability *cap)
> -{
> - GICCapabilityList *item = g_new0(GICCapabilityList, 1);
> - item->value = cap;
> - item->next = head;
> - return item;
> -}
> -
> static inline void gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3)
> {
> #ifdef CONFIG_KVM
> @@ -84,8 +75,8 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
>
> gic_cap_kvm_probe(v2, v3);
>
> - head = gic_cap_list_add(head, v2);
> - head = gic_cap_list_add(head, v3);
> + QAPI_LIST_ADD(head, v2);
> + QAPI_LIST_ADD(head, v3);
>
> return head;
> }
> diff --git a/target/i386/cpu.c b/target/i386/cpu.c
> index 0d8606958e9e..9ae6661f97e3 100644
> --- a/target/i386/cpu.c
> +++ b/target/i386/cpu.c
> @@ -4984,7 +4984,6 @@ static void x86_cpu_definition_entry(gpointer data, gpointer user_data)
> ObjectClass *oc = data;
> X86CPUClass *cc = X86_CPU_CLASS(oc);
> CpuDefinitionInfoList **cpu_list = user_data;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
>
> info = g_malloc0(sizeof(*info));
> @@ -5009,10 +5008,7 @@ static void x86_cpu_definition_entry(gpointer data, gpointer user_data)
> info->has_alias_of = !!info->alias_of;
> }
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = *cpu_list;
> - *cpu_list = entry;
> + QAPI_LIST_ADD(*cpu_list, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> diff --git a/target/mips/helper.c b/target/mips/helper.c
> index afd78b1990be..036bacc24b22 100644
> --- a/target/mips/helper.c
> +++ b/target/mips/helper.c
> @@ -1502,7 +1502,6 @@ static void mips_cpu_add_definition(gpointer data, gpointer user_data)
> {
> ObjectClass *oc = data;
> CpuDefinitionInfoList **cpu_list = user_data;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
> const char *typename;
>
> @@ -1512,10 +1511,7 @@ static void mips_cpu_add_definition(gpointer data, gpointer user_data)
> strlen(typename) - strlen("-" TYPE_MIPS_CPU));
> info->q_typename = g_strdup(typename);
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = *cpu_list;
> - *cpu_list = entry;
> + QAPI_LIST_ADD(*cpu_list, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
> index 461e0b8f4a8d..a837ac66c9c8 100644
> --- a/target/s390x/cpu_models.c
> +++ b/target/s390x/cpu_models.c
> @@ -427,7 +427,6 @@ static void create_cpu_model_list(ObjectClass *klass, void *opaque)
> {
> struct CpuDefinitionInfoListData *cpu_list_data = opaque;
> CpuDefinitionInfoList **cpu_list = &cpu_list_data->list;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
> char *name = g_strdup(object_class_get_name(klass));
> S390CPUClass *scc = S390_CPU_CLASS(klass);
> @@ -454,10 +453,7 @@ static void create_cpu_model_list(ObjectClass *klass, void *opaque)
> object_unref(obj);
> }
>
> - entry = g_new0(CpuDefinitionInfoList, 1);
> - entry->value = info;
> - entry->next = *cpu_list;
> - *cpu_list = entry;
> + QAPI_LIST_ADD(*cpu_list, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> @@ -624,12 +620,8 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
> static void list_add_feat(const char *name, void *opaque)
> {
> strList **last = (strList **) opaque;
> - strList *entry;
>
> - entry = g_new0(strList, 1);
> - entry->value = g_strdup(name);
> - entry->next = *last;
> - *last = entry;
> + QAPI_LIST_ADD(*last, g_strdup(name));
> }
>
> CpuModelCompareInfo *qmp_query_cpu_model_comparison(CpuModelInfo *infoa,
> diff --git a/tests/test-clone-visitor.c b/tests/test-clone-visitor.c
> index 5e1e8b2f5e8a..03788d355130 100644
> --- a/tests/test-clone-visitor.c
> +++ b/tests/test-clone-visitor.c
> @@ -65,16 +65,13 @@ static void test_clone_alternate(void)
>
> static void test_clone_list_union(void)
> {
> - uint8List *src, *dst;
> + uint8List *src = NULL, *dst;
> uint8List *tmp = NULL;
> int i;
>
> /* Build list in reverse */
> for (i = 10; i; i--) {
> - src = g_new0(uint8List, 1);
> - src->next = tmp;
> - src->value = i;
> - tmp = src;
> + QAPI_LIST_ADD(src, i);
> }
>
> dst = QAPI_CLONE(uint8List, src);
> diff --git a/tests/test-qobject-output-visitor.c b/tests/test-qobject-output-visitor.c
> index 1c856d9bd20a..95487b139801 100644
> --- a/tests/test-qobject-output-visitor.c
> +++ b/tests/test-qobject-output-visitor.c
> @@ -223,7 +223,8 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
> const void *unused)
> {
> const char *value_str = "list value";
> - TestStructList *p, *head = NULL;
> + TestStruct *value;
> + TestStructList *head = NULL;
> const int max_items = 10;
> bool value_bool = true;
> int value_int = 10;
> @@ -233,14 +234,12 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
>
> /* Build the list in reverse order... */
> for (i = 0; i < max_items; i++) {
> - p = g_malloc0(sizeof(*p));
> - p->value = g_malloc0(sizeof(*p->value));
> - p->value->integer = value_int + (max_items - i - 1);
> - p->value->boolean = value_bool;
> - p->value->string = g_strdup(value_str);
> + value = g_malloc0(sizeof(*value));
> + value->integer = value_int + (max_items - i - 1);
> + value->boolean = value_bool;
> + value->string = g_strdup(value_str);
>
> - p->next = head;
> - head = p;
> + QAPI_LIST_ADD(head, value);
> }
>
> visit_type_TestStructList(data->ov, NULL, &head, &error_abort);
> @@ -270,26 +269,25 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
> static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data,
> const void *unused)
> {
> - UserDefTwoList *p, *head = NULL;
> + UserDefTwo *value;
> + UserDefTwoList *head = NULL;
> const char string[] = "foo bar";
> int i, max_count = 1024;
>
> for (i = 0; i < max_count; i++) {
> - p = g_malloc0(sizeof(*p));
> - p->value = g_malloc0(sizeof(*p->value));
> + value = g_malloc0(sizeof(*value));
>
> - p->value->string0 = g_strdup(string);
> - p->value->dict1 = g_new0(UserDefTwoDict, 1);
> - p->value->dict1->string1 = g_strdup(string);
> - p->value->dict1->dict2 = g_new0(UserDefTwoDictDict, 1);
> - p->value->dict1->dict2->userdef = g_new0(UserDefOne, 1);
> - p->value->dict1->dict2->userdef->string = g_strdup(string);
> - p->value->dict1->dict2->userdef->integer = 42;
> - p->value->dict1->dict2->string = g_strdup(string);
> - p->value->dict1->has_dict3 = false;
> + value->string0 = g_strdup(string);
> + value->dict1 = g_new0(UserDefTwoDict, 1);
> + value->dict1->string1 = g_strdup(string);
> + value->dict1->dict2 = g_new0(UserDefTwoDictDict, 1);
> + value->dict1->dict2->userdef = g_new0(UserDefOne, 1);
> + value->dict1->dict2->userdef->string = g_strdup(string);
> + value->dict1->dict2->userdef->integer = 42;
> + value->dict1->dict2->string = g_strdup(string);
> + value->dict1->has_dict3 = false;
>
> - p->next = head;
> - head = p;
> + QAPI_LIST_ADD(head, value);
> }
>
> qapi_free_UserDefTwoList(head);
> diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c
> index 1c5a8b94ea87..efbf744fcf25 100644
> --- a/tests/test-visitor-serialization.c
> +++ b/tests/test-visitor-serialization.c
> @@ -704,10 +704,7 @@ static void test_nested_struct_list(gconstpointer opaque)
> int i = 0;
>
> for (i = 0; i < 8; i++) {
> - tmp = g_new0(UserDefTwoList, 1);
> - tmp->value = nested_struct_create();
> - tmp->next = listp;
> - listp = tmp;
> + QAPI_LIST_ADD(listp, nested_struct_create());
> }
>
> ops->serialize(listp, &serialize_data, visit_nested_struct_list,
> diff --git a/trace/qmp.c b/trace/qmp.c
> index 38246e1aa692..8755835edabc 100644
> --- a/trace/qmp.c
> +++ b/trace/qmp.c
> @@ -92,39 +92,37 @@ TraceEventInfoList *qmp_trace_event_get_state(const char *name,
> /* Get states (all errors checked above) */
> trace_event_iter_init(&iter, name);
> while ((ev = trace_event_iter_next(&iter)) != NULL) {
> - TraceEventInfoList *elem;
> + TraceEventInfo *value;
> bool is_vcpu = trace_event_is_vcpu(ev);
> if (has_vcpu && !is_vcpu) {
> continue;
> }
>
> - elem = g_new(TraceEventInfoList, 1);
> - elem->value = g_new(TraceEventInfo, 1);
> - elem->value->vcpu = is_vcpu;
> - elem->value->name = g_strdup(trace_event_get_name(ev));
> + value = g_new(TraceEventInfo, 1);
> + value->vcpu = is_vcpu;
> + value->name = g_strdup(trace_event_get_name(ev));
>
> if (!trace_event_get_state_static(ev)) {
> - elem->value->state = TRACE_EVENT_STATE_UNAVAILABLE;
> + value->state = TRACE_EVENT_STATE_UNAVAILABLE;
> } else {
> if (has_vcpu) {
> if (is_vcpu) {
> if (trace_event_get_vcpu_state_dynamic(cpu, ev)) {
> - elem->value->state = TRACE_EVENT_STATE_ENABLED;
> + value->state = TRACE_EVENT_STATE_ENABLED;
> } else {
> - elem->value->state = TRACE_EVENT_STATE_DISABLED;
> + value->state = TRACE_EVENT_STATE_DISABLED;
> }
> }
> /* else: already skipped above */
> } else {
> if (trace_event_get_state_dynamic(ev)) {
> - elem->value->state = TRACE_EVENT_STATE_ENABLED;
> + value->state = TRACE_EVENT_STATE_ENABLED;
> } else {
> - elem->value->state = TRACE_EVENT_STATE_DISABLED;
> + value->state = TRACE_EVENT_STATE_DISABLED;
> }
> }
> }
> - elem->next = events;
> - events = elem;
> + QAPI_LIST_ADD(events, value);
> }
>
> return events;
> diff --git a/ui/vnc.c b/ui/vnc.c
> index f006aa1afdb2..f39cfc952906 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -365,14 +365,11 @@ static VncDisplay *vnc_display_find(const char *id)
>
> static VncClientInfoList *qmp_query_client_list(VncDisplay *vd)
> {
> - VncClientInfoList *cinfo, *prev = NULL;
> + VncClientInfoList *prev = NULL;
> VncState *client;
>
> QTAILQ_FOREACH(client, &vd->clients, next) {
> - cinfo = g_new0(VncClientInfoList, 1);
> - cinfo->value = qmp_query_vnc_client(client);
> - cinfo->next = prev;
> - prev = cinfo;
> + QAPI_LIST_ADD(prev, qmp_query_vnc_client(client));
> }
> return prev;
> }
> @@ -453,7 +450,6 @@ static VncServerInfo2List *qmp_query_server_entry(QIOChannelSocket *ioc,
> int subauth,
> VncServerInfo2List *prev)
> {
> - VncServerInfo2List *list;
> VncServerInfo2 *info;
> Error *err = NULL;
> SocketAddress *addr;
> @@ -476,10 +472,8 @@ static VncServerInfo2List *qmp_query_server_entry(QIOChannelSocket *ioc,
> qmp_query_auth(auth, subauth, &info->auth,
> &info->vencrypt, &info->has_vencrypt);
>
> - list = g_new0(VncServerInfo2List, 1);
> - list->value = info;
> - list->next = prev;
> - return list;
> + QAPI_LIST_ADD(prev, info);
> + return prev;
> }
>
> static void qmp_query_auth(int auth, int subauth,
> @@ -554,7 +548,7 @@ static void qmp_query_auth(int auth, int subauth,
>
> VncInfo2List *qmp_query_vnc_servers(Error **errp)
> {
> - VncInfo2List *item, *prev = NULL;
> + VncInfo2List *prev = NULL;
> VncInfo2 *info;
> VncDisplay *vd;
> DeviceState *dev;
> @@ -583,10 +577,7 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp)
> vd->ws_subauth, info->server);
> }
>
> - item = g_new0(VncInfo2List, 1);
> - item->value = info;
> - item->next = prev;
> - prev = item;
> + QAPI_LIST_ADD(prev, info);
> }
> return prev;
> }
> diff --git a/util/qemu-config.c b/util/qemu-config.c
> index 660f47b0050f..495ada45f3df 100644
> --- a/util/qemu-config.c
> +++ b/util/qemu-config.c
> @@ -55,7 +55,7 @@ QemuOpts *qemu_find_opts_singleton(const char *group)
>
> static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
> {
> - CommandLineParameterInfoList *param_list = NULL, *entry;
> + CommandLineParameterInfoList *param_list = NULL;
> CommandLineParameterInfo *info;
> int i;
>
> @@ -87,10 +87,7 @@ static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
> info->q_default = g_strdup(desc[i].def_value_str);
> }
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = param_list;
> - param_list = entry;
> + QAPI_LIST_ADD(param_list, info);
> }
>
> return param_list;
> @@ -246,7 +243,7 @@ CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
> const char *option,
> Error **errp)
> {
> - CommandLineOptionInfoList *conf_list = NULL, *entry;
> + CommandLineOptionInfoList *conf_list = NULL;
> CommandLineOptionInfo *info;
> int i;
>
> @@ -262,10 +259,7 @@ CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
> info->parameters =
> query_option_descs(vm_config_groups[i]->desc);
> }
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = conf_list;
> - conf_list = entry;
> + QAPI_LIST_ADD(conf_list, info);
> }
> }
>
> diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc
> index bb66526280ef..5795d0e5af2c 100644
> --- a/target/ppc/translate_init.c.inc
> +++ b/target/ppc/translate_init.c.inc
> @@ -10621,7 +10621,6 @@ static void ppc_cpu_defs_entry(gpointer data, gpointer user_data)
> ObjectClass *oc = data;
> CpuDefinitionInfoList **first = user_data;
> const char *typename;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
>
> typename = object_class_get_name(oc);
> @@ -10629,10 +10628,7 @@ static void ppc_cpu_defs_entry(gpointer data, gpointer user_data)
> info->name = g_strndup(typename,
> strlen(typename) - strlen(POWERPC_CPU_TYPE_SUFFIX));
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = *first;
> - *first = entry;
> + QAPI_LIST_ADD(*first, info);
> }
>
> CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> @@ -10648,7 +10644,6 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) {
> PowerPCCPUAlias *alias = &ppc_cpu_aliases[i];
> ObjectClass *oc;
> - CpuDefinitionInfoList *entry;
> CpuDefinitionInfo *info;
>
> oc = ppc_cpu_class_by_name(alias->model);
> @@ -10660,10 +10655,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
> info->name = g_strdup(alias->alias);
> info->q_typename = g_strdup(object_class_get_name(oc));
>
> - entry = g_malloc0(sizeof(*entry));
> - entry->value = info;
> - entry->next = cpu_list;
> - cpu_list = entry;
> + QAPI_LIST_ADD(cpu_list, info);
> }
>
> return cpu_list;
> --
> 2.29.0
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 08/11] block: Return depth level during bdrv_is_allocated_above
2020-10-27 5:05 ` [PATCH v6 08/11] block: Return depth level during bdrv_is_allocated_above Eric Blake
@ 2020-10-27 12:05 ` Vladimir Sementsov-Ogievskiy
0 siblings, 0 replies; 28+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-10-27 12:05 UTC (permalink / raw)
To: Eric Blake, qemu-devel
Cc: kwolf, stefanha, armbru, rjones, pkrempa, qemu-block, John Snow,
Max Reitz, Fam Zheng
27.10.2020 08:05, Eric Blake wrote:
> When checking for allocation across a chain, it's already easy to
> count the depth within the chain at which the allocation is found.
> Instead of throwing that information away, return it to the caller.
> Existing callers only cared about allocated/non-allocated, but having
> a depth available will be used by NBD in the next patch.
>
> Signed-off-by: Eric Blake<eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
--
Best regards,
Vladimir
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible
2020-10-27 10:09 ` Markus Armbruster
@ 2020-10-27 12:28 ` Eric Blake
2020-10-27 15:36 ` Markus Armbruster
0 siblings, 1 reply; 28+ messages in thread
From: Eric Blake @ 2020-10-27 12:28 UTC (permalink / raw)
To: Markus Armbruster
Cc: Peter Maydell, pkrempa, Michael S. Tsirkin, Jason Wang,
qemu-devel, Jiaxun Yang, Philippe Mathieu-Daudé,
Gerd Hoffmann, qemu-block, Juan Quintela, David Hildenbrand,
Michael Roth, Halil Pasic, Christian Borntraeger,
Marc-André Lureau, Richard Henderson, Thomas Huth,
Jiri Pirko, Eduardo Habkost, Dr. David Alan Gilbert,
open list:S390 KVM CPUs, vsementsov, stefanha, David Gibson,
kwolf, open list:GLUSTER, Daniel P. Berrangé, Cornelia Huck,
rjones, Max Reitz, open list:ARM TCG CPUs,
open list:PowerPC TCG CPUs, Paolo Bonzini, Aleksandar Rikalo,
Aurelien Jarno
On 10/27/20 5:09 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
>
>> Anywhere we create a list of just one item or by prepending items
>> (typically because order doesn't matter), we can use the now-public
>> macro. But places where we must keep the list in order by appending
>> remain open-coded.
>
> Should we rename the macro to QAPI_LIST_PREPEND()?
That would make sense if we add a counterpart QAPI_LIST_APPEND.
>
> How many places append? If it's more than just a few, an attempt to
> factor out the common code is in order. Not in this patch, of course.
> Not even in this series.
Quite a few. The most common pattern for appending is like this from
qemu-img.c:
ImageInfoList *head = NULL, *elem;
ImageInfoList **last = &head;
...
while (...) {
elem = g_new0(ImageInfoList, 1);
elem->value = info;
*last = elem;
last = &elem->next;
}
although I saw several other patterns as well. And we frequently have
this comment, such as from block/qapi.c:
/* XXX: waiting for the qapi to support qemu-queue.h types */
Several of the existing append spots could be switched to prepend with
no change to semantics (the resulting list would be presented to the
user in the opposite order, but the semantics of that item were a set
rather than an ordered list so other than tweaking the testsuite, it
would not matter), while others absolutely have to append to maintain
correct order.
Part of me wonders if it would be worth adjusting the QAPI generator to
create a head and tail pointer for _every_ FOOList member, rather than
just a head pointer. Or to create a function for an O(n) reversal of an
existing list, then flipping spots to construct lists in reverse order
followed by a list reverse (no change in big-O complexity, more code
reuse, but slightly more CPU time). But as you observe, that quickly
goes beyond the scope of this series.
>> +++ b/docs/devel/writing-qmp-commands.txt
>> @@ -531,15 +531,10 @@ TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
>> bool current = true;
>>
>> for (p = alarm_timers; p->name; p++) {
>> - TimerAlarmMethodList *info = g_malloc0(sizeof(*info));
[1]
>> - info->value = g_malloc0(sizeof(*info->value));
[2]
>> - info->value->method_name = g_strdup(p->name);
>> - info->value->current = current;
>> -
>> - current = false;
>> -
>> - info->next = method_list;
>> - method_list = info;
>> + TimerAlarmMethod *value = g_new0(TimerAlarmMethod, 1);
>
> Can just as well use g_new(), as QAPI_LIST_ADD() will set both members
> of @value. Same elsewhere.
Not quite. Allocation [1] can use g_new() instead of g_malloc0()
because we fill both members of info, but allocation [2] is unchanged by
this code transformation (I did not want to research whether the code
was filling all members of info->value (probably true, but it was
unrelated to my rewrite). Switching to QAPI_LIST_ADD is what moves
allocation [1] into the macro (where it indeed uses g_new), but
QAPI_LIST_ADD has no impact on the contents of value in allocation [2]
(which is the only allocation left locally in this hunk).
However, the fact that I changed from g_malloc0(sizeof(*info->value)) to
g_new0(TimerAlarmMethod, 1), instead of keeping it as
g_malloc0(sizeof(*value)), is indeed a case of me doing a bit more than
a strict mechanical conversion; this was one of the hunks I touched
earlier in my audit.
>> @@ -655,15 +656,9 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
>> qemu_opts_del(opts);
>> }
>>
>> - if (gconf->server == NULL) {
>> - gconf->server = g_new0(SocketAddressList, 1);
>> - gconf->server->value = gsconf;
>> - curr = gconf->server;
>> - } else {
>> - curr->next = g_new0(SocketAddressList, 1);
>> - curr->next->value = gsconf;
>> - curr = curr->next;
>> - }
>> + *curr = g_new0(SocketAddressList, 1);
>> + (*curr)->value = gsconf;
>> + curr = &(*curr)->next;
>> gsconf = NULL;
>>
>> qobject_unref(backing_options);
>
> The change to qemu_gluster_parse_json() looks unrelated.
Indeed, this is also one of the earlier files I touched, where I saw
that our 'append' pattern can be simplified, but it's separate from the
'prepend' pattern that this patch should be touching. I guess I'll need
to clean this patch up to be more strictly mechanical.
>
>> diff --git a/chardev/char.c b/chardev/char.c
>> index 78553125d311..8dd7ef4c5935 100644
>> --- a/chardev/char.c
>> +++ b/chardev/char.c
>> @@ -776,15 +776,14 @@ static int qmp_query_chardev_foreach(Object *obj, void *data)
>> {
>> Chardev *chr = CHARDEV(obj);
>> ChardevInfoList **list = data;
>> - ChardevInfoList *info = g_malloc0(sizeof(*info));
>> + ChardevInfo *value;
>>
>> - info->value = g_malloc0(sizeof(*info->value));
>> - info->value->label = g_strdup(chr->label);
>> - info->value->filename = g_strdup(chr->filename);
>> - info->value->frontend_open = chr->be && chr->be->fe_open;
>> + value = g_malloc0(sizeof(*value));
>
> You could use an initializer instead, like you do in the next hunk. Up
> to you.
Yeah, the further I got into the manual audit, the less I was rewriting
code to minimize lines, such as consistently initializing variables at
their declaration.
>> +++ b/hw/core/machine.c
>> @@ -492,11 +492,7 @@ static void machine_set_nvdimm_persistence(Object *obj, const char *value,
>>
>> void machine_class_allow_dynamic_sysbus_dev(MachineClass *mc, const char *type)
>> {
>> - strList *item = g_new0(strList, 1);
>> -
>> - item->value = g_strdup(type);
>> - item->next = mc->allowed_dynamic_sysbus_devices;
>> - mc->allowed_dynamic_sysbus_devices = item;
>> + QAPI_LIST_ADD(mc->allowed_dynamic_sysbus_devices, g_strdup(type));
>
> Side effect in a macro argument. Works, because QAPI_LIST_ADD() expands
> @element exactly once. Sure we want to rely on it?
>
> If yes, please add a contract to QAPI_LIST_ADD() that documents it.
Multiple instances depend on it, so yes, I think it's worth documenting.
>
> More instances below.
Indeed.
>> +++ b/hw/net/rocker/rocker_fp.c
>> @@ -51,14 +51,14 @@ bool fp_port_get_link_up(FpPort *port)
>> return !qemu_get_queue(port->nic)->link_down;
>> }
>>
>> -void fp_port_get_info(FpPort *port, RockerPortList *info)
>> +void fp_port_get_info(FpPort *port, RockerPort *value)
>> {
>> - info->value->name = g_strdup(port->name);
>> - info->value->enabled = port->enabled;
>> - info->value->link_up = fp_port_get_link_up(port);
>> - info->value->speed = port->speed;
>> - info->value->duplex = port->duplex;
>> - info->value->autoneg = port->autoneg;
>> + value->name = g_strdup(port->name);
>> + value->enabled = port->enabled;
>> + value->link_up = fp_port_get_link_up(port);
>> + value->speed = port->speed;
>> + value->duplex = port->duplex;
>> + value->autoneg = port->autoneg;
>> }
>
> This cleanup of fp_port_get_info() could be a separate patch. Up to
> you.
>
> You could move the allocation into fp_port_get_info(), like this:
>
> RockerPort *fp_port_get_info(FpPort *port)
> {
> RockerPort *value = g_malloc0(sizeof(*value));
>
> value->name = g_strdup(port->name);
> value->enabled = port->enabled;
> value->link_up = fp_port_get_link_up(port);
> value->speed = port->speed;
> value->duplex = port->duplex;
> value->autoneg = port->autoneg;
> return value;
> }
>
> Also up to you.
Yeah, I thought about splitting that one out. I think you've convinced
me it is worth it.
>> +++ b/monitor/hmp-cmds.c
>> @@ -1248,7 +1248,8 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
>> const char *cap = qdict_get_str(qdict, "capability");
>> bool state = qdict_get_bool(qdict, "state");
>> Error *err = NULL;
>> - MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
>> + MigrationCapabilityStatusList *caps = NULL;
>> + MigrationCapabilityStatus *value = NULL;
>
> No need to initialize @value.
>
>> int val;
>>
>> val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err);
>> @@ -1256,10 +1257,10 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
>> goto end;
>> }
>>
>> - caps->value = g_malloc0(sizeof(*caps->value));
>> - caps->value->capability = val;
>> - caps->value->state = state;
>> - caps->next = NULL;
>> + value = g_malloc0(sizeof(*value));
>> + value->capability = val;
>> + value->state = state;
>> + QAPI_LIST_ADD(caps, value);
>> qmp_migrate_set_capabilities(caps, &err);
>>
>> end:
> qapi_free_MigrationCapabilityStatusList(caps);
>
> This could be moved before the label now. No need to initialize @caps
> to null then. Up to you.
>
> hmp_handle_error(mon, err);
> }
>
Since the conversion was all manual, I don't mind making it look nicer,
when it is still minimally invasive.
>
>> diff --git a/qemu-img.c b/qemu-img.c
>> index 2103507936ea..4cfa8bccc5e7 100644
>> --- a/qemu-img.c
>> +++ b/qemu-img.c
>> @@ -1643,14 +1643,13 @@ static void do_dirty_bitmap_merge(const char *dst_node, const char *dst_name,
>> Error **errp)
>> {
>> BlockDirtyBitmapMergeSource *merge_src;
>> - BlockDirtyBitmapMergeSourceList *list;
>> + BlockDirtyBitmapMergeSourceList *list = NULL;
>>
>> merge_src = g_new0(BlockDirtyBitmapMergeSource, 1);
>> merge_src->type = QTYPE_QDICT;
>> merge_src->u.external.node = g_strdup(src_node);
>> merge_src->u.external.name = g_strdup(src_name);
>> - list = g_new0(BlockDirtyBitmapMergeSourceList, 1);
>> - list->value = merge_src;
>> + QAPI_LIST_ADD(list, merge_src);
>> qmp_block_dirty_bitmap_merge(dst_node, dst_name, list, errp);
>> qapi_free_BlockDirtyBitmapMergeSourceList(list);
>> }
>> diff --git a/qga/commands-posix.c b/qga/commands-posix.c
>> index 3bffee99d4c9..06540425ded2 100644
>> --- a/qga/commands-posix.c
>> +++ b/qga/commands-posix.c
>> @@ -1211,7 +1211,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
>> {
>> FsMountList mounts;
>> struct FsMount *mount;
>> - GuestFilesystemInfoList *new, *ret = NULL;
>> + GuestFilesystemInfoList *ret = NULL;
>> Error *local_err = NULL;
>>
>> QTAILQ_INIT(&mounts);
>> @@ -1224,10 +1224,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
>> QTAILQ_FOREACH(mount, &mounts, next) {
>> g_debug("Building guest fsinfo for '%s'", mount->dirname);
>>
>> - new = g_malloc0(sizeof(*ret));
>
> Ugh! Glad you get rid of this.
Yep, C++ reserved words as a C variable name is always awkward. It was
fun cleaning that up (several places in this patch).
>> +++ b/qga/commands-win32.c
>> @@ -926,10 +926,8 @@ static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
>> error_free(local_err);
>> goto out;
>> }
>> - list = g_malloc0(sizeof(*list));
>> - list->value = disk;
>> + QAPI_LIST_ADD(list, disk);
>> disk = NULL;
>> - list->next = NULL;
>> goto out;
>
> Both old and new code tacitly rely on @list being empty. Okay.
This was population of a single element into list (so prepending vs.
appending doesn't matter, and we can use the prepend macro), while...
>
>> } else {
>> error_setg_win32(errp, GetLastError(),
>
> Did you miss the spot where we add to this list?
>
> /* Go through each extent */
> for (i = 0; i < extents->NumberOfDiskExtents; i++) {
> disk = g_malloc0(sizeof(GuestDiskAddress));
>
> /* Disk numbers directly correspond to numbers used in UNCs
> *
> * See documentation for DISK_EXTENT:
> * https://docs.microsoft.com/en-us/windows/desktop/api/winioctl/ns-winioctl-_disk_extent
> *
> * See also Naming Files, Paths and Namespaces:
> * https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#win32-device-namespaces
> */
> disk->has_dev = true;
> disk->dev = g_strdup_printf("\\\\.\\PhysicalDrive%lu",
> extents->Extents[i].DiskNumber);
>
> get_single_disk_info(extents->Extents[i].DiskNumber, disk, &local_err);
> if (local_err) {
> error_propagate(errp, local_err);
> goto out;
> }
> cur_item = g_malloc0(sizeof(*list));
> cur_item->value = disk;
> disk = NULL;
> cur_item->next = list;
> ---> list = cur_item;
> }
This is appending, not prepending. Using the macro here would have
reversed the multi-element list seen by the user. I did not check
whether the QMP is documenting that particular list more as a set (where
order does not matter, so prepending is fine) or as an ordered list, but
instead conservatively left it to appending. As we said earlier,
further cleanups of all append places may be worth its own later series.
>> +++ b/qom/qom-qmp-cmds.c
>> @@ -46,14 +46,12 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
>>
>> object_property_iter_init(&iter, obj);
>> while ((prop = object_property_iter_next(&iter))) {
>> - ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
>> + ObjectPropertyInfo *value = g_malloc0(sizeof(ObjectPropertyInfo));
>>
>> - entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
>> - entry->next = props;
>> - props = entry;
>> + QAPI_LIST_ADD(props, value);
>>
>> - entry->value->name = g_strdup(prop->name);
>> - entry->value->type = g_strdup(prop->type);
>> + value->name = g_strdup(prop->name);
>> + value->type = g_strdup(prop->type);
>
> This is the minimally invasive patch. Best to stick to minimal in a big
> series like this one, to ease review as much as possible.
>
> If that wasn't an issue, I'd suggest finishing the list element before
> inserting it into the list:
>
> ObjectPropertyInfo *value = g_malloc0(sizeof(ObjectPropertyInfo));
>
> value->name = g_strdup(prop->name);
> value->type = g_strdup(prop->type);
> QAPI_LIST_ADD(props, value);
>
> There might be more instances.
Agreed (both that sticking to minimally invasive is good, and on the
fact that this patch points out a number of future potential cleanups).
>
> The macro definitely makes the code easier to read. Yes, please!
>
> The patch feels almost ready.
Thanks for the careful review!
Right now, my thoughts are to get 1-10 into 5.2, then turn this one
patch into a more-complete series for post-5.2 that address more cases
of QAPI list management (splitting this patch into at least 3 based on
the comments above, then new patches to make appending use more
consistent patterns before adding macros to ease that as well).
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization: qemu.org | libvirt.org
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 04/11] nbd: Update qapi to support exporting multiple bitmaps
2020-10-27 5:05 ` [PATCH v6 04/11] nbd: Update qapi to support exporting multiple bitmaps Eric Blake
2020-10-27 10:29 ` Vladimir Sementsov-Ogievskiy
@ 2020-10-27 12:37 ` Peter Krempa
1 sibling, 0 replies; 28+ messages in thread
From: Peter Krempa @ 2020-10-27 12:37 UTC (permalink / raw)
To: Eric Blake
Cc: kwolf, vsementsov, qemu-block, reviewer:Incompatible changes,
armbru, rjones, qemu-devel, stefanha, Max Reitz
On Tue, Oct 27, 2020 at 00:05:49 -0500, Eric Blake wrote:
> Since 'block-export-add' is new to 5.2, we can still tweak the
> interface; there, allowing 'bitmaps':['str'] is nicer than
> 'bitmap':'str'. This wires up the qapi and qemu-nbd changes to permit
> passing multiple bitmaps as distinct metadata contexts that the NBD
> client may request, but the actual support for more than one will
> require a further patch to the server.
>
> Note that there are no changes made to the existing deprecated
> 'nbd-server-add' command; this required splitting the QAPI type
> BlockExportOptionsNbd, which fortunately does not affect QMP
> introspection.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
> ---
> docs/system/deprecated.rst | 3 ++-
> qapi/block-export.json | 41 +++++++++++++++++++++++++++-----------
> blockdev-nbd.c | 6 +++++-
> nbd/server.c | 19 ++++++++++++------
> qemu-nbd.c | 18 ++++++++---------
> 5 files changed, 58 insertions(+), 29 deletions(-)
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 01/11] block: Simplify QAPI_LIST_ADD
2020-10-27 5:05 ` [PATCH v6 01/11] block: Simplify QAPI_LIST_ADD Eric Blake
2020-10-27 10:06 ` Vladimir Sementsov-Ogievskiy
@ 2020-10-27 12:58 ` Markus Armbruster
1 sibling, 0 replies; 28+ messages in thread
From: Markus Armbruster @ 2020-10-27 12:58 UTC (permalink / raw)
To: Eric Blake
Cc: kwolf, pkrempa, qemu-block, qemu-devel, rjones, vsementsov,
stefanha, Max Reitz
Eric Blake <eblake@redhat.com> writes:
> There is no need to rely on the verbosity of the gcc/clang compiler
> extension of g_new(typeof(X), 1) when we can instead use the standard
> g_malloc(sizeof(X)). In general, we like g_new over g_malloc for
> returning type X rather than void* to let the compiler catch more
> potential typing mistakes, but in this particular macro, our other use
> of typeof on the same line already ensures we are getting correct
> results.
>
> Suggested-by: Markus Armbruster <armbru@redhat.com>
> Signed-off-by: Eric Blake <eblake@redhat.com>
> ---
> block.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/block.c b/block.c
> index 430edf79bb10..857387f3912f 100644
> --- a/block.c
> +++ b/block.c
> @@ -5231,7 +5231,7 @@ BlockDeviceInfoList *bdrv_named_nodes_list(bool flat,
> }
>
> #define QAPI_LIST_ADD(list, element) do { \
> - typeof(list) _tmp = g_new(typeof(*(list)), 1); \
> + typeof(list) _tmp = g_malloc(sizeof(*(list))); \
> _tmp->value = (element); \
> _tmp->next = (list); \
> (list) = _tmp; \
Reviewed-by: Markus Armbruster <armbru@redhat.com>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible
2020-10-27 5:05 ` [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible Eric Blake
` (3 preceding siblings ...)
2020-10-27 11:26 ` Dr. David Alan Gilbert
@ 2020-10-27 13:42 ` Vladimir Sementsov-Ogievskiy
4 siblings, 0 replies; 28+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-10-27 13:42 UTC (permalink / raw)
To: Eric Blake, qemu-devel
Cc: kwolf, stefanha, armbru, rjones, pkrempa, qemu-block, Max Reitz,
Marc-André Lureau, Paolo Bonzini, Eduardo Habkost,
Marcel Apfelbaum, Jiri Pirko, Jason Wang, Michael S. Tsirkin,
Juan Quintela, Dr. David Alan Gilbert, Michael Roth,
Daniel P. Berrangé, Peter Maydell, Richard Henderson,
Philippe Mathieu-Daudé, Aurelien Jarno, Jiaxun Yang,
Aleksandar Rikalo, David Gibson, Halil Pasic, Cornelia Huck,
Christian Borntraeger, Thomas Huth, David Hildenbrand,
Gerd Hoffmann, open list:GLUSTER, open list:ARM TCG CPUs,
open list:PowerPC TCG CPUs, open list:S390 KVM CPUs
27.10.2020 08:05, Eric Blake wrote:
> Anywhere we create a list of just one item or by prepending items
> (typically because order doesn't matter), we can use the now-public
> macro. But places where we must keep the list in order by appending
> remain open-coded.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
> ---
[..]
>
> diff --git a/docs/devel/writing-qmp-commands.txt b/docs/devel/writing-qmp-commands.txt
> index 46a6c48683f5..3e11eeaa1893 100644
> --- a/docs/devel/writing-qmp-commands.txt
> +++ b/docs/devel/writing-qmp-commands.txt
> @@ -531,15 +531,10 @@ TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
> bool current = true;
>
> for (p = alarm_timers; p->name; p++) {
> - TimerAlarmMethodList *info = g_malloc0(sizeof(*info));
> - info->value = g_malloc0(sizeof(*info->value));
> - info->value->method_name = g_strdup(p->name);
> - info->value->current = current;
> -
> - current = false;
You need to keep this line, otherwise logic is broken.
> -
> - info->next = method_list;
> - method_list = info;
> + TimerAlarmMethod *value = g_new0(TimerAlarmMethod, 1);
> + value->method_name = g_strdup(p->name);
> + value->current = current;
> + QAPI_LIST_ADD(method_list, value);
> }
>
> return method_list;
--
Best regards,
Vladimir
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible
2020-10-27 12:28 ` Eric Blake
@ 2020-10-27 15:36 ` Markus Armbruster
2020-10-27 18:44 ` Eric Blake
0 siblings, 1 reply; 28+ messages in thread
From: Markus Armbruster @ 2020-10-27 15:36 UTC (permalink / raw)
To: Eric Blake
Cc: Peter Maydell, pkrempa, Michael S. Tsirkin, Jason Wang,
qemu-devel, Jiaxun Yang, rjones, Gerd Hoffmann, qemu-block,
Juan Quintela, David Hildenbrand, Michael Roth, Halil Pasic,
Christian Borntraeger, Marc-André Lureau, David Gibson,
Thomas Huth, Jiri Pirko, Eduardo Habkost, Dr. David Alan Gilbert,
open list:S390 KVM CPUs, open list:GLUSTER, stefanha,
Richard Henderson, kwolf, vsementsov, Daniel P. Berrangé,
Cornelia Huck, Philippe Mathieu-Daudé, Max Reitz,
open list:ARM TCG CPUs, open list:PowerPC TCG CPUs, Paolo Bonzini,
Aleksandar Rikalo, Aurelien Jarno
Eric Blake <eblake@redhat.com> writes:
> On 10/27/20 5:09 AM, Markus Armbruster wrote:
>> Eric Blake <eblake@redhat.com> writes:
>>
>>> Anywhere we create a list of just one item or by prepending items
>>> (typically because order doesn't matter), we can use the now-public
>>> macro. But places where we must keep the list in order by appending
>>> remain open-coded.
>>
>> Should we rename the macro to QAPI_LIST_PREPEND()?
>
> That would make sense if we add a counterpart QAPI_LIST_APPEND.
It may make sense even if we don't. QAPI_LIST_ADD() leaves the reader
guessing whether we prepend or append.
>> How many places append? If it's more than just a few, an attempt to
>> factor out the common code is in order. Not in this patch, of course.
>> Not even in this series.
>
> Quite a few. The most common pattern for appending is like this from
> qemu-img.c:
>
> ImageInfoList *head = NULL, *elem;
> ImageInfoList **last = &head;
> ...
> while (...) {
> elem = g_new0(ImageInfoList, 1);
> elem->value = info;
> *last = elem;
> last = &elem->next;
> }
>
> although I saw several other patterns as well. And we frequently have
> this comment, such as from block/qapi.c:
> /* XXX: waiting for the qapi to support qemu-queue.h types */
>
> Several of the existing append spots could be switched to prepend with
> no change to semantics (the resulting list would be presented to the
> user in the opposite order, but the semantics of that item were a set
> rather than an ordered list so other than tweaking the testsuite, it
> would not matter), while others absolutely have to append to maintain
> correct order.
>
> Part of me wonders if it would be worth adjusting the QAPI generator to
> create a head and tail pointer for _every_ FOOList member, rather than
> just a head pointer.
Changes the C type we generate for a QAPI array from pointer to struct.
Could be awkward.
> Or to create a function for an O(n) reversal of an
> existing list, then flipping spots to construct lists in reverse order
> followed by a list reverse (no change in big-O complexity, more code
> reuse, but slightly more CPU time).
I'd expect the cost of reversing the list to be negligible.
Another option is to simply factor out the common part of the common way
to build a list by appending: "append to list, update tail pointer".
Similar to how QAPI_LIST_ADD() factors out the common "prepend to list,
update head pointer".
> But as you observe, that quickly
> goes beyond the scope of this series.
Definitely.
>>> +++ b/docs/devel/writing-qmp-commands.txt
>>> @@ -531,15 +531,10 @@ TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
>>> bool current = true;
>>>
>>> for (p = alarm_timers; p->name; p++) {
>>> - TimerAlarmMethodList *info = g_malloc0(sizeof(*info));
>
> [1]
>
>>> - info->value = g_malloc0(sizeof(*info->value));
>
> [2]
>
>>> - info->value->method_name = g_strdup(p->name);
>>> - info->value->current = current;
>>> -
>>> - current = false;
>>> -
>>> - info->next = method_list;
>>> - method_list = info;
>>> + TimerAlarmMethod *value = g_new0(TimerAlarmMethod, 1);
>>
>> Can just as well use g_new(), as QAPI_LIST_ADD() will set both members
>> of @value. Same elsewhere.
>
> Not quite. Allocation [1] can use g_new() instead of g_malloc0()
> because we fill both members of info, but allocation [2] is unchanged by
> this code transformation (I did not want to research whether the code
> was filling all members of info->value (probably true, but it was
> unrelated to my rewrite). Switching to QAPI_LIST_ADD is what moves
> allocation [1] into the macro (where it indeed uses g_new), but
> QAPI_LIST_ADD has no impact on the contents of value in allocation [2]
> (which is the only allocation left locally in this hunk).
You're right.
> However, the fact that I changed from g_malloc0(sizeof(*info->value)) to
> g_new0(TimerAlarmMethod, 1), instead of keeping it as
> g_malloc0(sizeof(*value)), is indeed a case of me doing a bit more than
> a strict mechanical conversion; this was one of the hunks I touched
> earlier in my audit.
>
>
>>> @@ -655,15 +656,9 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
>>> qemu_opts_del(opts);
>>> }
>>>
>>> - if (gconf->server == NULL) {
>>> - gconf->server = g_new0(SocketAddressList, 1);
>>> - gconf->server->value = gsconf;
>>> - curr = gconf->server;
>>> - } else {
>>> - curr->next = g_new0(SocketAddressList, 1);
>>> - curr->next->value = gsconf;
>>> - curr = curr->next;
>>> - }
>>> + *curr = g_new0(SocketAddressList, 1);
>>> + (*curr)->value = gsconf;
>>> + curr = &(*curr)->next;
>>> gsconf = NULL;
>>>
>>> qobject_unref(backing_options);
>>
>> The change to qemu_gluster_parse_json() looks unrelated.
>
> Indeed, this is also one of the earlier files I touched, where I saw
> that our 'append' pattern can be simplified, but it's separate from the
> 'prepend' pattern that this patch should be touching. I guess I'll need
> to clean this patch up to be more strictly mechanical.
>
>>
>>> diff --git a/chardev/char.c b/chardev/char.c
>>> index 78553125d311..8dd7ef4c5935 100644
>>> --- a/chardev/char.c
>>> +++ b/chardev/char.c
>>> @@ -776,15 +776,14 @@ static int qmp_query_chardev_foreach(Object *obj, void *data)
>>> {
>>> Chardev *chr = CHARDEV(obj);
>>> ChardevInfoList **list = data;
>>> - ChardevInfoList *info = g_malloc0(sizeof(*info));
>>> + ChardevInfo *value;
>>>
>>> - info->value = g_malloc0(sizeof(*info->value));
>>> - info->value->label = g_strdup(chr->label);
>>> - info->value->filename = g_strdup(chr->filename);
>>> - info->value->frontend_open = chr->be && chr->be->fe_open;
>>> + value = g_malloc0(sizeof(*value));
>>
>> You could use an initializer instead, like you do in the next hunk. Up
>> to you.
>
> Yeah, the further I got into the manual audit, the less I was rewriting
> code to minimize lines, such as consistently initializing variables at
> their declaration.
>
>>> +++ b/hw/core/machine.c
>>> @@ -492,11 +492,7 @@ static void machine_set_nvdimm_persistence(Object *obj, const char *value,
>>>
>>> void machine_class_allow_dynamic_sysbus_dev(MachineClass *mc, const char *type)
>>> {
>>> - strList *item = g_new0(strList, 1);
>>> -
>>> - item->value = g_strdup(type);
>>> - item->next = mc->allowed_dynamic_sysbus_devices;
>>> - mc->allowed_dynamic_sysbus_devices = item;
>>> + QAPI_LIST_ADD(mc->allowed_dynamic_sysbus_devices, g_strdup(type));
>>
>> Side effect in a macro argument. Works, because QAPI_LIST_ADD() expands
>> @element exactly once. Sure we want to rely on it?
>>
>> If yes, please add a contract to QAPI_LIST_ADD() that documents it.
>
> Multiple instances depend on it, so yes, I think it's worth documenting.
>
>>
>> More instances below.
>
> Indeed.
>
>
>>> +++ b/hw/net/rocker/rocker_fp.c
>>> @@ -51,14 +51,14 @@ bool fp_port_get_link_up(FpPort *port)
>>> return !qemu_get_queue(port->nic)->link_down;
>>> }
>>>
>>> -void fp_port_get_info(FpPort *port, RockerPortList *info)
>>> +void fp_port_get_info(FpPort *port, RockerPort *value)
>>> {
>>> - info->value->name = g_strdup(port->name);
>>> - info->value->enabled = port->enabled;
>>> - info->value->link_up = fp_port_get_link_up(port);
>>> - info->value->speed = port->speed;
>>> - info->value->duplex = port->duplex;
>>> - info->value->autoneg = port->autoneg;
>>> + value->name = g_strdup(port->name);
>>> + value->enabled = port->enabled;
>>> + value->link_up = fp_port_get_link_up(port);
>>> + value->speed = port->speed;
>>> + value->duplex = port->duplex;
>>> + value->autoneg = port->autoneg;
>>> }
>>
>> This cleanup of fp_port_get_info() could be a separate patch. Up to
>> you.
>>
>> You could move the allocation into fp_port_get_info(), like this:
>>
>> RockerPort *fp_port_get_info(FpPort *port)
>> {
>> RockerPort *value = g_malloc0(sizeof(*value));
>>
>> value->name = g_strdup(port->name);
>> value->enabled = port->enabled;
>> value->link_up = fp_port_get_link_up(port);
>> value->speed = port->speed;
>> value->duplex = port->duplex;
>> value->autoneg = port->autoneg;
>> return value;
>> }
>>
>> Also up to you.
>
> Yeah, I thought about splitting that one out. I think you've convinced
> me it is worth it.
>
>>> +++ b/monitor/hmp-cmds.c
>>> @@ -1248,7 +1248,8 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
>>> const char *cap = qdict_get_str(qdict, "capability");
>>> bool state = qdict_get_bool(qdict, "state");
>>> Error *err = NULL;
>>> - MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
>>> + MigrationCapabilityStatusList *caps = NULL;
>>> + MigrationCapabilityStatus *value = NULL;
>>
>> No need to initialize @value.
>>
>>> int val;
>>>
>>> val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err);
>>> @@ -1256,10 +1257,10 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
>>> goto end;
>>> }
>>>
>>> - caps->value = g_malloc0(sizeof(*caps->value));
>>> - caps->value->capability = val;
>>> - caps->value->state = state;
>>> - caps->next = NULL;
>>> + value = g_malloc0(sizeof(*value));
>>> + value->capability = val;
>>> + value->state = state;
>>> + QAPI_LIST_ADD(caps, value);
>>> qmp_migrate_set_capabilities(caps, &err);
>>>
>>> end:
>> qapi_free_MigrationCapabilityStatusList(caps);
>>
>> This could be moved before the label now. No need to initialize @caps
>> to null then. Up to you.
>>
>> hmp_handle_error(mon, err);
>> }
>>
>
> Since the conversion was all manual, I don't mind making it look nicer,
> when it is still minimally invasive.
>
>>
>>> diff --git a/qemu-img.c b/qemu-img.c
>>> index 2103507936ea..4cfa8bccc5e7 100644
>>> --- a/qemu-img.c
>>> +++ b/qemu-img.c
>>> @@ -1643,14 +1643,13 @@ static void do_dirty_bitmap_merge(const char *dst_node, const char *dst_name,
>>> Error **errp)
>>> {
>>> BlockDirtyBitmapMergeSource *merge_src;
>>> - BlockDirtyBitmapMergeSourceList *list;
>>> + BlockDirtyBitmapMergeSourceList *list = NULL;
>>>
>>> merge_src = g_new0(BlockDirtyBitmapMergeSource, 1);
>>> merge_src->type = QTYPE_QDICT;
>>> merge_src->u.external.node = g_strdup(src_node);
>>> merge_src->u.external.name = g_strdup(src_name);
>>> - list = g_new0(BlockDirtyBitmapMergeSourceList, 1);
>>> - list->value = merge_src;
>>> + QAPI_LIST_ADD(list, merge_src);
>>> qmp_block_dirty_bitmap_merge(dst_node, dst_name, list, errp);
>>> qapi_free_BlockDirtyBitmapMergeSourceList(list);
>>> }
>>> diff --git a/qga/commands-posix.c b/qga/commands-posix.c
>>> index 3bffee99d4c9..06540425ded2 100644
>>> --- a/qga/commands-posix.c
>>> +++ b/qga/commands-posix.c
>>> @@ -1211,7 +1211,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
>>> {
>>> FsMountList mounts;
>>> struct FsMount *mount;
>>> - GuestFilesystemInfoList *new, *ret = NULL;
>>> + GuestFilesystemInfoList *ret = NULL;
>>> Error *local_err = NULL;
>>>
>>> QTAILQ_INIT(&mounts);
>>> @@ -1224,10 +1224,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
>>> QTAILQ_FOREACH(mount, &mounts, next) {
>>> g_debug("Building guest fsinfo for '%s'", mount->dirname);
>>>
>>> - new = g_malloc0(sizeof(*ret));
>>
>> Ugh! Glad you get rid of this.
>
> Yep, C++ reserved words as a C variable name is always awkward. It was
> fun cleaning that up (several places in this patch).
I don't give a rat's ass about C++, actually. I'm glad you got rid of
the tacit "@new points to the same type as @ret does".
Clean:
new = g_malloc0(sizeof(*new));
new = g_new0(GuestFilesystemInfoList, 1);
Clean (but I'd use g_new0() instead):
new = g_malloc0(sizeof(GuestFilesystemInfoList));
Dirty:
new = g_malloc0(sizeof(X));
where X is anything else.
>
>
>>> +++ b/qga/commands-win32.c
>>> @@ -926,10 +926,8 @@ static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
>>> error_free(local_err);
>>> goto out;
>>> }
>>> - list = g_malloc0(sizeof(*list));
>>> - list->value = disk;
>>> + QAPI_LIST_ADD(list, disk);
>>> disk = NULL;
>>> - list->next = NULL;
>>> goto out;
>>
>> Both old and new code tacitly rely on @list being empty. Okay.
>
> This was population of a single element into list (so prepending vs.
> appending doesn't matter, and we can use the prepend macro), while...
>
>>
>>> } else {
>>> error_setg_win32(errp, GetLastError(),
>>
>> Did you miss the spot where we add to this list?
>>
>> /* Go through each extent */
>> for (i = 0; i < extents->NumberOfDiskExtents; i++) {
>> disk = g_malloc0(sizeof(GuestDiskAddress));
>>
>> /* Disk numbers directly correspond to numbers used in UNCs
>> *
>> * See documentation for DISK_EXTENT:
>> * https://docs.microsoft.com/en-us/windows/desktop/api/winioctl/ns-winioctl-_disk_extent
>> *
>> * See also Naming Files, Paths and Namespaces:
>> * https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#win32-device-namespaces
>> */
>> disk->has_dev = true;
>> disk->dev = g_strdup_printf("\\\\.\\PhysicalDrive%lu",
>> extents->Extents[i].DiskNumber);
>>
>> get_single_disk_info(extents->Extents[i].DiskNumber, disk, &local_err);
>> if (local_err) {
>> error_propagate(errp, local_err);
>> goto out;
>> }
>> cur_item = g_malloc0(sizeof(*list));
>> cur_item->value = disk;
>> disk = NULL;
>> cur_item->next = list;
>> ---> list = cur_item;
>> }
>
> This is appending, not prepending.
One of us is blind, and it might be me :)
@list points to the first element (we return it, so it better does).
@cur_item is the new list node.
We set cut_item->next = list, and then list = cur_item. Sure looks like
prepending to me.
> Using the macro here would have
> reversed the multi-element list seen by the user. I did not check
> whether the QMP is documenting that particular list more as a set (where
> order does not matter, so prepending is fine) or as an ordered list, but
> instead conservatively left it to appending. As we said earlier,
> further cleanups of all append places may be worth its own later series.
>
>>> +++ b/qom/qom-qmp-cmds.c
>>> @@ -46,14 +46,12 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
>>>
>>> object_property_iter_init(&iter, obj);
>>> while ((prop = object_property_iter_next(&iter))) {
>>> - ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
>>> + ObjectPropertyInfo *value = g_malloc0(sizeof(ObjectPropertyInfo));
>>>
>>> - entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
>>> - entry->next = props;
>>> - props = entry;
>>> + QAPI_LIST_ADD(props, value);
>>>
>>> - entry->value->name = g_strdup(prop->name);
>>> - entry->value->type = g_strdup(prop->type);
>>> + value->name = g_strdup(prop->name);
>>> + value->type = g_strdup(prop->type);
>>
>> This is the minimally invasive patch. Best to stick to minimal in a big
>> series like this one, to ease review as much as possible.
>>
>> If that wasn't an issue, I'd suggest finishing the list element before
>> inserting it into the list:
>>
>> ObjectPropertyInfo *value = g_malloc0(sizeof(ObjectPropertyInfo));
>>
>> value->name = g_strdup(prop->name);
>> value->type = g_strdup(prop->type);
>> QAPI_LIST_ADD(props, value);
>>
>> There might be more instances.
>
> Agreed (both that sticking to minimally invasive is good, and on the
> fact that this patch points out a number of future potential cleanups).
>
>>
>> The macro definitely makes the code easier to read. Yes, please!
>>
>> The patch feels almost ready.
>
> Thanks for the careful review!
>
> Right now, my thoughts are to get 1-10 into 5.2, then turn this one
Makes sense.
> patch into a more-complete series for post-5.2 that address more cases
> of QAPI list management (splitting this patch into at least 3 based on
> the comments above, then new patches to make appending use more
> consistent patterns before adding macros to ease that as well).
Holding the updated prepend part until the append part is ready for
posting might be unadvisable. You decide.
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible
2020-10-27 15:36 ` Markus Armbruster
@ 2020-10-27 18:44 ` Eric Blake
0 siblings, 0 replies; 28+ messages in thread
From: Eric Blake @ 2020-10-27 18:44 UTC (permalink / raw)
To: Markus Armbruster
Cc: Peter Maydell, pkrempa, Michael S. Tsirkin, Jason Wang,
qemu-devel, Jiaxun Yang, rjones, Gerd Hoffmann, qemu-block,
Juan Quintela, David Hildenbrand, Michael Roth, Halil Pasic,
Christian Borntraeger, Marc-André Lureau, David Gibson,
Thomas Huth, Jiri Pirko, Eduardo Habkost, Dr. David Alan Gilbert,
open list:S390 KVM CPUs, open list:GLUSTER, stefanha,
Richard Henderson, kwolf, vsementsov, Daniel P. Berrangé,
Cornelia Huck, Philippe Mathieu-Daudé, Max Reitz,
open list:ARM TCG CPUs, open list:PowerPC TCG CPUs, Paolo Bonzini,
Aleksandar Rikalo, Aurelien Jarno
On 10/27/20 10:36 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
>
>> On 10/27/20 5:09 AM, Markus Armbruster wrote:
>>> Eric Blake <eblake@redhat.com> writes:
>>>
>>>> Anywhere we create a list of just one item or by prepending items
>>>> (typically because order doesn't matter), we can use the now-public
>>>> macro. But places where we must keep the list in order by appending
>>>> remain open-coded.
>>>
>>> Should we rename the macro to QAPI_LIST_PREPEND()?
>>
>> That would make sense if we add a counterpart QAPI_LIST_APPEND.
>
> It may make sense even if we don't. QAPI_LIST_ADD() leaves the reader
> guessing whether we prepend or append.
That's a strong enough argument for me to make the rename in patch 2/11,
with minor rebase fallout in the rest of the series, and then this patch
gets a major rewrite (but I'm already not trying to get this patch into
5.2).
>>>> @@ -1224,10 +1224,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
>>>> QTAILQ_FOREACH(mount, &mounts, next) {
>>>> g_debug("Building guest fsinfo for '%s'", mount->dirname);
>>>>
>>>> - new = g_malloc0(sizeof(*ret));
>>>
>>> Ugh! Glad you get rid of this.
>>
>> Yep, C++ reserved words as a C variable name is always awkward. It was
>> fun cleaning that up (several places in this patch).
>
> I don't give a rat's ass about C++, actually. I'm glad you got rid of
> the tacit "@new points to the same type as @ret does".
>
> Clean:
>
> new = g_malloc0(sizeof(*new));
> new = g_new0(GuestFilesystemInfoList, 1);
>
> Clean (but I'd use g_new0() instead):
>
> new = g_malloc0(sizeof(GuestFilesystemInfoList));
>
> Dirty:
>
> new = g_malloc0(sizeof(X));
>
> where X is anything else.
Ah, I hadn't even spotted what you disliked, but yes, it makes total
sense that allocating for assignment to one variable by utilizing the
type from another puts unnecessary linkage that the two variables must
have the same type.
>>> Did you miss the spot where we add to this list?
>>>
>>> /* Go through each extent */
>>> for (i = 0; i < extents->NumberOfDiskExtents; i++) {
>>> disk = g_malloc0(sizeof(GuestDiskAddress));
>>>
>>> /* Disk numbers directly correspond to numbers used in UNCs
>>> *
>>> * See documentation for DISK_EXTENT:
>>> * https://docs.microsoft.com/en-us/windows/desktop/api/winioctl/ns-winioctl-_disk_extent
>>> *
>>> * See also Naming Files, Paths and Namespaces:
>>> * https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#win32-device-namespaces
>>> */
>>> disk->has_dev = true;
>>> disk->dev = g_strdup_printf("\\\\.\\PhysicalDrive%lu",
>>> extents->Extents[i].DiskNumber);
>>>
>>> get_single_disk_info(extents->Extents[i].DiskNumber, disk, &local_err);
>>> if (local_err) {
>>> error_propagate(errp, local_err);
>>> goto out;
>>> }
>>> cur_item = g_malloc0(sizeof(*list));
>>> cur_item->value = disk;
>>> disk = NULL;
>>> cur_item->next = list;
>>> ---> list = cur_item;
>>> }
>>
>> This is appending, not prepending.
>
> One of us is blind, and it might be me :)
Oh, I indeed misread this. Yes, this is prepending after all, so I'll
use the macro here.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization: qemu.org | libvirt.org
^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2020-10-27 18:58 UTC | newest]
Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-10-27 5:05 [PATCH v6 00/11] Exposing backing-chain allocation over NBD Eric Blake
2020-10-27 5:05 ` [PATCH v6 01/11] block: Simplify QAPI_LIST_ADD Eric Blake
2020-10-27 10:06 ` Vladimir Sementsov-Ogievskiy
2020-10-27 12:58 ` Markus Armbruster
2020-10-27 5:05 ` [PATCH v6 02/11] qapi: Make QAPI_LIST_ADD() public Eric Blake
2020-10-27 5:05 ` [PATCH v6 03/11] nbd: Utilize QAPI_CLONE for type conversion Eric Blake
2020-10-27 5:05 ` [PATCH v6 04/11] nbd: Update qapi to support exporting multiple bitmaps Eric Blake
2020-10-27 10:29 ` Vladimir Sementsov-Ogievskiy
2020-10-27 12:37 ` Peter Krempa
2020-10-27 5:05 ` [PATCH v6 05/11] nbd: Simplify qemu bitmap context name Eric Blake
2020-10-27 5:05 ` [PATCH v6 06/11] nbd: Refactor counting of metadata contexts Eric Blake
2020-10-27 10:33 ` Vladimir Sementsov-Ogievskiy
2020-10-27 5:05 ` [PATCH v6 07/11] nbd: Allow export of multiple bitmaps for one device Eric Blake
2020-10-27 5:05 ` [PATCH v6 08/11] block: Return depth level during bdrv_is_allocated_above Eric Blake
2020-10-27 12:05 ` Vladimir Sementsov-Ogievskiy
2020-10-27 5:05 ` [PATCH v6 09/11] nbd: Add new qemu:allocation-depth metadata context Eric Blake
2020-10-27 10:53 ` Vladimir Sementsov-Ogievskiy
2020-10-27 5:05 ` [PATCH v6 10/11] nbd: Add 'qemu-nbd -A' to expose allocation depth Eric Blake
2020-10-27 11:03 ` Vladimir Sementsov-Ogievskiy
2020-10-27 5:05 ` [PATCH v6 11/11] qapi: Use QAPI_LIST_ADD() where possible Eric Blake
2020-10-27 5:53 ` Thomas Huth
2020-10-27 6:39 ` David Gibson
2020-10-27 10:09 ` Markus Armbruster
2020-10-27 12:28 ` Eric Blake
2020-10-27 15:36 ` Markus Armbruster
2020-10-27 18:44 ` Eric Blake
2020-10-27 11:26 ` Dr. David Alan Gilbert
2020-10-27 13:42 ` Vladimir Sementsov-Ogievskiy
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).