diff options
author | SeokYeon Hwang <syeon.hwang@samsung.com> | 2017-06-28 16:20:50 +0900 |
---|---|---|
committer | SeokYeon Hwang <syeon.hwang@samsung.com> | 2017-06-28 16:21:16 +0900 |
commit | e6230f92c2a7c924f4092b877ee70a74f76e6841 (patch) | |
tree | 3f6f4a364da163b80c9669f903eda6f8aeb4d19b /qapi | |
parent | e9775ba331166fc2de29a387b1070281c8ec0985 (diff) | |
parent | 6ca9395b240883513b16a1875a7080b081612c57 (diff) | |
download | qemu-e6230f92c2a7c924f4092b877ee70a74f76e6841.tar.gz qemu-e6230f92c2a7c924f4092b877ee70a74f76e6841.tar.bz2 qemu-e6230f92c2a7c924f4092b877ee70a74f76e6841.zip |
Merge spin into tizen
Change-Id: I00f8d0dbf2d26f3c9c6754b9f1d986355037f5bb
Diffstat (limited to 'qapi')
-rw-r--r-- | qapi/Makefile.objs | 4 | ||||
-rw-r--r-- | qapi/block-core.json | 551 | ||||
-rw-r--r-- | qapi/block.json | 47 | ||||
-rw-r--r-- | qapi/common.json | 14 | ||||
-rw-r--r-- | qapi/crypto.json | 45 | ||||
-rw-r--r-- | qapi/event.json | 58 | ||||
-rw-r--r-- | qapi/introspect.json | 28 | ||||
-rw-r--r-- | qapi/qapi-clone-visitor.c | 2 | ||||
-rw-r--r-- | qapi/qapi-visit-core.c | 51 | ||||
-rw-r--r-- | qapi/qmp-event.c | 17 | ||||
-rw-r--r-- | qapi/qmp-output-visitor.c | 256 | ||||
-rw-r--r-- | qapi/qmp-registry.c | 8 | ||||
-rw-r--r-- | qapi/qobject-input-visitor.c (renamed from qapi/qmp-input-visitor.c) | 221 | ||||
-rw-r--r-- | qapi/qobject-output-visitor.c | 254 | ||||
-rw-r--r-- | qapi/rocker.json | 2 | ||||
-rw-r--r-- | qapi/trace-events | 33 | ||||
-rw-r--r-- | qapi/trace.json | 8 |
17 files changed, 967 insertions, 632 deletions
diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs index 7ea4aebb00..33906ff321 100644 --- a/qapi/Makefile.objs +++ b/qapi/Makefile.objs @@ -1,5 +1,5 @@ -util-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o -util-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o +util-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qobject-input-visitor.o +util-obj-y += qobject-output-visitor.o qmp-registry.o qmp-dispatch.o util-obj-y += string-input-visitor.o string-output-visitor.o util-obj-y += opts-visitor.o qapi-clone-visitor.o util-obj-y += qmp-event.o diff --git a/qapi/block-core.json b/qapi/block-core.json index 5e2d7d78d2..6b42216960 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -6,7 +6,7 @@ { 'include': 'common.json' } ## -# @SnapshotInfo +# @SnapshotInfo: # # @id: unique snapshot id # @@ -25,7 +25,6 @@ # Since: 1.3 # ## - { 'struct': 'SnapshotInfo', 'data': { 'id': 'str', 'name': 'str', 'vm-state-size': 'int', 'date-sec': 'int', 'date-nsec': 'int', @@ -81,7 +80,6 @@ # # Since: 1.7 ## - { 'union': 'ImageInfoSpecific', 'data': { 'qcow2': 'ImageInfoSpecificQCow2', @@ -129,7 +127,6 @@ # Since: 1.3 # ## - { 'struct': 'ImageInfo', 'data': {'filename': 'str', 'format': 'str', '*dirty-flag': 'bool', '*actual-size': 'int', 'virtual-size': 'int', @@ -181,7 +178,6 @@ # Since: 1.4 # ## - { 'struct': 'ImageCheck', 'data': {'filename': 'str', 'format': 'str', 'check-errors': 'int', '*image-end-offset': 'int', '*corruptions': 'int', '*leaks': 'int', @@ -217,7 +213,7 @@ '*filename': 'str' } } ## -# @BlockdevCacheInfo +# @BlockdevCacheInfo: # # Cache mode information for a block device # @@ -247,11 +243,12 @@ # 0.14.0 this can be: 'blkdebug', 'bochs', 'cloop', 'cow', 'dmg', # 'file', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device', # 'http', 'https', 'luks', 'nbd', 'parallels', 'qcow', -# 'qcow2', 'raw', 'tftp', 'vdi', 'vmdk', 'vpc', 'vvfat' +# 'qcow2', 'raw', 'vdi', 'vmdk', 'vpc', 'vvfat' # 2.2: 'archipelago' added, 'cow' dropped # 2.3: 'host_floppy' deprecated # 2.5: 'host_floppy' dropped # 2.6: 'luks' added +# 2.8: 'replication' added, 'tftp' dropped # # @backing_file: #optional the name of the backing file (for copy-on-write) # @@ -381,7 +378,7 @@ # @offset: if present, the image file stores the data for this range in # raw format at the given offset. # -# Since 1.7 +# Since: 1.7 ## { 'struct': 'BlockDeviceMapEntry', 'data': { 'start': 'int', 'length': 'int', 'depth': 'int', 'zero': 'bool', @@ -517,7 +514,6 @@ # # Since: 2.5 ## - { 'struct': 'BlockDeviceTimedStats', 'data': { 'interval_length': 'int', 'min_rd_latency_ns': 'int', 'max_rd_latency_ns': 'int', 'avg_rd_latency_ns': 'int', @@ -794,7 +790,7 @@ '*node-name': 'str', 'password': 'str'} } ## -# @block_resize +# @block_resize: # # Resize a block image while a guest is running. # @@ -816,7 +812,7 @@ 'size': 'int' }} ## -# @NewImageMode +# @NewImageMode: # # An enumeration that tells QEMU how to set the backing file path in # a new image file. @@ -833,7 +829,7 @@ 'data': [ 'existing', 'absolute-paths' ] } ## -# @BlockdevSnapshotSync +# @BlockdevSnapshotSync: # # Either @device or @node-name must be set but not both. # @@ -856,7 +852,7 @@ '*format': 'str', '*mode': 'NewImageMode' } } ## -# @BlockdevSnapshot +# @BlockdevSnapshot: # # @node: device or node name that will have a snapshot created. # @@ -865,18 +861,18 @@ # It must not have a current backing file (this can be # achieved by passing "backing": "" to blockdev-add). # -# Since 2.5 +# Since: 2.5 ## { 'struct': 'BlockdevSnapshot', 'data': { 'node': 'str', 'overlay': 'str' } } ## -# @DriveBackup +# @DriveBackup: # # @job-id: #optional identifier for the newly-created block job. If # omitted, the device name will be used. (Since 2.7) # -# @device: the name of the device which should be copied. +# @device: the device name or node-name of a root node which should be copied. # # @target: the target of the new image. If the file exists, or if it # is a device, the existing file/device will be used as the new @@ -898,6 +894,9 @@ # Must be present if sync is "incremental", must NOT be present # otherwise. (Since 2.4) # +# @compress: #optional true to compress data, if the target format supports it. +# (default: false) (since 2.8) +# # @on-source-error: #optional the action to take on an error on the source, # default 'report'. 'stop' and 'enospc' can only be used # if the block device supports io-status (see BlockInfo). @@ -906,26 +905,26 @@ # default 'report' (no limitations, since this applies to # a different block device than @device). # -# Note that @on-source-error and @on-target-error only affect background I/O. -# If an error occurs during a guest write request, the device's rerror/werror -# actions will be used. +# Note: @on-source-error and @on-target-error only affect background +# I/O. If an error occurs during a guest write request, the device's +# rerror/werror actions will be used. # # Since: 1.6 ## { 'struct': 'DriveBackup', 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', '*format': 'str', 'sync': 'MirrorSyncMode', '*mode': 'NewImageMode', - '*speed': 'int', '*bitmap': 'str', + '*speed': 'int', '*bitmap': 'str', '*compress': 'bool', '*on-source-error': 'BlockdevOnError', '*on-target-error': 'BlockdevOnError' } } ## -# @BlockdevBackup +# @BlockdevBackup: # # @job-id: #optional identifier for the newly-created block job. If # omitted, the device name will be used. (Since 2.7) # -# @device: the name of the device which should be copied. +# @device: the device name or node-name of a root node which should be copied. # # @target: the device name or node-name of the backup target node. # @@ -936,6 +935,9 @@ # @speed: #optional the maximum speed, in bytes per second. The default is 0, # for unlimited. # +# @compress: #optional true to compress data, if the target format supports it. +# (default: false) (since 2.8) +# # @on-source-error: #optional the action to take on an error on the source, # default 'report'. 'stop' and 'enospc' can only be used # if the block device supports io-status (see BlockInfo). @@ -944,9 +946,9 @@ # default 'report' (no limitations, since this applies to # a different block device than @device). # -# Note that @on-source-error and @on-target-error only affect background I/O. -# If an error occurs during a guest write request, the device's rerror/werror -# actions will be used. +# Note: @on-source-error and @on-target-error only affect background +# I/O. If an error occurs during a guest write request, the device's +# rerror/werror actions will be used. # # Since: 2.3 ## @@ -954,11 +956,12 @@ 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', 'sync': 'MirrorSyncMode', '*speed': 'int', + '*compress': 'bool', '*on-source-error': 'BlockdevOnError', '*on-target-error': 'BlockdevOnError' } } ## -# @blockdev-snapshot-sync +# @blockdev-snapshot-sync: # # Generates a synchronous snapshot of a block device. # @@ -967,26 +970,26 @@ # Returns: nothing on success # If @device is not a valid block device, DeviceNotFound # -# Since 0.14.0 +# Since: 0.14.0 ## { 'command': 'blockdev-snapshot-sync', 'data': 'BlockdevSnapshotSync' } ## -# @blockdev-snapshot +# @blockdev-snapshot: # # Generates a snapshot of a block device. # # For the arguments, see the documentation of BlockdevSnapshot. # -# Since 2.5 +# Since: 2.5 ## { 'command': 'blockdev-snapshot', 'data': 'BlockdevSnapshot' } ## -# @change-backing-file +# @change-backing-file: # # Change the backing file in the image file metadata. This does not # cause QEMU to reopen the image file to reparse the backing filename @@ -998,7 +1001,8 @@ # @image-node-name: The name of the block driver state node of the # image to modify. # -# @device: The name of the device that owns image-node-name. +# @device: The device name or node-name of the root node that owns +# image-node-name. # # @backing-file: The string to write as the backing file. This # string is not validated, so care should be taken @@ -1012,7 +1016,7 @@ 'backing-file': 'str' } } ## -# @block-commit +# @block-commit: # # Live commit of data from overlay image nodes into backing nodes - i.e., # writes data between 'top' and 'base' into 'base'. @@ -1020,7 +1024,7 @@ # @job-id: #optional identifier for the newly-created block job. If # omitted, the device name will be used. (Since 2.7) # -# @device: the name of the device +# @device: the device name or node-name of a root node # # @base: #optional The file name of the backing image to write data into. # If not specified, this is the deepest backing image @@ -1075,7 +1079,7 @@ '*backing-file': 'str', '*speed': 'int' } } ## -# @drive-backup +# @drive-backup: # # Start a point-in-time copy of a block device to a new destination. The # status of ongoing drive-backup operations can be checked with @@ -1086,14 +1090,15 @@ # For the arguments, see the documentation of DriveBackup. # # Returns: nothing on success -# If @device is not a valid block device, DeviceNotFound +# If @device is not a valid block device, GenericError # -# Since 1.6 +# Since: 1.6 ## -{ 'command': 'drive-backup', 'data': 'DriveBackup' } +{ 'command': 'drive-backup', 'boxed': true, + 'data': 'DriveBackup' } ## -# @blockdev-backup +# @blockdev-backup: # # Start a point-in-time copy of a block device to a new destination. The # status of ongoing blockdev-backup operations can be checked with @@ -1103,46 +1108,51 @@ # # For the arguments, see the documentation of BlockdevBackup. # -# Since 2.3 +# Returns: nothing on success +# If @device is not a valid block device, DeviceNotFound +# +# Since: 2.3 ## -{ 'command': 'blockdev-backup', 'data': 'BlockdevBackup' } +{ 'command': 'blockdev-backup', 'boxed': true, + 'data': 'BlockdevBackup' } ## -# @query-named-block-nodes +# @query-named-block-nodes: # # Get the named block driver list # # Returns: the list of BlockDeviceInfo # -# Since 2.0 +# Since: 2.0 ## { 'command': 'query-named-block-nodes', 'returns': [ 'BlockDeviceInfo' ] } ## -# @drive-mirror +# @drive-mirror: # # Start mirroring a block device's writes to a new destination. # # See DriveMirror for parameter descriptions # # Returns: nothing on success -# If @device is not a valid block device, DeviceNotFound +# If @device is not a valid block device, GenericError # -# Since 1.3 +# Since: 1.3 ## { 'command': 'drive-mirror', 'boxed': true, 'data': 'DriveMirror' } ## -# DriveMirror +# @DriveMirror: # # A set of parameters describing drive mirror setup. # # @job-id: #optional identifier for the newly-created block job. If # omitted, the device name will be used. (Since 2.7) # -# @device: the name of the device whose writes should be mirrored. +# @device: the device name or node-name of a root node whose writes should be +# mirrored. # # @target: the target of the new image. If the file exists, or if it # is a device, the existing file/device will be used as the new @@ -1188,7 +1198,7 @@ # written. Both will result in identical contents. # Default is true. (Since 2.4) # -# Since 1.3 +# Since: 1.3 ## { 'struct': 'DriveMirror', 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', @@ -1200,19 +1210,19 @@ '*unmap': 'bool' } } ## -# @BlockDirtyBitmap +# @BlockDirtyBitmap: # # @node: name of device/node which the bitmap is tracking # # @name: name of the dirty bitmap # -# Since 2.4 +# Since: 2.4 ## { 'struct': 'BlockDirtyBitmap', 'data': { 'node': 'str', 'name': 'str' } } ## -# @BlockDirtyBitmapAdd +# @BlockDirtyBitmapAdd: # # @node: name of device/node which the bitmap is tracking # @@ -1221,13 +1231,13 @@ # @granularity: #optional the bitmap granularity, default is 64k for # block-dirty-bitmap-add # -# Since 2.4 +# Since: 2.4 ## { 'struct': 'BlockDirtyBitmapAdd', 'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32' } } ## -# @block-dirty-bitmap-add +# @block-dirty-bitmap-add: # # Create a dirty bitmap with a name on the node # @@ -1235,13 +1245,13 @@ # If @node is not a valid block device or node, DeviceNotFound # If @name is already taken, GenericError with an explanation # -# Since 2.4 +# Since: 2.4 ## { 'command': 'block-dirty-bitmap-add', 'data': 'BlockDirtyBitmapAdd' } ## -# @block-dirty-bitmap-remove +# @block-dirty-bitmap-remove: # # Remove a dirty bitmap on the node # @@ -1250,13 +1260,13 @@ # If @name is not found, GenericError with an explanation # if @name is frozen by an operation, GenericError # -# Since 2.4 +# Since: 2.4 ## { 'command': 'block-dirty-bitmap-remove', 'data': 'BlockDirtyBitmap' } ## -# @block-dirty-bitmap-clear +# @block-dirty-bitmap-clear: # # Clear (reset) a dirty bitmap on the device # @@ -1264,20 +1274,21 @@ # If @node is not a valid block device, DeviceNotFound # If @name is not found, GenericError with an explanation # -# Since 2.4 +# Since: 2.4 ## { 'command': 'block-dirty-bitmap-clear', 'data': 'BlockDirtyBitmap' } ## -# @blockdev-mirror +# @blockdev-mirror: # # Start mirroring a block device's writes to a new destination. # # @job-id: #optional identifier for the newly-created block job. If # omitted, the device name will be used. (Since 2.7) # -# @device: the name of the device whose writes should be mirrored. +# @device: The device name or node-name of a root node whose writes should be +# mirrored. # # @target: the id or node-name of the block device to mirror to. This mustn't be # attached to guest. @@ -1310,7 +1321,7 @@ # # Returns: nothing on success. # -# Since 2.6 +# Since: 2.6 ## { 'command': 'blockdev-mirror', 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', @@ -1357,11 +1368,13 @@ 'data': 'BlockIOThrottle' } ## -# BlockIOThrottle +# @BlockIOThrottle: # # A set of parameters describing block throttling. # -# @device: The name of the device +# @device: #optional Block device name (deprecated, use @id instead) +# +# @id: #optional The name or QOM path of the guest device (since: 2.8) # # @bps: total throughput limit in bytes per second # @@ -1430,8 +1443,8 @@ # Since: 1.1 ## { 'struct': 'BlockIOThrottle', - 'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int', - 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int', + 'data': { '*device': 'str', '*id': 'str', 'bps': 'int', 'bps_rd': 'int', + 'bps_wr': 'int', 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int', '*bps_max': 'int', '*bps_rd_max': 'int', '*bps_wr_max': 'int', '*iops_max': 'int', '*iops_rd_max': 'int', '*iops_wr_max': 'int', @@ -1451,6 +1464,13 @@ # with query-block-jobs. The operation can be stopped before it has completed # using the block-job-cancel command. # +# The node that receives the data is called the top image, can be located in +# any part of the chain (but always above the base image; see below) and can be +# specified using its device or node name. Earlier qemu versions only allowed +# 'device' to name the top level node; presence of the 'base-node' parameter +# during introspection can be used as a witness of the enhanced semantics +# of 'device'. +# # If a base file is specified then sectors are not copied from that base file and # its backing chain. When streaming completes the image file will have the base # file as its backing file. This can be used to stream a subset of the backing @@ -1462,12 +1482,16 @@ # @job-id: #optional identifier for the newly-created block job. If # omitted, the device name will be used. (Since 2.7) # -# @device: the device name +# @device: the device or node name of the top image +# +# @base: #optional the common backing file name. +# It cannot be set if @base-node is also set. # -# @base: #optional the common backing file name +# @base-node: #optional the node name of the backing file. +# It cannot be set if @base is also set. (Since 2.8) # -# @backing-file: #optional The backing file string to write into the active -# layer. This filename is not validated. +# @backing-file: #optional The backing file string to write into the top +# image. This filename is not validated. # # If a pathname string is such that it cannot be # resolved by QEMU, that means that subsequent QMP or @@ -1487,14 +1511,11 @@ # 'stop' and 'enospc' can only be used if the block device # supports io-status (see BlockInfo). Since 1.3. # -# Returns: Nothing on success -# If @device does not exist, DeviceNotFound -# # Since: 1.1 ## { 'command': 'block-stream', 'data': { '*job-id': 'str', 'device': 'str', '*base': 'str', - '*backing-file': 'str', '*speed': 'int', + '*base-node': 'str', '*backing-file': 'str', '*speed': 'int', '*on-error': 'BlockdevOnError' } } ## @@ -1629,7 +1650,7 @@ { 'command': 'block-job-complete', 'data': { 'device': 'str' } } ## -# @BlockdevDiscardOptions +# @BlockdevDiscardOptions: # # Determines how to handle discard requests. # @@ -1642,7 +1663,7 @@ 'data': [ 'ignore', 'unmap' ] } ## -# @BlockdevDetectZeroesOptions +# @BlockdevDetectZeroesOptions: # # Describes the operation mode for the automatic conversion of plain # zero writes by the OS to driver specific optimized zero write commands. @@ -1658,7 +1679,7 @@ 'data': [ 'off', 'on', 'unmap' ] } ## -# @BlockdevAioOptions +# @BlockdevAioOptions: # # Selects the AIO backend to handle I/O requests # @@ -1671,7 +1692,7 @@ 'data': [ 'threads', 'native' ] } ## -# @BlockdevCacheOptions +# @BlockdevCacheOptions: # # Includes cache-related options for block devices # @@ -1687,37 +1708,44 @@ '*no-flush': 'bool' } } ## -# @BlockdevDriver +# @BlockdevDriver: # # Drivers that are supported in block device operations. # -# @host_device, @host_cdrom: Since 2.1 +# @host_device: Since 2.1 +# @host_cdrom: Since 2.1 # @gluster: Since 2.7 +# @nbd: Since 2.8 +# @nfs: Since 2.8 +# @replication: Since 2.8 +# @ssh: Since 2.8 # # Since: 2.0 ## { 'enum': 'BlockdevDriver', 'data': [ 'archipelago', 'blkdebug', 'blkverify', 'bochs', 'cloop', 'dmg', 'file', 'ftp', 'ftps', 'gluster', 'host_cdrom', - 'host_device', 'http', 'https', 'luks', 'null-aio', 'null-co', - 'parallels', 'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'tftp', - 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] } + 'host_device', 'http', 'https', 'luks', 'nbd', 'nfs', 'null-aio', + 'null-co', 'parallels', 'qcow', 'qcow2', 'qed', 'quorum', 'raw', + 'replication', 'ssh', 'vdi', 'vhdx', 'vmdk', 'vpc', + 'vvfat' ] } ## -# @BlockdevOptionsFile +# @BlockdevOptionsFile: # -# Driver specific block device options for the file backend and similar -# protocols. +# Driver specific block device options for the file backend. # # @filename: path to the image file +# @aio: #optional AIO backend (default: threads) (since: 2.8) # # Since: 1.7 ## { 'struct': 'BlockdevOptionsFile', - 'data': { 'filename': 'str' } } + 'data': { 'filename': 'str', + '*aio': 'BlockdevAioOptions' } } ## -# @BlockdevOptionsNull +# @BlockdevOptionsNull: # # Driver specific block device options for the null backend. # @@ -1732,7 +1760,7 @@ 'data': { '*size': 'int', '*latency-ns': 'uint64' } } ## -# @BlockdevOptionsVVFAT +# @BlockdevOptionsVVFAT: # # Driver specific block device options for the vvfat protocol. # @@ -1753,7 +1781,7 @@ '*label': 'str', '*rw': 'bool' } } ## -# @BlockdevOptionsGenericFormat +# @BlockdevOptionsGenericFormat: # # Driver specific block device options for image format that have no option # besides their data source. @@ -1766,7 +1794,7 @@ 'data': { 'file': 'BlockdevRef' } } ## -# @BlockdevOptionsLUKS +# @BlockdevOptionsLUKS: # # Driver specific block device options for LUKS. # @@ -1782,7 +1810,7 @@ ## -# @BlockdevOptionsGenericCOWFormat +# @BlockdevOptionsGenericCOWFormat: # # Driver specific block device options for image format that have no option # besides their data source and an optional backing file. @@ -1799,7 +1827,7 @@ 'data': { '*backing': 'BlockdevRef' } } ## -# @Qcow2OverlapCheckMode +# @Qcow2OverlapCheckMode: # # General overlap check modes. # @@ -1819,7 +1847,7 @@ 'data': [ 'none', 'constant', 'cached', 'all' ] } ## -# @Qcow2OverlapCheckFlags +# @Qcow2OverlapCheckFlags: # # Structure of flags for each metadata structure. Setting a field to 'true' # makes qemu guard that structure against unintended overwriting. The default @@ -1842,7 +1870,7 @@ '*inactive-l2': 'bool' } } ## -# @Qcow2OverlapChecks +# @Qcow2OverlapChecks: # # Specifies which metadata structures should be guarded against unintended # overwriting. @@ -1859,7 +1887,7 @@ 'mode': 'Qcow2OverlapCheckMode' } } ## -# @BlockdevOptionsQcow2 +# @BlockdevOptionsQcow2: # # Driver specific block device options for qcow2. # @@ -1909,7 +1937,7 @@ ## -# @BlockdevOptionsArchipelago +# @BlockdevOptionsArchipelago: # # Driver specific block device options for Archipelago. # @@ -1937,9 +1965,28 @@ '*vport': 'int', '*segment': 'str' } } +## +# @BlockdevOptionsSsh: +# +# @server: host address +# +# @path: path to the image on the host +# +# @user: #optional user as which to connect, defaults to current +# local user name +# +# TODO: Expose the host_key_check option in QMP +# +# Since: 2.8 +## +{ 'struct': 'BlockdevOptionsSsh', + 'data': { 'server': 'InetSocketAddress', + 'path': 'str', + '*user': 'str' } } + ## -# @BlkdebugEvent +# @BlkdebugEvent: # # Trigger events supported by blkdebug. # @@ -1962,7 +2009,7 @@ 'pwritev_zero', 'pwritev_done', 'empty_image_prepare' ] } ## -# @BlkdebugInjectErrorOptions +# @BlkdebugInjectErrorOptions: # # Describes a single error injection for blkdebug. # @@ -1994,7 +2041,7 @@ '*immediately': 'bool' } } ## -# @BlkdebugSetStateOptions +# @BlkdebugSetStateOptions: # # Describes a single state-change event for blkdebug. # @@ -2014,7 +2061,7 @@ 'new_state': 'int' } } ## -# @BlockdevOptionsBlkdebug +# @BlockdevOptionsBlkdebug: # # Driver specific block device options for blkdebug. # @@ -2039,7 +2086,7 @@ '*set-state': ['BlkdebugSetStateOptions'] } } ## -# @BlockdevOptionsBlkverify +# @BlockdevOptionsBlkverify: # # Driver specific block device options for blkverify. # @@ -2054,7 +2101,7 @@ 'raw': 'BlockdevRef' } } ## -# @QuorumReadPattern +# @QuorumReadPattern: # # An enumeration of quorum read patterns. # @@ -2067,7 +2114,7 @@ { 'enum': 'QuorumReadPattern', 'data': [ 'quorum', 'fifo' ] } ## -# @BlockdevOptionsQuorum +# @BlockdevOptionsQuorum: # # Driver specific block device options for Quorum # @@ -2094,7 +2141,7 @@ '*read-pattern': 'QuorumReadPattern' } } ## -# @GlusterTransport +# @GlusterTransport: # # An enumeration of Gluster transport types # @@ -2109,7 +2156,7 @@ ## -# @GlusterServer +# @GlusterServer: # # Captures the address of a socket # @@ -2117,9 +2164,17 @@ # # @type: Transport type used for gluster connection # -# @unix: socket file +# This is similar to SocketAddress, only distinction: +# +# 1. GlusterServer is a flat union, SocketAddress is a simple union. +# A flat union is nicer than simple because it avoids nesting +# (i.e. more {}) on the wire. +# +# 2. GlusterServer lacks case 'fd', since gluster doesn't let you +# pass in a file descriptor. # -# @tcp: host address and port number +# GlusterServer is actually not Gluster-specific, its a +# compatibility evolved into an alternate for SocketAddress. # # Since: 2.7 ## @@ -2130,7 +2185,7 @@ 'tcp': 'InetSocketAddress' } } ## -# @BlockdevOptionsGluster +# @BlockdevOptionsGluster: # # Driver specific block device options for Gluster # @@ -2140,7 +2195,10 @@ # # @server: gluster servers description # -# @debug-level: #optional libgfapi log level (default '4' which is Error) +# @debug: #optional libgfapi log level (default '4' which is Error) +# (Since 2.8) +# +# @logfile: #optional libgfapi log file (default /dev/stderr) (Since 2.8) # # Since: 2.7 ## @@ -2148,25 +2206,163 @@ 'data': { 'volume': 'str', 'path': 'str', 'server': ['GlusterServer'], - '*debug-level': 'int' } } + '*debug': 'int', + '*logfile': 'str' } } + +## +# @ReplicationMode: +# +# An enumeration of replication modes. +# +# @primary: Primary mode, the vm's state will be sent to secondary QEMU. +# +# @secondary: Secondary mode, receive the vm's state from primary QEMU. +# +# Since: 2.8 +## +{ 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ] } + +## +# @BlockdevOptionsReplication: +# +# Driver specific block device options for replication +# +# @mode: the replication mode +# +# @top-id: #optional In secondary mode, node name or device ID of the root +# node who owns the replication node chain. Must not be given in +# primary mode. +# +# Since: 2.8 +## +{ 'struct': 'BlockdevOptionsReplication', + 'base': 'BlockdevOptionsGenericFormat', + 'data': { 'mode': 'ReplicationMode', + '*top-id': 'str' } } + +## +# @NFSTransport: +# +# An enumeration of NFS transport types +# +# @inet: TCP transport +# +# Since: 2.8 +## +{ 'enum': 'NFSTransport', + 'data': [ 'inet' ] } + +## +# @NFSServer: +# +# Captures the address of the socket +# +# @type: transport type used for NFS (only TCP supported) +# +# @host: host address for NFS server +# +# Since: 2.8 +## +{ 'struct': 'NFSServer', + 'data': { 'type': 'NFSTransport', + 'host': 'str' } } + +## +# @BlockdevOptionsNfs: +# +# Driver specific block device option for NFS +# +# @server: host address +# +# @path: path of the image on the host +# +# @user: #optional UID value to use when talking to the +# server (defaults to 65534 on Windows and getuid() +# on unix) +# +# @group: #optional GID value to use when talking to the +# server (defaults to 65534 on Windows and getgid() +# in unix) +# +# @tcp-syn-count: #optional number of SYNs during the session +# establishment (defaults to libnfs default) +# +# @readahead-size: #optional set the readahead size in bytes (defaults +# to libnfs default) +# +# @page-cache-size: #optional set the pagecache size in bytes (defaults +# to libnfs default) +# +# @debug: #optional set the NFS debug level (max 2) (defaults +# to libnfs default) +# +# Since: 2.8 +## +{ 'struct': 'BlockdevOptionsNfs', + 'data': { 'server': 'NFSServer', + 'path': 'str', + '*user': 'int', + '*group': 'int', + '*tcp-syn-count': 'int', + '*readahead-size': 'int', + '*page-cache-size': 'int', + '*debug': 'int' } } + +## +# @BlockdevOptionsCurl: +# +# Driver specific block device options for the curl backend. +# +# @filename: path to the image file +# +# Since: 1.7 +## +{ 'struct': 'BlockdevOptionsCurl', + 'data': { 'filename': 'str' } } + +## +# @BlockdevOptionsNbd: +# +# Driver specific block device options for NBD. +# +# @server: NBD server address +# +# @export: #optional export name +# +# @tls-creds: #optional TLS credentials ID +# +# Since: 2.8 +## +{ 'struct': 'BlockdevOptionsNbd', + 'data': { 'server': 'SocketAddress', + '*export': 'str', + '*tls-creds': 'str' } } ## -# @BlockdevOptions +# @BlockdevOptionsRaw: +# +# Driver specific block device options for the raw driver. +# +# @offset: #optional position where the block device starts +# @size: #optional the assumed size of the device +# +# Since: 2.8 +## +{ 'struct': 'BlockdevOptionsRaw', + 'base': 'BlockdevOptionsGenericFormat', + 'data': { '*offset': 'int', '*size': 'int' } } + +## +# @BlockdevOptions: # # Options for creating a block device. Many options are available for all # block devices, independent of the block driver: # # @driver: block driver name -# @id: #optional id by which the new block device can be referred to. -# This option is only allowed on the top level of blockdev-add. -# A BlockBackend will be created by blockdev-add if and only if -# this option is given. -# @node-name: #optional the name of a block driver state node (Since 2.0). -# This option is required on the top level of blockdev-add if -# the @id option is not given there. +# @node-name: #optional the node name of the new node (Since 2.0). +# This option is required on the top level of blockdev-add. # @discard: #optional discard-related options (default: ignore) # @cache: #optional cache-related options -# @aio: #optional AIO backend (default: threads) # @read-only: #optional whether the block device should be read-only # (default: false) # @detect-zeroes: #optional detect and optimize zero writes (Since 2.1) @@ -2178,12 +2374,9 @@ ## { 'union': 'BlockdevOptions', 'base': { 'driver': 'BlockdevDriver', -# TODO 'id' is a BB-level option, remove it - '*id': 'str', '*node-name': 'str', '*discard': 'BlockdevDiscardOptions', '*cache': 'BlockdevCacheOptions', - '*aio': 'BlockdevAioOptions', '*read-only': 'bool', '*detect-zeroes': 'BlockdevDetectZeroesOptions' }, 'discriminator': 'driver', @@ -2195,17 +2388,17 @@ 'cloop': 'BlockdevOptionsGenericFormat', 'dmg': 'BlockdevOptionsGenericFormat', 'file': 'BlockdevOptionsFile', - 'ftp': 'BlockdevOptionsFile', - 'ftps': 'BlockdevOptionsFile', + 'ftp': 'BlockdevOptionsCurl', + 'ftps': 'BlockdevOptionsCurl', 'gluster': 'BlockdevOptionsGluster', 'host_cdrom': 'BlockdevOptionsFile', 'host_device':'BlockdevOptionsFile', - 'http': 'BlockdevOptionsFile', - 'https': 'BlockdevOptionsFile', + 'http': 'BlockdevOptionsCurl', + 'https': 'BlockdevOptionsCurl', # TODO iscsi: Wait for structured options 'luks': 'BlockdevOptionsLUKS', -# TODO nbd: Should take InetSocketAddress for 'host'? -# TODO nfs: Wait for structured options + 'nbd': 'BlockdevOptionsNbd', + 'nfs': 'BlockdevOptionsNfs', 'null-aio': 'BlockdevOptionsNull', 'null-co': 'BlockdevOptionsNull', 'parallels': 'BlockdevOptionsGenericFormat', @@ -2213,11 +2406,11 @@ 'qcow': 'BlockdevOptionsGenericCOWFormat', 'qed': 'BlockdevOptionsGenericCOWFormat', 'quorum': 'BlockdevOptionsQuorum', - 'raw': 'BlockdevOptionsGenericFormat', + 'raw': 'BlockdevOptionsRaw', # TODO rbd: Wait for structured options + 'replication':'BlockdevOptionsReplication', # TODO sheepdog: Wait for structured options -# TODO ssh: Should take InetSocketAddress for 'host'? - 'tftp': 'BlockdevOptionsFile', + 'ssh': 'BlockdevOptionsSsh', 'vdi': 'BlockdevOptionsGenericFormat', 'vhdx': 'BlockdevOptionsGenericFormat', 'vmdk': 'BlockdevOptionsGenericCOWFormat', @@ -2226,7 +2419,7 @@ } } ## -# @BlockdevRef +# @BlockdevRef: # # Reference to a block device. # @@ -2252,39 +2445,28 @@ # block drivers among other things. Stay away from it unless you want # to help with its development. # -# @options: block device options for the new device +# For the arguments, see the documentation of BlockdevOptions. # # Since: 1.7 ## -{ 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } } +{ 'command': 'blockdev-add', 'data': 'BlockdevOptions', 'boxed': true } ## # @x-blockdev-del: # # Deletes a block device that has been added using blockdev-add. -# The selected device can be either a block backend or a graph node. -# -# In the former case the backend will be destroyed, along with its -# inserted medium if there's any. The command will fail if the backend -# or its medium are in use. -# -# In the latter case the node will be destroyed. The command will fail -# if the node is attached to a block backend or is otherwise being -# used. -# -# One of @id or @node-name must be specified, but not both. +# The command will fail if the node is attached to a device or is +# otherwise being used. # # This command is still a work in progress and is considered # experimental. Stay away from it unless you want to help with its # development. # -# @id: #optional Name of the block backend device to delete. -# -# @node-name: #optional Name of the graph node to delete. +# @node-name: Name of the graph node to delete. # # Since: 2.5 ## -{ 'command': 'x-blockdev-del', 'data': { '*id': 'str', '*node-name': 'str' } } +{ 'command': 'x-blockdev-del', 'data': { 'node-name': 'str' } } ## # @blockdev-open-tray: @@ -2304,7 +2486,9 @@ # to it # - if the guest device does not have an actual tray # -# @device: block device name +# @device: #optional Block device name (deprecated, use @id instead) +# +# @id: #optional The name or QOM path of the guest device (since: 2.8) # # @force: #optional if false (the default), an eject request will be sent to # the guest if it has locked the tray (and the tray will not be opened @@ -2314,7 +2498,8 @@ # Since: 2.5 ## { 'command': 'blockdev-open-tray', - 'data': { 'device': 'str', + 'data': { '*device': 'str', + '*id': 'str', '*force': 'bool' } } ## @@ -2326,12 +2511,15 @@ # # If the tray was already closed before, this will be a no-op. # -# @device: block device name +# @device: #optional Block device name (deprecated, use @id instead) +# +# @id: #optional The name or QOM path of the guest device (since: 2.8) # # Since: 2.5 ## { 'command': 'blockdev-close-tray', - 'data': { 'device': 'str' } } + 'data': { '*device': 'str', + '*id': 'str' } } ## # @x-blockdev-remove-medium: @@ -2345,12 +2533,15 @@ # This command is still a work in progress and is considered experimental. # Stay away from it unless you want to help with its development. # -# @device: block device name +# @device: #optional Block device name (deprecated, use @id instead) +# +# @id: #optional The name or QOM path of the guest device (since: 2.8) # # Since: 2.5 ## { 'command': 'x-blockdev-remove-medium', - 'data': { 'device': 'str' } } + 'data': { '*device': 'str', + '*id': 'str' } } ## # @x-blockdev-insert-medium: @@ -2362,14 +2553,17 @@ # This command is still a work in progress and is considered experimental. # Stay away from it unless you want to help with its development. # -# @device: block device name +# @device: #optional Block device name (deprecated, use @id instead) +# +# @id: #optional The name or QOM path of the guest device (since: 2.8) # # @node-name: name of a node in the block driver state graph # # Since: 2.5 ## { 'command': 'x-blockdev-insert-medium', - 'data': { 'device': 'str', + 'data': { '*device': 'str', + '*id': 'str', 'node-name': 'str'} } @@ -2399,7 +2593,10 @@ # combines blockdev-open-tray, x-blockdev-remove-medium, # x-blockdev-insert-medium and blockdev-close-tray). # -# @device: block device name +# @device: #optional Block device name (deprecated, use @id instead) +# +# @id: #optional The name or QOM path of the guest device +# (since: 2.8) # # @filename: filename of the new image to be loaded # @@ -2412,14 +2609,15 @@ # Since: 2.5 ## { 'command': 'blockdev-change-medium', - 'data': { 'device': 'str', + 'data': { '*device': 'str', + '*id': 'str', 'filename': 'str', '*format': 'str', '*read-only-mode': 'BlockdevChangeReadOnlyMode' } } ## -# @BlockErrorAction +# @BlockErrorAction: # # An enumeration of action that has been taken when a DISK I/O occurs # @@ -2436,7 +2634,7 @@ ## -# @BLOCK_IMAGE_CORRUPTED +# @BLOCK_IMAGE_CORRUPTED: # # Emitted when a corruption has been detected in a disk image # @@ -2471,11 +2669,17 @@ 'fatal' : 'bool' } } ## -# @BLOCK_IO_ERROR +# @BLOCK_IO_ERROR: # # Emitted when a disk I/O error occurs # -# @device: device name +# @device: device name. This is always present for compatibility +# reasons, but it can be empty ("") if the image does not +# have a device name associated. +# +# @node-name: node name. Note that errors may be reported for the root node +# that is directly attached to a guest device rather than for the +# node where the error occurred. (Since: 2.8) # # @operation: I/O operation # @@ -2496,12 +2700,12 @@ # Since: 0.13.0 ## { 'event': 'BLOCK_IO_ERROR', - 'data': { 'device': 'str', 'operation': 'IoOperationType', + 'data': { 'device': 'str', 'node-name': 'str', 'operation': 'IoOperationType', 'action': 'BlockErrorAction', '*nospace': 'bool', 'reason': 'str' } } ## -# @BLOCK_JOB_COMPLETED +# @BLOCK_JOB_COMPLETED: # # Emitted when a block job has completed # @@ -2533,7 +2737,7 @@ '*error': 'str' } } ## -# @BLOCK_JOB_CANCELLED +# @BLOCK_JOB_CANCELLED: # # Emitted when a block job has been cancelled # @@ -2559,7 +2763,7 @@ 'speed' : 'int' } } ## -# @BLOCK_JOB_ERROR +# @BLOCK_JOB_ERROR: # # Emitted when a block job encounters an error # @@ -2578,7 +2782,7 @@ 'action' : 'BlockErrorAction' } } ## -# @BLOCK_JOB_READY +# @BLOCK_JOB_READY: # # Emitted when a block job is ready to complete # @@ -2606,7 +2810,8 @@ 'offset': 'int', 'speed' : 'int' } } -# @PreallocMode +## +# @PreallocMode: # # Preallocation mode of QEMU image file # @@ -2618,13 +2823,13 @@ # space is really available. @full preallocation also sets up # metadata correctly. # -# Since 2.2 +# Since: 2.2 ## { 'enum': 'PreallocMode', 'data': [ 'off', 'metadata', 'falloc', 'full' ] } ## -# @BLOCK_WRITE_THRESHOLD +# @BLOCK_WRITE_THRESHOLD: # # Emitted when writes on block device reaches or exceeds the # configured write threshold. For thin-provisioned devices, this @@ -2647,7 +2852,7 @@ 'write-threshold': 'uint64' } } ## -# @block-set-write-threshold +# @block-set-write-threshold: # # Change the write threshold for a block drive. An event will be delivered # if a write to this block drive crosses the configured threshold. @@ -2665,7 +2870,7 @@ 'data': { 'node-name': 'str', 'write-threshold': 'uint64' } } ## -# @x-blockdev-change +# @x-blockdev-change: # # Dynamically reconfigure the block driver state graph. It can be used # to add, remove, insert or replace a graph node. Currently only the diff --git a/qapi/block.json b/qapi/block.json index 937337dce5..8e9f59019a 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -40,7 +40,7 @@ 'data': ['auto', 'none', 'lba', 'large', 'rechs']} ## -# @FloppyDriveType +# @FloppyDriveType: # # Type of Floppy drive to be emulated by the Floppy Disk Controller. # @@ -56,9 +56,10 @@ 'data': ['144', '288', '120', 'none', 'auto']} ## -# @BlockdevSnapshotInternal +# @BlockdevSnapshotInternal: # -# @device: the name of the device to generate the snapshot from +# @device: the device name or node-name of a root node to generate the snapshot +# from # # @name: the name of the internal snapshot to be created # @@ -72,7 +73,7 @@ 'data': { 'device': 'str', 'name': 'str' } } ## -# @blockdev-snapshot-internal-sync +# @blockdev-snapshot-internal-sync: # # Synchronously take an internal snapshot of a block device, when the format # of the image used supports it. @@ -80,39 +81,40 @@ # For the arguments, see the documentation of BlockdevSnapshotInternal. # # Returns: nothing on success -# If @device is not a valid block device, DeviceNotFound +# If @device is not a valid block device, GenericError # If any snapshot matching @name exists, or @name is empty, # GenericError # If the format of the image used does not support it, # BlockFormatFeatureNotSupported # -# Since 1.7 +# Since: 1.7 ## { 'command': 'blockdev-snapshot-internal-sync', 'data': 'BlockdevSnapshotInternal' } ## -# @blockdev-snapshot-delete-internal-sync +# @blockdev-snapshot-delete-internal-sync: # # Synchronously delete an internal snapshot of a block device, when the format # of the image used support it. The snapshot is identified by name or id or # both. One of the name or id is required. Return SnapshotInfo for the # successfully deleted snapshot. # -# @device: the name of the device to delete the snapshot from +# @device: the device name or node-name of a root node to delete the snapshot +# from # # @id: optional the snapshot's ID to be deleted # # @name: optional the snapshot's name to be deleted # # Returns: SnapshotInfo on success -# If @device is not a valid block device, DeviceNotFound +# If @device is not a valid block device, GenericError # If snapshot not found, GenericError # If the format of the image used does not support it, # BlockFormatFeatureNotSupported # If @id and @name are both not specified, GenericError # -# Since 1.7 +# Since: 1.7 ## { 'command': 'blockdev-snapshot-delete-internal-sync', 'data': { 'device': 'str', '*id': 'str', '*name': 'str'}, @@ -123,7 +125,9 @@ # # Ejects a device from a removable drive. # -# @device: The name of the device +# @device: #optional Block device name (deprecated, use @id instead) +# +# @id: #optional The name or QOM path of the guest device (since: 2.8) # # @force: @optional If true, eject regardless of whether the drive is locked. # If not specified, the default value is false. @@ -135,7 +139,10 @@ # # Since: 0.14.0 ## -{ 'command': 'eject', 'data': {'device': 'str', '*force': 'bool'} } +{ 'command': 'eject', + 'data': { '*device': 'str', + '*id': 'str', + '*force': 'bool' } } ## # @nbd-server-start: @@ -159,9 +166,9 @@ ## # @nbd-server-add: # -# Export a device to QEMU's embedded NBD server. +# Export a block node to QEMU's embedded NBD server. # -# @device: Block device to be exported +# @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). #optional @@ -183,22 +190,26 @@ { 'command': 'nbd-server-stop' } ## -# @DEVICE_TRAY_MOVED +# @DEVICE_TRAY_MOVED: # # Emitted whenever the tray of a removable device is moved by the guest or by # HMP/QMP commands # -# @device: device name +# @device: Block device name. This is always present for compatibility +# reasons, but it can be empty ("") if the image does not +# have a device name associated. +# +# @id: The name or QOM path of the guest device (since 2.8) # # @tray-open: true if the tray has been opened or false if it has been closed # # Since: 1.1 ## { 'event': 'DEVICE_TRAY_MOVED', - 'data': { 'device': 'str', 'tray-open': 'bool' } } + 'data': { 'device': 'str', 'id': 'str', 'tray-open': 'bool' } } ## -# @QuorumOpType +# @QuorumOpType: # # An enumeration of the quorum operation types # diff --git a/qapi/common.json b/qapi/common.json index 9353a7b377..624a8619c8 100644 --- a/qapi/common.json +++ b/qapi/common.json @@ -3,7 +3,7 @@ # QAPI common definitions ## -# @QapiErrorClass +# @QapiErrorClass: # # QEMU error classes # @@ -30,15 +30,15 @@ 'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap' ] } ## -# @VersionTriple +# @VersionTriple: # # A three-part version number. # -# @qemu.major: The major version number. +# @major: The major version number. # -# @qemu.minor: The minor version number. +# @minor: The minor version number. # -# @qemu.micro: The micro version number. +# @micro: The micro version number. # # Since: 2.4 ## @@ -101,7 +101,7 @@ { 'command': 'query-commands', 'returns': ['CommandInfo'] } ## -# @OnOffAuto +# @OnOffAuto: # # An enumeration of three options: on, off, and auto # @@ -117,7 +117,7 @@ 'data': [ 'auto', 'on', 'off' ] } ## -# @OnOffSplit +# @OnOffSplit: # # An enumeration of three values: on, off, and split # diff --git a/qapi/crypto.json b/qapi/crypto.json index 34d2583154..15d296e3c1 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -3,7 +3,7 @@ # QAPI crypto definitions ## -# QCryptoTLSCredsEndpoint: +# @QCryptoTLSCredsEndpoint: # # The type of network endpoint that will be using the credentials. # Most types of credential require different setup / structures @@ -22,7 +22,7 @@ ## -# QCryptoSecretFormat: +# @QCryptoSecretFormat: # # The data format that the secret is provided in # @@ -36,7 +36,7 @@ ## -# QCryptoHashAlgorithm: +# @QCryptoHashAlgorithm: # # The supported algorithms for computing content digests # @@ -55,7 +55,7 @@ ## -# QCryptoCipherAlgorithm: +# @QCryptoCipherAlgorithm: # # The supported algorithms for content encryption ciphers # @@ -82,22 +82,23 @@ ## -# QCryptoCipherMode: +# @QCryptoCipherMode: # # The supported modes for content encryption ciphers # # @ecb: Electronic Code Book # @cbc: Cipher Block Chaining # @xts: XEX with tweaked code book and ciphertext stealing +# @ctr: Counter (Since 2.8) # Since: 2.6 ## { 'enum': 'QCryptoCipherMode', 'prefix': 'QCRYPTO_CIPHER_MODE', - 'data': ['ecb', 'cbc', 'xts']} + 'data': ['ecb', 'cbc', 'xts', 'ctr']} ## -# QCryptoIVGenAlgorithm: +# @QCryptoIVGenAlgorithm: # # The supported algorithms for generating initialization # vectors for full disk encryption. The 'plain' generator @@ -115,7 +116,7 @@ 'data': ['plain', 'plain64', 'essiv']} ## -# QCryptoBlockFormat: +# @QCryptoBlockFormat: # # The supported full disk encryption formats # @@ -130,7 +131,7 @@ 'data': ['qcow', 'luks']} ## -# QCryptoBlockOptionsBase: +# @QCryptoBlockOptionsBase: # # The common options that apply to all full disk # encryption formats @@ -143,7 +144,7 @@ 'data': { 'format': 'QCryptoBlockFormat' }} ## -# QCryptoBlockOptionsQCow: +# @QCryptoBlockOptionsQCow: # # The options that apply to QCow/QCow2 AES-CBC encryption format # @@ -157,7 +158,7 @@ 'data': { '*key-secret': 'str' }} ## -# QCryptoBlockOptionsLUKS: +# @QCryptoBlockOptionsLUKS: # # The options that apply to LUKS encryption format # @@ -171,7 +172,7 @@ ## -# QCryptoBlockCreateOptionsLUKS: +# @QCryptoBlockCreateOptionsLUKS: # # The options that apply to LUKS encryption format initialization # @@ -185,6 +186,9 @@ # Currently defaults to 'sha256' # @hash-alg: #optional the master key hash algorithm # Currently defaults to 'sha256' +# @iter-time: #optional number of milliseconds to spend in +# PBKDF passphrase processing. Currently defaults +# to 2000. (since 2.8) # Since: 2.6 ## { 'struct': 'QCryptoBlockCreateOptionsLUKS', @@ -193,11 +197,12 @@ '*cipher-mode': 'QCryptoCipherMode', '*ivgen-alg': 'QCryptoIVGenAlgorithm', '*ivgen-hash-alg': 'QCryptoHashAlgorithm', - '*hash-alg': 'QCryptoHashAlgorithm'}} + '*hash-alg': 'QCryptoHashAlgorithm', + '*iter-time': 'int'}} ## -# QCryptoBlockOpenOptions: +# @QCryptoBlockOpenOptions: # # The options that are available for all encryption formats # when opening an existing volume @@ -212,7 +217,7 @@ ## -# QCryptoBlockCreateOptions: +# @QCryptoBlockCreateOptions: # # The options that are available for all encryption formats # when initializing a new volume @@ -227,7 +232,7 @@ ## -# QCryptoBlockInfoBase: +# @QCryptoBlockInfoBase: # # The common information that applies to all full disk # encryption formats @@ -241,7 +246,7 @@ ## -# QCryptoBlockInfoLUKSSlot: +# @QCryptoBlockInfoLUKSSlot: # # Information about the LUKS block encryption key # slot options @@ -261,7 +266,7 @@ ## -# QCryptoBlockInfoLUKS: +# @QCryptoBlockInfoLUKS: # # Information about the LUKS block encryption options # @@ -289,7 +294,7 @@ 'slots': [ 'QCryptoBlockInfoLUKSSlot' ] }} ## -# QCryptoBlockInfoQCow: +# @QCryptoBlockInfoQCow: # # Information about the QCow block encryption options # @@ -300,7 +305,7 @@ ## -# QCryptoBlockInfo: +# @QCryptoBlockInfo: # # Information about the block encryption options # diff --git a/qapi/event.json b/qapi/event.json index 8642052ebc..37bf34ed6d 100644 --- a/qapi/event.json +++ b/qapi/event.json @@ -1,5 +1,5 @@ ## -# @SHUTDOWN +# @SHUTDOWN: # # Emitted when the virtual machine has shut down, indicating that qemu is # about to exit. @@ -12,7 +12,7 @@ { 'event': 'SHUTDOWN' } ## -# @POWERDOWN +# @POWERDOWN: # # Emitted when the virtual machine is powered down through the power control # system, such as via ACPI. @@ -22,7 +22,7 @@ { 'event': 'POWERDOWN' } ## -# @RESET +# @RESET: # # Emitted when the virtual machine is reset # @@ -31,7 +31,7 @@ { 'event': 'RESET' } ## -# @STOP +# @STOP: # # Emitted when the virtual machine is stopped # @@ -40,7 +40,7 @@ { 'event': 'STOP' } ## -# @RESUME +# @RESUME: # # Emitted when the virtual machine resumes execution # @@ -49,7 +49,7 @@ { 'event': 'RESUME' } ## -# @SUSPEND +# @SUSPEND: # # Emitted when guest enters a hardware suspension state, for example, S3 state, # which is sometimes called standby state @@ -59,7 +59,7 @@ { 'event': 'SUSPEND' } ## -# @SUSPEND_DISK +# @SUSPEND_DISK: # # Emitted when guest enters a hardware suspension state with data saved on # disk, for example, S4 state, which is sometimes called hibernate state @@ -71,7 +71,7 @@ { 'event': 'SUSPEND_DISK' } ## -# @WAKEUP +# @WAKEUP: # # Emitted when the guest has woken up from suspend state and is running # @@ -80,7 +80,7 @@ { 'event': 'WAKEUP' } ## -# @RTC_CHANGE +# @RTC_CHANGE: # # Emitted when the guest changes the RTC time. # @@ -93,7 +93,7 @@ 'data': { 'offset': 'int' } } ## -# @WATCHDOG +# @WATCHDOG: # # Emitted when the watchdog device's timer is expired # @@ -108,7 +108,7 @@ 'data': { 'action': 'WatchdogExpirationAction' } } ## -# @DEVICE_DELETED +# @DEVICE_DELETED: # # Emitted whenever the device removal completion is acknowledged by the guest. # At this point, it's safe to reuse the specified device ID. Device removal can @@ -124,7 +124,7 @@ 'data': { '*device': 'str', 'path': 'str' } } ## -# @NIC_RX_FILTER_CHANGED +# @NIC_RX_FILTER_CHANGED: # # Emitted once until the 'query-rx-filter' command is executed, the first event # will always be emitted @@ -139,7 +139,7 @@ 'data': { '*name': 'str', 'path': 'str' } } ## -# @VNC_CONNECTED +# @VNC_CONNECTED: # # Emitted when a VNC client establishes a connection # @@ -157,7 +157,7 @@ 'client': 'VncBasicInfo' } } ## -# @VNC_INITIALIZED +# @VNC_INITIALIZED: # # Emitted after authentication takes place (if any) and the VNC session is # made active @@ -173,7 +173,7 @@ 'client': 'VncClientInfo' } } ## -# @VNC_DISCONNECTED +# @VNC_DISCONNECTED: # # Emitted when the connection is closed # @@ -188,7 +188,7 @@ 'client': 'VncClientInfo' } } ## -# @SPICE_CONNECTED +# @SPICE_CONNECTED: # # Emitted when a SPICE client establishes a connection # @@ -203,7 +203,7 @@ 'client': 'SpiceBasicInfo' } } ## -# @SPICE_INITIALIZED +# @SPICE_INITIALIZED: # # Emitted after initial handshake and authentication takes place (if any) # and the SPICE channel is up and running @@ -219,7 +219,7 @@ 'client': 'SpiceChannel' } } ## -# @SPICE_DISCONNECTED +# @SPICE_DISCONNECTED: # # Emitted when the SPICE connection is closed # @@ -234,7 +234,7 @@ 'client': 'SpiceBasicInfo' } } ## -# @SPICE_MIGRATE_COMPLETED +# @SPICE_MIGRATE_COMPLETED: # # Emitted when SPICE migration has completed # @@ -243,7 +243,7 @@ { 'event': 'SPICE_MIGRATE_COMPLETED' } ## -# @MIGRATION +# @MIGRATION: # # Emitted when a migration event happens # @@ -255,7 +255,7 @@ 'data': {'status': 'MigrationStatus'}} ## -# @MIGRATION_PASS +# @MIGRATION_PASS: # # Emitted from the source side of a migration at the start of each pass # (when it syncs the dirty bitmap) @@ -268,7 +268,7 @@ 'data': { 'pass': 'int' } } ## -# @ACPI_DEVICE_OST +# @ACPI_DEVICE_OST: # # Emitted when guest executes ACPI _OST method. # @@ -280,7 +280,7 @@ 'data': { 'info': 'ACPIOSTInfo' } } ## -# @BALLOON_CHANGE +# @BALLOON_CHANGE: # # Emitted when the guest changes the actual BALLOON level. This value is # equivalent to the @actual field return by the 'query-balloon' command @@ -293,7 +293,7 @@ 'data': { 'actual': 'int' } } ## -# @GUEST_PANICKED +# @GUEST_PANICKED: # # Emitted when guest OS panic is detected # @@ -305,7 +305,7 @@ 'data': { 'action': 'GuestPanicAction' } } ## -# @QUORUM_FAILURE +# @QUORUM_FAILURE: # # Emitted by the Quorum block driver if it fails to establish a quorum # @@ -321,7 +321,7 @@ 'data': { 'reference': 'str', 'sector-num': 'int', 'sectors-count': 'int' } } ## -# @QUORUM_REPORT_BAD +# @QUORUM_REPORT_BAD: # # Emitted to report a corruption of a Quorum file # @@ -345,7 +345,7 @@ 'sector-num': 'int', 'sectors-count': 'int' } } ## -# @VSERPORT_CHANGE +# @VSERPORT_CHANGE: # # Emitted when the guest opens or closes a virtio-serial port. # @@ -359,7 +359,7 @@ 'data': { 'id': 'str', 'open': 'bool' } } ## -# @MEM_UNPLUG_ERROR +# @MEM_UNPLUG_ERROR: # # Emitted when memory hot unplug error occurs. # @@ -373,7 +373,7 @@ 'data': { 'device': 'str', 'msg': 'str' } } ## -# @DUMP_COMPLETED +# @DUMP_COMPLETED: # # Emitted when background dump has completed # diff --git a/qapi/introspect.json b/qapi/introspect.json index 3fd81fb540..fd4dc84196 100644 --- a/qapi/introspect.json +++ b/qapi/introspect.json @@ -11,7 +11,7 @@ # See the COPYING file in the top-level directory. ## -# @query-qmp-schema +# @query-qmp-schema: # # Command query-qmp-schema exposes the QMP wire ABI as an array of # SchemaInfo. This lets QMP clients figure out what commands and @@ -49,7 +49,7 @@ 'gen': false } # just to simplify qmp_query_json() ## -# @SchemaMetaType +# @SchemaMetaType: # # This is a @SchemaInfo's meta type, i.e. the kind of entity it # describes. @@ -75,7 +75,7 @@ 'command', 'event' ] } ## -# @SchemaInfo +# @SchemaInfo: # # @name: the entity's name, inherited from @base. # Commands and events have the name defined in the QAPI schema. @@ -105,7 +105,7 @@ 'event': 'SchemaInfoEvent' } } ## -# @SchemaInfoBuiltin +# @SchemaInfoBuiltin: # # Additional SchemaInfo members for meta-type 'builtin'. # @@ -117,7 +117,7 @@ 'data': { 'json-type': 'JSONType' } } ## -# @JSONType +# @JSONType: # # The four primitive and two structured types according to RFC 7159 # section 1, plus 'int' (split off 'number'), plus the obvious top @@ -130,7 +130,7 @@ 'object', 'array', 'value' ] } ## -# @SchemaInfoEnum +# @SchemaInfoEnum: # # Additional SchemaInfo members for meta-type 'enum'. # @@ -144,7 +144,7 @@ 'data': { 'values': ['str'] } } ## -# @SchemaInfoArray +# @SchemaInfoArray: # # Additional SchemaInfo members for meta-type 'array'. # @@ -158,7 +158,7 @@ 'data': { 'element-type': 'str' } } ## -# @SchemaInfoObject +# @SchemaInfoObject: # # Additional SchemaInfo members for meta-type 'object'. # @@ -183,7 +183,7 @@ '*variants': [ 'SchemaInfoObjectVariant' ] } } ## -# @SchemaInfoObjectMember +# @SchemaInfoObjectMember: # # An object member. # @@ -206,7 +206,7 @@ # @default's type must be null or match @type ## -# @SchemaInfoObjectVariant +# @SchemaInfoObjectVariant: # # The variant members for a value of the type tag. # @@ -221,7 +221,7 @@ 'data': { 'case': 'str', 'type': 'str' } } ## -# @SchemaInfoAlternate +# @SchemaInfoAlternate: # # Additional SchemaInfo members for meta-type 'alternate'. # @@ -237,7 +237,7 @@ 'data': { 'members': [ 'SchemaInfoAlternateMember' ] } } ## -# @SchemaInfoAlternateMember +# @SchemaInfoAlternateMember: # # An alternate member. # @@ -249,7 +249,7 @@ 'data': { 'type': 'str' } } ## -# @SchemaInfoCommand +# @SchemaInfoCommand: # # Additional SchemaInfo members for meta-type 'command'. # @@ -266,7 +266,7 @@ 'data': { 'arg-type': 'str', 'ret-type': 'str' } } ## -# @SchemaInfoEvent +# @SchemaInfoEvent: # # Additional SchemaInfo members for meta-type 'event'. # diff --git a/qapi/qapi-clone-visitor.c b/qapi/qapi-clone-visitor.c index 0bb8216372..34086cbfc0 100644 --- a/qapi/qapi-clone-visitor.c +++ b/qapi/qapi-clone-visitor.c @@ -110,7 +110,7 @@ static void qapi_clone_type_str(Visitor *v, const char *name, char **obj, assert(qcv->depth); /* * Pointer was already cloned by g_memdup; create fresh copy. - * Note that as long as qmp-output-visitor accepts NULL instead of + * Note that as long as qobject-output-visitor accepts NULL instead of * "", then we must do likewise. However, we want to obey the * input visitor semantics of never producing NULL when the empty * string is intended. diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index 55f5876dc0..63bd97b341 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -19,10 +19,12 @@ #include "qapi/qmp/qerror.h" #include "qapi/visitor.h" #include "qapi/visitor-impl.h" +#include "trace.h" void visit_complete(Visitor *v, void *opaque) { assert(v->type != VISITOR_OUTPUT || v->complete); + trace_visit_complete(v, opaque); if (v->complete) { v->complete(v, opaque); } @@ -30,6 +32,7 @@ void visit_complete(Visitor *v, void *opaque) void visit_free(Visitor *v) { + trace_visit_free(v); if (v) { v->free(v); } @@ -40,6 +43,7 @@ void visit_start_struct(Visitor *v, const char *name, void **obj, { Error *err = NULL; + trace_visit_start_struct(v, name, obj, size); if (obj) { assert(size); assert(!(v->type & VISITOR_OUTPUT) || *obj); @@ -53,6 +57,7 @@ void visit_start_struct(Visitor *v, const char *name, void **obj, void visit_check_struct(Visitor *v, Error **errp) { + trace_visit_check_struct(v); if (v->check_struct) { v->check_struct(v, errp); } @@ -60,6 +65,7 @@ void visit_check_struct(Visitor *v, Error **errp) void visit_end_struct(Visitor *v, void **obj) { + trace_visit_end_struct(v, obj); v->end_struct(v, obj); } @@ -69,6 +75,7 @@ void visit_start_list(Visitor *v, const char *name, GenericList **list, Error *err = NULL; assert(!list || size >= sizeof(GenericList)); + trace_visit_start_list(v, name, list, size); v->start_list(v, name, list, size, &err); if (list && (v->type & VISITOR_INPUT)) { assert(!(err && *list)); @@ -79,11 +86,13 @@ void visit_start_list(Visitor *v, const char *name, GenericList **list, GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size) { assert(tail && size >= sizeof(GenericList)); + trace_visit_next_list(v, tail, size); return v->next_list(v, tail, size); } void visit_end_list(Visitor *v, void **obj) { + trace_visit_end_list(v, obj); v->end_list(v, obj); } @@ -95,6 +104,7 @@ void visit_start_alternate(Visitor *v, const char *name, assert(obj && size >= sizeof(GenericAlternate)); assert(!(v->type & VISITOR_OUTPUT) || *obj); + trace_visit_start_alternate(v, name, obj, size, promote_int); if (v->start_alternate) { v->start_alternate(v, name, obj, size, promote_int, &err); } @@ -106,6 +116,7 @@ void visit_start_alternate(Visitor *v, const char *name, void visit_end_alternate(Visitor *v, void **obj) { + trace_visit_end_alternate(v, obj); if (v->end_alternate) { v->end_alternate(v, obj); } @@ -113,6 +124,7 @@ void visit_end_alternate(Visitor *v, void **obj) bool visit_optional(Visitor *v, const char *name, bool *present) { + trace_visit_optional(v, name, present); if (v->optional) { v->optional(v, name, present); } @@ -127,6 +139,7 @@ bool visit_is_input(Visitor *v) void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp) { assert(obj); + trace_visit_type_int(v, name, obj); v->type_int64(v, name, obj, errp); } @@ -150,7 +163,10 @@ static void visit_type_uintN(Visitor *v, uint64_t *obj, const char *name, void visit_type_uint8(Visitor *v, const char *name, uint8_t *obj, Error **errp) { - uint64_t value = *obj; + uint64_t value; + + trace_visit_type_uint8(v, name, obj); + value = *obj; visit_type_uintN(v, &value, name, UINT8_MAX, "uint8_t", errp); *obj = value; } @@ -158,7 +174,10 @@ void visit_type_uint8(Visitor *v, const char *name, uint8_t *obj, void visit_type_uint16(Visitor *v, const char *name, uint16_t *obj, Error **errp) { - uint64_t value = *obj; + uint64_t value; + + trace_visit_type_uint16(v, name, obj); + value = *obj; visit_type_uintN(v, &value, name, UINT16_MAX, "uint16_t", errp); *obj = value; } @@ -166,7 +185,10 @@ void visit_type_uint16(Visitor *v, const char *name, uint16_t *obj, void visit_type_uint32(Visitor *v, const char *name, uint32_t *obj, Error **errp) { - uint64_t value = *obj; + uint64_t value; + + trace_visit_type_uint32(v, name, obj); + value = *obj; visit_type_uintN(v, &value, name, UINT32_MAX, "uint32_t", errp); *obj = value; } @@ -175,6 +197,7 @@ void visit_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) { assert(obj); + trace_visit_type_uint64(v, name, obj); v->type_uint64(v, name, obj, errp); } @@ -198,7 +221,10 @@ static void visit_type_intN(Visitor *v, int64_t *obj, const char *name, void visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp) { - int64_t value = *obj; + int64_t value; + + trace_visit_type_int8(v, name, obj); + value = *obj; visit_type_intN(v, &value, name, INT8_MIN, INT8_MAX, "int8_t", errp); *obj = value; } @@ -206,7 +232,10 @@ void visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp) void visit_type_int16(Visitor *v, const char *name, int16_t *obj, Error **errp) { - int64_t value = *obj; + int64_t value; + + trace_visit_type_int16(v, name, obj); + value = *obj; visit_type_intN(v, &value, name, INT16_MIN, INT16_MAX, "int16_t", errp); *obj = value; } @@ -214,7 +243,10 @@ void visit_type_int16(Visitor *v, const char *name, int16_t *obj, void visit_type_int32(Visitor *v, const char *name, int32_t *obj, Error **errp) { - int64_t value = *obj; + int64_t value; + + trace_visit_type_int32(v, name, obj); + value = *obj; visit_type_intN(v, &value, name, INT32_MIN, INT32_MAX, "int32_t", errp); *obj = value; } @@ -223,6 +255,7 @@ void visit_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) { assert(obj); + trace_visit_type_int64(v, name, obj); v->type_int64(v, name, obj, errp); } @@ -230,6 +263,7 @@ void visit_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) { assert(obj); + trace_visit_type_size(v, name, obj); if (v->type_size) { v->type_size(v, name, obj, errp); } else { @@ -240,6 +274,7 @@ void visit_type_size(Visitor *v, const char *name, uint64_t *obj, void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) { assert(obj); + trace_visit_type_bool(v, name, obj); v->type_bool(v, name, obj, errp); } @@ -252,6 +287,7 @@ void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp) * can enable: assert(!(v->type & VISITOR_OUTPUT) || *obj); */ + trace_visit_type_str(v, name, obj); v->type_str(v, name, obj, &err); if (v->type & VISITOR_INPUT) { assert(!err != !*obj); @@ -263,6 +299,7 @@ void visit_type_number(Visitor *v, const char *name, double *obj, Error **errp) { assert(obj); + trace_visit_type_number(v, name, obj); v->type_number(v, name, obj, errp); } @@ -272,6 +309,7 @@ void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp) assert(obj); assert(v->type != VISITOR_OUTPUT || *obj); + trace_visit_type_any(v, name, obj); v->type_any(v, name, obj, &err); if (v->type == VISITOR_INPUT) { assert(!err != !*obj); @@ -281,6 +319,7 @@ void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp) void visit_type_null(Visitor *v, const char *name, Error **errp) { + trace_visit_type_null(v, name); v->type_null(v, name, errp); } diff --git a/qapi/qmp-event.c b/qapi/qmp-event.c index 8bba165bfb..802ede48e3 100644 --- a/qapi/qmp-event.c +++ b/qapi/qmp-event.c @@ -35,21 +35,12 @@ static void timestamp_put(QDict *qdict) int err; QObject *obj; qemu_timeval tv; - int64_t sec, usec; err = qemu_gettimeofday(&tv); - if (err < 0) { - /* Put -1 to indicate failure of getting host time */ - sec = -1; - usec = -1; - } else { - sec = tv.tv_sec; - usec = tv.tv_usec; - } - - obj = qobject_from_jsonf("{ 'seconds': %" PRId64 ", " - "'microseconds': %" PRId64 " }", - sec, usec); + /* Put -1 to indicate failure of getting host time */ + obj = qobject_from_jsonf("{ 'seconds': %lld, 'microseconds': %lld }", + err < 0 ? -1LL : (long long)tv.tv_sec, + err < 0 ? -1LL : (long long)tv.tv_usec); qdict_put_obj(qdict, "timestamp", obj); } diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c deleted file mode 100644 index 9e3b67ce13..0000000000 --- a/qapi/qmp-output-visitor.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Core Definitions for QAPI/QMP Command Registry - * - * Copyright (C) 2012-2016 Red Hat, Inc. - * Copyright IBM, Corp. 2011 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ - -#include "qemu/osdep.h" -#include "qapi/qmp-output-visitor.h" -#include "qapi/visitor-impl.h" -#include "qemu/queue.h" -#include "qemu-common.h" -#include "qapi/qmp/types.h" - -typedef struct QStackEntry -{ - QObject *value; - void *qapi; /* sanity check that caller uses same pointer */ - QSLIST_ENTRY(QStackEntry) node; -} QStackEntry; - -struct QmpOutputVisitor -{ - Visitor visitor; - QSLIST_HEAD(, QStackEntry) stack; /* Stack of unfinished containers */ - QObject *root; /* Root of the output visit */ - QObject **result; /* User's storage location for result */ -}; - -#define qmp_output_add(qov, name, value) \ - qmp_output_add_obj(qov, name, QOBJECT(value)) -#define qmp_output_push(qov, value, qapi) \ - qmp_output_push_obj(qov, QOBJECT(value), qapi) - -static QmpOutputVisitor *to_qov(Visitor *v) -{ - return container_of(v, QmpOutputVisitor, visitor); -} - -/* Push @value onto the stack of current QObjects being built */ -static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value, - void *qapi) -{ - QStackEntry *e = g_malloc0(sizeof(*e)); - - assert(qov->root); - assert(value); - e->value = value; - e->qapi = qapi; - QSLIST_INSERT_HEAD(&qov->stack, e, node); -} - -/* Pop a value off the stack of QObjects being built, and return it. */ -static QObject *qmp_output_pop(QmpOutputVisitor *qov, void *qapi) -{ - QStackEntry *e = QSLIST_FIRST(&qov->stack); - QObject *value; - - assert(e); - assert(e->qapi == qapi); - QSLIST_REMOVE_HEAD(&qov->stack, node); - value = e->value; - assert(value); - g_free(e); - return value; -} - -/* Add @value to the current QObject being built. - * If the stack is visiting a dictionary or list, @value is now owned - * by that container. Otherwise, @value is now the root. */ -static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name, - QObject *value) -{ - QStackEntry *e = QSLIST_FIRST(&qov->stack); - QObject *cur = e ? e->value : NULL; - - if (!cur) { - /* Don't allow reuse of visitor on more than one root */ - assert(!qov->root); - qov->root = value; - } else { - switch (qobject_type(cur)) { - case QTYPE_QDICT: - assert(name); - qdict_put_obj(qobject_to_qdict(cur), name, value); - break; - case QTYPE_QLIST: - assert(!name); - qlist_append_obj(qobject_to_qlist(cur), value); - break; - default: - g_assert_not_reached(); - } - } -} - -static void qmp_output_start_struct(Visitor *v, const char *name, void **obj, - size_t unused, Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - QDict *dict = qdict_new(); - - qmp_output_add(qov, name, dict); - qmp_output_push(qov, dict, obj); -} - -static void qmp_output_end_struct(Visitor *v, void **obj) -{ - QmpOutputVisitor *qov = to_qov(v); - QObject *value = qmp_output_pop(qov, obj); - assert(qobject_type(value) == QTYPE_QDICT); -} - -static void qmp_output_start_list(Visitor *v, const char *name, - GenericList **listp, size_t size, - Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - QList *list = qlist_new(); - - qmp_output_add(qov, name, list); - qmp_output_push(qov, list, listp); -} - -static GenericList *qmp_output_next_list(Visitor *v, GenericList *tail, - size_t size) -{ - return tail->next; -} - -static void qmp_output_end_list(Visitor *v, void **obj) -{ - QmpOutputVisitor *qov = to_qov(v); - QObject *value = qmp_output_pop(qov, obj); - assert(qobject_type(value) == QTYPE_QLIST); -} - -static void qmp_output_type_int64(Visitor *v, const char *name, int64_t *obj, - Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - qmp_output_add(qov, name, qint_from_int(*obj)); -} - -static void qmp_output_type_uint64(Visitor *v, const char *name, uint64_t *obj, - Error **errp) -{ - /* FIXME: QMP outputs values larger than INT64_MAX as negative */ - QmpOutputVisitor *qov = to_qov(v); - qmp_output_add(qov, name, qint_from_int(*obj)); -} - -static void qmp_output_type_bool(Visitor *v, const char *name, bool *obj, - Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - qmp_output_add(qov, name, qbool_from_bool(*obj)); -} - -static void qmp_output_type_str(Visitor *v, const char *name, char **obj, - Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - if (*obj) { - qmp_output_add(qov, name, qstring_from_str(*obj)); - } else { - qmp_output_add(qov, name, qstring_from_str("")); - } -} - -static void qmp_output_type_number(Visitor *v, const char *name, double *obj, - Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - qmp_output_add(qov, name, qfloat_from_double(*obj)); -} - -static void qmp_output_type_any(Visitor *v, const char *name, QObject **obj, - Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - qobject_incref(*obj); - qmp_output_add_obj(qov, name, *obj); -} - -static void qmp_output_type_null(Visitor *v, const char *name, Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - qmp_output_add_obj(qov, name, qnull()); -} - -/* Finish building, and return the root object. - * The root object is never null. The caller becomes the object's - * owner, and should use qobject_decref() when done with it. */ -static void qmp_output_complete(Visitor *v, void *opaque) -{ - QmpOutputVisitor *qov = to_qov(v); - - /* A visit must have occurred, with each start paired with end. */ - assert(qov->root && QSLIST_EMPTY(&qov->stack)); - assert(opaque == qov->result); - - qobject_incref(qov->root); - *qov->result = qov->root; - qov->result = NULL; -} - -static void qmp_output_free(Visitor *v) -{ - QmpOutputVisitor *qov = to_qov(v); - QStackEntry *e; - - while (!QSLIST_EMPTY(&qov->stack)) { - e = QSLIST_FIRST(&qov->stack); - QSLIST_REMOVE_HEAD(&qov->stack, node); - g_free(e); - } - - qobject_decref(qov->root); - g_free(qov); -} - -Visitor *qmp_output_visitor_new(QObject **result) -{ - QmpOutputVisitor *v; - - v = g_malloc0(sizeof(*v)); - - v->visitor.type = VISITOR_OUTPUT; - v->visitor.start_struct = qmp_output_start_struct; - v->visitor.end_struct = qmp_output_end_struct; - v->visitor.start_list = qmp_output_start_list; - v->visitor.next_list = qmp_output_next_list; - v->visitor.end_list = qmp_output_end_list; - v->visitor.type_int64 = qmp_output_type_int64; - v->visitor.type_uint64 = qmp_output_type_uint64; - v->visitor.type_bool = qmp_output_type_bool; - v->visitor.type_str = qmp_output_type_str; - v->visitor.type_number = qmp_output_type_number; - v->visitor.type_any = qmp_output_type_any; - v->visitor.type_null = qmp_output_type_null; - v->visitor.complete = qmp_output_complete; - v->visitor.free = qmp_output_free; - - *result = NULL; - v->result = result; - - return &v->visitor; -} diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c index 68b24c98b0..e8053686f3 100644 --- a/qapi/qmp-registry.c +++ b/qapi/qmp-registry.c @@ -30,6 +30,14 @@ void qmp_register_command(const char *name, QmpCommandFunc *fn, QTAILQ_INSERT_TAIL(&qmp_commands, cmd, node); } +void qmp_unregister_command(const char *name) +{ + QmpCommand *cmd = qmp_find_command(name); + + QTAILQ_REMOVE(&qmp_commands, cmd, node); + g_free(cmd); +} + QmpCommand *qmp_find_command(const char *name) { QmpCommand *cmd; diff --git a/qapi/qmp-input-visitor.c b/qapi/qobject-input-visitor.c index 64dd392e6f..0063327b3b 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qobject-input-visitor.c @@ -14,7 +14,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qapi/qmp-input-visitor.h" +#include "qapi/qobject-input-visitor.h" #include "qapi/visitor-impl.h" #include "qemu/queue.h" #include "qemu-common.h" @@ -34,7 +34,7 @@ typedef struct StackObject QSLIST_ENTRY(StackObject) node; } StackObject; -struct QmpInputVisitor +struct QObjectInputVisitor { Visitor visitor; @@ -49,14 +49,14 @@ struct QmpInputVisitor bool strict; }; -static QmpInputVisitor *to_qiv(Visitor *v) +static QObjectInputVisitor *to_qiv(Visitor *v) { - return container_of(v, QmpInputVisitor, visitor); + return container_of(v, QObjectInputVisitor, visitor); } -static QObject *qmp_input_get_object(QmpInputVisitor *qiv, - const char *name, - bool consume) +static QObject *qobject_input_get_object(QObjectInputVisitor *qiv, + const char *name, + bool consume, Error **errp) { StackObject *tos; QObject *qobj; @@ -64,6 +64,7 @@ static QObject *qmp_input_get_object(QmpInputVisitor *qiv, if (QSLIST_EMPTY(&qiv->stack)) { /* Starting at root, name is ignored. */ + assert(qiv->root); return qiv->root; } @@ -79,10 +80,14 @@ static QObject *qmp_input_get_object(QmpInputVisitor *qiv, bool removed = g_hash_table_remove(tos->h, name); assert(removed); } + if (!ret) { + error_setg(errp, QERR_MISSING_PARAMETER, name); + } } else { assert(qobject_type(qobj) == QTYPE_QLIST); assert(!name); ret = qlist_entry_obj(tos->entry); + assert(ret); if (consume) { tos->entry = qlist_next(tos->entry); } @@ -97,8 +102,9 @@ static void qdict_add_key(const char *key, QObject *obj, void *opaque) g_hash_table_insert(h, (gpointer) key, NULL); } -static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj, - void *qapi, Error **errp) +static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv, + QObject *obj, void *qapi, + Error **errp) { GHashTable *h; StackObject *tos = g_new0(StackObject, 1); @@ -120,9 +126,9 @@ static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj, } -static void qmp_input_check_struct(Visitor *v, Error **errp) +static void qobject_input_check_struct(Visitor *v, Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); + QObjectInputVisitor *qiv = to_qiv(v); StackObject *tos = QSLIST_FIRST(&qiv->stack); assert(tos && !tos->entry); @@ -140,7 +146,7 @@ static void qmp_input_check_struct(Visitor *v, Error **errp) } } -static void qmp_input_stack_object_free(StackObject *tos) +static void qobject_input_stack_object_free(StackObject *tos) { if (tos->h) { g_hash_table_unref(tos->h); @@ -149,33 +155,36 @@ static void qmp_input_stack_object_free(StackObject *tos) g_free(tos); } -static void qmp_input_pop(Visitor *v, void **obj) +static void qobject_input_pop(Visitor *v, void **obj) { - QmpInputVisitor *qiv = to_qiv(v); + QObjectInputVisitor *qiv = to_qiv(v); StackObject *tos = QSLIST_FIRST(&qiv->stack); assert(tos && tos->qapi == obj); QSLIST_REMOVE_HEAD(&qiv->stack, node); - qmp_input_stack_object_free(tos); + qobject_input_stack_object_free(tos); } -static void qmp_input_start_struct(Visitor *v, const char *name, void **obj, - size_t size, Error **errp) +static void qobject_input_start_struct(Visitor *v, const char *name, void **obj, + size_t size, Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); Error *err = NULL; if (obj) { *obj = NULL; } - if (!qobj || qobject_type(qobj) != QTYPE_QDICT) { + if (!qobj) { + return; + } + if (qobject_type(qobj) != QTYPE_QDICT) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "QDict"); return; } - qmp_input_push(qiv, qobj, obj, &err); + qobject_input_push(qiv, qobj, obj, &err); if (err) { error_propagate(errp, err); return; @@ -187,14 +196,18 @@ static void qmp_input_start_struct(Visitor *v, const char *name, void **obj, } -static void qmp_input_start_list(Visitor *v, const char *name, - GenericList **list, size_t size, Error **errp) +static void qobject_input_start_list(Visitor *v, const char *name, + GenericList **list, size_t size, + Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); const QListEntry *entry; - if (!qobj || qobject_type(qobj) != QTYPE_QLIST) { + if (!qobj) { + return; + } + if (qobject_type(qobj) != QTYPE_QLIST) { if (list) { *list = NULL; } @@ -203,7 +216,7 @@ static void qmp_input_start_list(Visitor *v, const char *name, return; } - entry = qmp_input_push(qiv, qobj, list, errp); + entry = qobject_input_push(qiv, qobj, list, errp); if (list) { if (entry) { *list = g_malloc0(size); @@ -213,10 +226,10 @@ static void qmp_input_start_list(Visitor *v, const char *name, } } -static GenericList *qmp_input_next_list(Visitor *v, GenericList *tail, - size_t size) +static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail, + size_t size) { - QmpInputVisitor *qiv = to_qiv(v); + QObjectInputVisitor *qiv = to_qiv(v); StackObject *so = QSLIST_FIRST(&qiv->stack); if (!so->entry) { @@ -227,16 +240,15 @@ static GenericList *qmp_input_next_list(Visitor *v, GenericList *tail, } -static void qmp_input_start_alternate(Visitor *v, const char *name, - GenericAlternate **obj, size_t size, - bool promote_int, Error **errp) +static void qobject_input_start_alternate(Visitor *v, const char *name, + GenericAlternate **obj, size_t size, + bool promote_int, Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, false); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, false, errp); if (!qobj) { *obj = NULL; - error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null"); return; } *obj = g_malloc0(size); @@ -246,12 +258,17 @@ static void qmp_input_start_alternate(Visitor *v, const char *name, } } -static void qmp_input_type_int64(Visitor *v, const char *name, int64_t *obj, - Error **errp) +static void qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj, + Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true)); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); + QInt *qint; + if (!qobj) { + return; + } + qint = qobject_to_qint(qobj); if (!qint) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "integer"); @@ -261,13 +278,18 @@ static void qmp_input_type_int64(Visitor *v, const char *name, int64_t *obj, *obj = qint_get_int(qint); } -static void qmp_input_type_uint64(Visitor *v, const char *name, uint64_t *obj, - Error **errp) +static void qobject_input_type_uint64(Visitor *v, const char *name, + uint64_t *obj, Error **errp) { /* FIXME: qobject_to_qint mishandles values over INT64_MAX */ - QmpInputVisitor *qiv = to_qiv(v); - QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true)); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); + QInt *qint; + if (!qobj) { + return; + } + qint = qobject_to_qint(qobj); if (!qint) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "integer"); @@ -277,12 +299,17 @@ static void qmp_input_type_uint64(Visitor *v, const char *name, uint64_t *obj, *obj = qint_get_int(qint); } -static void qmp_input_type_bool(Visitor *v, const char *name, bool *obj, - Error **errp) +static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj, + Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QBool *qbool = qobject_to_qbool(qmp_input_get_object(qiv, name, true)); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); + QBool *qbool; + if (!qobj) { + return; + } + qbool = qobject_to_qbool(qobj); if (!qbool) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "boolean"); @@ -292,14 +319,19 @@ static void qmp_input_type_bool(Visitor *v, const char *name, bool *obj, *obj = qbool_get_bool(qbool); } -static void qmp_input_type_str(Visitor *v, const char *name, char **obj, - Error **errp) +static void qobject_input_type_str(Visitor *v, const char *name, char **obj, + Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QString *qstr = qobject_to_qstring(qmp_input_get_object(qiv, name, true)); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); + QString *qstr; + *obj = NULL; + if (!qobj) { + return; + } + qstr = qobject_to_qstring(qobj); if (!qstr) { - *obj = NULL; error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string"); return; @@ -308,14 +340,17 @@ static void qmp_input_type_str(Visitor *v, const char *name, char **obj, *obj = g_strdup(qstring_get_str(qstr)); } -static void qmp_input_type_number(Visitor *v, const char *name, double *obj, - Error **errp) +static void qobject_input_type_number(Visitor *v, const char *name, double *obj, + Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); QInt *qint; QFloat *qfloat; + if (!qobj) { + return; + } qint = qobject_to_qint(qobj); if (qint) { *obj = qint_get_int(qobject_to_qint(qobj)); @@ -332,20 +367,29 @@ static void qmp_input_type_number(Visitor *v, const char *name, double *obj, "number"); } -static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj, - Error **errp) +static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj, + Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); + + *obj = NULL; + if (!qobj) { + return; + } qobject_incref(qobj); *obj = qobj; } -static void qmp_input_type_null(Visitor *v, const char *name, Error **errp) +static void qobject_input_type_null(Visitor *v, const char *name, Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); + + if (!qobj) { + return; + } if (qobject_type(qobj) != QTYPE_QNULL) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", @@ -353,10 +397,10 @@ static void qmp_input_type_null(Visitor *v, const char *name, Error **errp) } } -static void qmp_input_optional(Visitor *v, const char *name, bool *present) +static void qobject_input_optional(Visitor *v, const char *name, bool *present) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, false); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, false, NULL); if (!qobj) { *present = false; @@ -366,43 +410,44 @@ static void qmp_input_optional(Visitor *v, const char *name, bool *present) *present = true; } -static void qmp_input_free(Visitor *v) +static void qobject_input_free(Visitor *v) { - QmpInputVisitor *qiv = to_qiv(v); + QObjectInputVisitor *qiv = to_qiv(v); while (!QSLIST_EMPTY(&qiv->stack)) { StackObject *tos = QSLIST_FIRST(&qiv->stack); QSLIST_REMOVE_HEAD(&qiv->stack, node); - qmp_input_stack_object_free(tos); + qobject_input_stack_object_free(tos); } qobject_decref(qiv->root); g_free(qiv); } -Visitor *qmp_input_visitor_new(QObject *obj, bool strict) +Visitor *qobject_input_visitor_new(QObject *obj, bool strict) { - QmpInputVisitor *v; + QObjectInputVisitor *v; + assert(obj); v = g_malloc0(sizeof(*v)); v->visitor.type = VISITOR_INPUT; - v->visitor.start_struct = qmp_input_start_struct; - v->visitor.check_struct = qmp_input_check_struct; - v->visitor.end_struct = qmp_input_pop; - v->visitor.start_list = qmp_input_start_list; - v->visitor.next_list = qmp_input_next_list; - v->visitor.end_list = qmp_input_pop; - v->visitor.start_alternate = qmp_input_start_alternate; - v->visitor.type_int64 = qmp_input_type_int64; - v->visitor.type_uint64 = qmp_input_type_uint64; - v->visitor.type_bool = qmp_input_type_bool; - v->visitor.type_str = qmp_input_type_str; - v->visitor.type_number = qmp_input_type_number; - v->visitor.type_any = qmp_input_type_any; - v->visitor.type_null = qmp_input_type_null; - v->visitor.optional = qmp_input_optional; - v->visitor.free = qmp_input_free; + v->visitor.start_struct = qobject_input_start_struct; + v->visitor.check_struct = qobject_input_check_struct; + v->visitor.end_struct = qobject_input_pop; + v->visitor.start_list = qobject_input_start_list; + v->visitor.next_list = qobject_input_next_list; + v->visitor.end_list = qobject_input_pop; + v->visitor.start_alternate = qobject_input_start_alternate; + v->visitor.type_int64 = qobject_input_type_int64; + v->visitor.type_uint64 = qobject_input_type_uint64; + v->visitor.type_bool = qobject_input_type_bool; + v->visitor.type_str = qobject_input_type_str; + v->visitor.type_number = qobject_input_type_number; + v->visitor.type_any = qobject_input_type_any; + v->visitor.type_null = qobject_input_type_null; + v->visitor.optional = qobject_input_optional; + v->visitor.free = qobject_input_free; v->strict = strict; v->root = obj; diff --git a/qapi/qobject-output-visitor.c b/qapi/qobject-output-visitor.c new file mode 100644 index 0000000000..871127079d --- /dev/null +++ b/qapi/qobject-output-visitor.c @@ -0,0 +1,254 @@ +/* + * Core Definitions for QAPI/QMP Command Registry + * + * Copyright (C) 2012-2016 Red Hat, Inc. + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/qobject-output-visitor.h" +#include "qapi/visitor-impl.h" +#include "qemu/queue.h" +#include "qemu-common.h" +#include "qapi/qmp/types.h" + +typedef struct QStackEntry { + QObject *value; + void *qapi; /* sanity check that caller uses same pointer */ + QSLIST_ENTRY(QStackEntry) node; +} QStackEntry; + +struct QObjectOutputVisitor { + Visitor visitor; + QSLIST_HEAD(, QStackEntry) stack; /* Stack of unfinished containers */ + QObject *root; /* Root of the output visit */ + QObject **result; /* User's storage location for result */ +}; + +#define qobject_output_add(qov, name, value) \ + qobject_output_add_obj(qov, name, QOBJECT(value)) +#define qobject_output_push(qov, value, qapi) \ + qobject_output_push_obj(qov, QOBJECT(value), qapi) + +static QObjectOutputVisitor *to_qov(Visitor *v) +{ + return container_of(v, QObjectOutputVisitor, visitor); +} + +/* Push @value onto the stack of current QObjects being built */ +static void qobject_output_push_obj(QObjectOutputVisitor *qov, QObject *value, + void *qapi) +{ + QStackEntry *e = g_malloc0(sizeof(*e)); + + assert(qov->root); + assert(value); + e->value = value; + e->qapi = qapi; + QSLIST_INSERT_HEAD(&qov->stack, e, node); +} + +/* Pop a value off the stack of QObjects being built, and return it. */ +static QObject *qobject_output_pop(QObjectOutputVisitor *qov, void *qapi) +{ + QStackEntry *e = QSLIST_FIRST(&qov->stack); + QObject *value; + + assert(e); + assert(e->qapi == qapi); + QSLIST_REMOVE_HEAD(&qov->stack, node); + value = e->value; + assert(value); + g_free(e); + return value; +} + +/* Add @value to the current QObject being built. + * If the stack is visiting a dictionary or list, @value is now owned + * by that container. Otherwise, @value is now the root. */ +static void qobject_output_add_obj(QObjectOutputVisitor *qov, const char *name, + QObject *value) +{ + QStackEntry *e = QSLIST_FIRST(&qov->stack); + QObject *cur = e ? e->value : NULL; + + if (!cur) { + /* Don't allow reuse of visitor on more than one root */ + assert(!qov->root); + qov->root = value; + } else { + switch (qobject_type(cur)) { + case QTYPE_QDICT: + assert(name); + qdict_put_obj(qobject_to_qdict(cur), name, value); + break; + case QTYPE_QLIST: + assert(!name); + qlist_append_obj(qobject_to_qlist(cur), value); + break; + default: + g_assert_not_reached(); + } + } +} + +static void qobject_output_start_struct(Visitor *v, const char *name, + void **obj, size_t unused, Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + QDict *dict = qdict_new(); + + qobject_output_add(qov, name, dict); + qobject_output_push(qov, dict, obj); +} + +static void qobject_output_end_struct(Visitor *v, void **obj) +{ + QObjectOutputVisitor *qov = to_qov(v); + QObject *value = qobject_output_pop(qov, obj); + assert(qobject_type(value) == QTYPE_QDICT); +} + +static void qobject_output_start_list(Visitor *v, const char *name, + GenericList **listp, size_t size, + Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + QList *list = qlist_new(); + + qobject_output_add(qov, name, list); + qobject_output_push(qov, list, listp); +} + +static GenericList *qobject_output_next_list(Visitor *v, GenericList *tail, + size_t size) +{ + return tail->next; +} + +static void qobject_output_end_list(Visitor *v, void **obj) +{ + QObjectOutputVisitor *qov = to_qov(v); + QObject *value = qobject_output_pop(qov, obj); + assert(qobject_type(value) == QTYPE_QLIST); +} + +static void qobject_output_type_int64(Visitor *v, const char *name, + int64_t *obj, Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + qobject_output_add(qov, name, qint_from_int(*obj)); +} + +static void qobject_output_type_uint64(Visitor *v, const char *name, + uint64_t *obj, Error **errp) +{ + /* FIXME values larger than INT64_MAX become negative */ + QObjectOutputVisitor *qov = to_qov(v); + qobject_output_add(qov, name, qint_from_int(*obj)); +} + +static void qobject_output_type_bool(Visitor *v, const char *name, bool *obj, + Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + qobject_output_add(qov, name, qbool_from_bool(*obj)); +} + +static void qobject_output_type_str(Visitor *v, const char *name, char **obj, + Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + if (*obj) { + qobject_output_add(qov, name, qstring_from_str(*obj)); + } else { + qobject_output_add(qov, name, qstring_from_str("")); + } +} + +static void qobject_output_type_number(Visitor *v, const char *name, + double *obj, Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + qobject_output_add(qov, name, qfloat_from_double(*obj)); +} + +static void qobject_output_type_any(Visitor *v, const char *name, + QObject **obj, Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + qobject_incref(*obj); + qobject_output_add_obj(qov, name, *obj); +} + +static void qobject_output_type_null(Visitor *v, const char *name, Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + qobject_output_add_obj(qov, name, qnull()); +} + +/* Finish building, and return the root object. + * The root object is never null. The caller becomes the object's + * owner, and should use qobject_decref() when done with it. */ +static void qobject_output_complete(Visitor *v, void *opaque) +{ + QObjectOutputVisitor *qov = to_qov(v); + + /* A visit must have occurred, with each start paired with end. */ + assert(qov->root && QSLIST_EMPTY(&qov->stack)); + assert(opaque == qov->result); + + qobject_incref(qov->root); + *qov->result = qov->root; + qov->result = NULL; +} + +static void qobject_output_free(Visitor *v) +{ + QObjectOutputVisitor *qov = to_qov(v); + QStackEntry *e; + + while (!QSLIST_EMPTY(&qov->stack)) { + e = QSLIST_FIRST(&qov->stack); + QSLIST_REMOVE_HEAD(&qov->stack, node); + g_free(e); + } + + qobject_decref(qov->root); + g_free(qov); +} + +Visitor *qobject_output_visitor_new(QObject **result) +{ + QObjectOutputVisitor *v; + + v = g_malloc0(sizeof(*v)); + + v->visitor.type = VISITOR_OUTPUT; + v->visitor.start_struct = qobject_output_start_struct; + v->visitor.end_struct = qobject_output_end_struct; + v->visitor.start_list = qobject_output_start_list; + v->visitor.next_list = qobject_output_next_list; + v->visitor.end_list = qobject_output_end_list; + v->visitor.type_int64 = qobject_output_type_int64; + v->visitor.type_uint64 = qobject_output_type_uint64; + v->visitor.type_bool = qobject_output_type_bool; + v->visitor.type_str = qobject_output_type_str; + v->visitor.type_number = qobject_output_type_number; + v->visitor.type_any = qobject_output_type_any; + v->visitor.type_null = qobject_output_type_null; + v->visitor.complete = qobject_output_complete; + v->visitor.free = qobject_output_free; + + *result = NULL; + v->result = result; + + return &v->visitor; +} diff --git a/qapi/rocker.json b/qapi/rocker.json index 2fe7fdfa66..ace27760f1 100644 --- a/qapi/rocker.json +++ b/qapi/rocker.json @@ -1,5 +1,5 @@ ## -# @Rocker: +# @RockerSwitch: # # Rocker switch information. # diff --git a/qapi/trace-events b/qapi/trace-events new file mode 100644 index 0000000000..2c5d3bc7d7 --- /dev/null +++ b/qapi/trace-events @@ -0,0 +1,33 @@ +# qapi-visit-core.c +visit_free(void *v) "v=%p" +visit_complete(void *v, void *opaque) "v=%p opaque=%p" + +visit_start_struct(void *v, const char *name, void *obj, size_t size) "v=%p name=%s obj=%p size=%zu" +visit_check_struct(void *v) "v=%p" +visit_end_struct(void *v, void *obj) "v=%p obj=%p" + +visit_start_list(void *v, const char *name, void *obj, size_t size) "v=%p name=%s obj=%p size=%zu" +visit_next_list(void *v, void *tail, size_t size) "v=%p tail=%p size=%zu" +visit_end_list(void *v, void *obj) "v=%p obj=%p" + +visit_start_alternate(void *v, const char *name, void *obj, size_t size, bool promote_int) "v=%p name=%s obj=%p size=%zu promote_int=%d" +visit_end_alternate(void *v, void *obj) "v=%p obj=%p" + +visit_optional(void *v, const char *name, bool *present) "v=%p name=%s present=%p" + +visit_type_enum(void *v, const char *name, int *obj) "v=%p name=%s obj=%p" +visit_type_int(void *v, const char *name, int64_t *obj) "v=%p name=%s obj=%p" +visit_type_uint8(void *v, const char *name, uint8_t *obj) "v=%p name=%s obj=%p" +visit_type_uint16(void *v, const char *name, uint16_t *obj) "v=%p name=%s obj=%p" +visit_type_uint32(void *v, const char *name, uint32_t *obj) "v=%p name=%s obj=%p" +visit_type_uint64(void *v, const char *name, uint64_t *obj) "v=%p name=%s obj=%p" +visit_type_int8(void *v, const char *name, int8_t *obj) "v=%p name=%s obj=%p" +visit_type_int16(void *v, const char *name, int16_t *obj) "v=%p name=%s obj=%p" +visit_type_int32(void *v, const char *name, int32_t *obj) "v=%p name=%s obj=%p" +visit_type_int64(void *v, const char *name, int64_t *obj) "v=%p name=%s obj=%p" +visit_type_size(void *v, const char *name, uint64_t *obj) "v=%p name=%s obj=%p" +visit_type_bool(void *v, const char *name, bool *obj) "v=%p name=%s obj=%p" +visit_type_str(void *v, const char *name, char **obj) "v=%p name=%s obj=%p" +visit_type_number(void *v, const char *name, double *obj) "v=%p name=%s obj=%p" +visit_type_any(void *v, const char *name, void *obj) "v=%p name=%s obj=%p" +visit_type_null(void *v, const char *name) "v=%p name=%s" diff --git a/qapi/trace.json b/qapi/trace.json index e87214677c..4fd39b7792 100644 --- a/qapi/trace.json +++ b/qapi/trace.json @@ -17,7 +17,7 @@ # # @enabled: The event is dynamically enabled. # -# Since 2.2 +# Since: 2.2 ## { 'enum': 'TraceEventState', 'data': ['unavailable', 'disabled', 'enabled'] } @@ -34,7 +34,7 @@ # An event is per-vCPU if it has the "vcpu" property in the "trace-events" # files. # -# Since 2.2 +# Since: 2.2 ## { 'struct': 'TraceEventInfo', 'data': {'name': 'str', 'state': 'TraceEventState', 'vcpu': 'bool'} } @@ -58,7 +58,7 @@ # exact match, @vcpu is given and the event does not have the "vcpu" property, # an error is returned. # -# Since 2.2 +# Since: 2.2 ## { 'command': 'trace-event-get-state', 'data': {'name': 'str', '*vcpu': 'int'}, @@ -83,7 +83,7 @@ # match, @vcpu is given and the event does not have the "vcpu" property, an # error is returned. # -# Since 2.2 +# Since: 2.2 ## { 'command': 'trace-event-set-state', 'data': {'name': 'str', 'enable': 'bool', '*ignore-unavailable': 'bool', |