Compare commits

...

95 Commits

Author SHA1 Message Date
Gerd Hoffmann
8977bd111f docs: add multiseat.txt
Howto on setting up multiseat for guests.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:43 +02:00
Gerd Hoffmann
f85d28316a usb: add input routing support for tablet and keyboard
Add display property to the keyboard.
Add display and head properties to the tablet.

If properties are set bind device to the display specified to
setup input routing.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:43 +02:00
Gerd Hoffmann
ee8c0b622c sdl: pass key event source to input layer
So the input layer knows where the input is coming from
and input routing works correctly.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:43 +02:00
Gerd Hoffmann
6f5943cf45 input: bind devices and input routing
Add function to bind input devices to display devices.  Implementing
input routing on top of this:  Events coming from the display device in
question are routed to the input device bound to it (if there is one).

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:43 +02:00
Gerd Hoffmann
8b84286f4c input: switch hid mouse and tablet to the new input layer api.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:43 +02:00
Gerd Hoffmann
1ff5eedd1d input: switch hid keyboard to new input layer api.
Minimal patch to get the switchover done.  We continue processing ps/2
scancodes for now as they are part of the live migration stream.  Fixing
that, then mapping directly from QKeyValue to HID keycodes is left as
excercise for another day.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:43 +02:00
Gerd Hoffmann
86846bfe64 input: keymap: add meta keys
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:43 +02:00
Gerd Hoffmann
2386a90730 input: add name to input_event_key_number
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:42 +02:00
Gerd Hoffmann
11c7fa7fa6 input: add qemu_input_key_number_to_qcode
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:42 +02:00
Andrew Oates
f5c0ab1312 input (curses): mask keycodes to remove modifier bits
Without the mask, control bits are passed on in the keycode, generating
incorrect PS/2 sequences when SHIFT, ALT, etc are held down.

Cc: qemu-stable@nongnu.org
Signed-off-by: Andrew Oates <andrew@aoates.org>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:42 +02:00
Peter Maydell
178ac111bc Merge remote-tracking branch 'remotes/qmp-unstable/queue/qmp' into staging
* remotes/qmp-unstable/queue/qmp:
  qapi: zero-initialize all QMP command parameters
  scripts/qapi.py: Avoid syntax not supported by Python 2.4
  doc: add "setup" to list of migration states

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-05-22 19:04:49 +01:00
Peter Maydell
6054d883d6 Merge remote-tracking branch 'remotes/kraxel/tags/pull-chardev-2' into staging
purge error_is_set()

# gpg: Signature made Wed 21 May 2014 11:43:44 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-chardev-2:
  error: error_is_set() is finally unused; remove
  char: Explain qmp_chardev_add()'s unusual error handling
  char: Clean up fragile use of error_is_set()
  char: Use return values instead of error_is_set(errp)
  qemu-socket: Clean up inet_connect_opts()

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-05-22 18:14:01 +01:00
Peter Maydell
5118dc5975 Merge remote-tracking branch 'remotes/kraxel/tags/pull-audio-5' into staging
audio: two intel-hda fixes.

# gpg: Signature made Wed 21 May 2014 09:49:39 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-audio-5:
  hw/audio/intel-hda: Avoid shift into sign bit
  audio/intel-hda: support FIFORDY

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-05-22 17:05:36 +01:00
Peter Maydell
45e66b7beb Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20140520' into staging
some s390 patches:

- Enable irqfds on s390 via the new adapter interrupt routing type.
  As a prereq, fix the kvm enable_cap helpers for some compilers and
  split the s390 flic into kvm and non-kvm parts.
- Enable software and hardware debugging support on s390. This needs a
  kernel headers update.

# gpg: Signature made Tue 20 May 2014 12:30:54 BST using RSA key ID C6F02FAF
# gpg: Can't check signature: public key not found

* remotes/cohuck/tags/s390x-20140520:
  s390x/kvm: hw debugging support via guest PER facility
  s390x/kvm: software breakpoint support
  s390x: remove duplicate definitions of DIAG 501
  linux-headers: update
  s390x/virtio-ccw: wire up irq routing and irqfds
  s390x/virtio-ccw: reference-counted indicators
  s390x: add I/O adapter registration
  s390x: split flic into kvm and non-kvm parts
  kvm: Fix enable_cap helpers on older gcc

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-05-22 16:14:02 +01:00
Peter Maydell
65903a8b08 Merge remote-tracking branch 'remotes/bonzini/scsi-next' into staging
* remotes/bonzini/scsi-next:
  megasas: remove buildtime strings
  block: iscsi build fix if LIBISCSI_FEATURE_IOVECTOR is not defined
  virtio-scsi: Plug memory leak on virtio_scsi_push_event() error path
  scsi: Document intentional fall through in scsi_req_length()

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-05-22 15:27:46 +01:00
Michael Roth
fc13d93726 qapi: zero-initialize all QMP command parameters
In general QMP command parameter values are specified by consumers of the
QMP/HMP interface, but in the case of optional parameters these values may
be left uninitialized.

It is considered a bug for code to make use of optional parameters that have
not been flagged as being present by the marshalling code (via corresponding
has_<parameter> parameter), however our marshalling code will still pass
these uninitialized values on to the corresponding QMP function (to then
be ignored). Some compilers (clang in particular) consider this unsafe
however, and generate warnings as a result. As reported by Peter Maydell:

  This is something clang's -fsanitize=undefined spotted. The
  code generated by qapi-commands.py in qmp-marshal.c for
  qmp_marshal_* functions where there are some optional
  arguments looks like this:

      bool has_force = false;
      bool force;

      mi = qmp_input_visitor_new_strict(QOBJECT(args));
      v = qmp_input_get_visitor(mi);
      visit_type_str(v, &device, "device", errp);
      visit_start_optional(v, &has_force, "force", errp);
      if (has_force) {
          visit_type_bool(v, &force, "force", errp);
      }
      visit_end_optional(v, errp);
      qmp_input_visitor_cleanup(mi);

      if (error_is_set(errp)) {
          goto out;
      }
      qmp_eject(device, has_force, force, errp);

  In the case where has_force is false, we never initialize
  force, but then we use it by passing it to qmp_eject.
  I imagine we don't then actually use the value, but clang
  complains in particular for 'bool' variables because the value
  that ends up being loaded from memory for 'force' is not either
  0 or 1 (being uninitialized stack contents).

Fix this by initializing all QMP command parameters to {0} in the
marshalling code prior to passing them on to the QMP functions.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Reported-by: Peter Maydell <peter.maydell@linaro.org>
Tested-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-21 09:25:31 -04:00
Luiz Capitulino
3478881130 scripts/qapi.py: Avoid syntax not supported by Python 2.4
The Python "except Foo as x" syntax was only introduced in
Python 2.6, but we aim to support Python 2.4 and later.
Use the old-style "except Foo, x" syntax instead, thus
fixing configure/compile on systems with older Python.

Reported-by: Peter Maydell <peter.maydell@linaro.org>
Tested-by: Andreas Färber <andreas.faerber@web.de>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-21 09:04:03 -04:00
Markus Armbruster
d2e064a73e error: error_is_set() is finally unused; remove
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-21 11:57:58 +02:00
Markus Armbruster
3894c78764 char: Explain qmp_chardev_add()'s unusual error handling
Character backend open hasn't been fully converted to the Error API.
Some opens fail without setting an error.  qmp_chardev_add() needs to
detect when that happens, and set a generic error.  Explain that in a
comment, and inline error_is_set() for clarity.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-21 11:57:58 +02:00
Markus Armbruster
0aff637e92 char: Clean up fragile use of error_is_set()
Using error_is_set(ERRP) to find out whether a function failed is
either wrong, fragile, or unnecessarily opaque.  It's wrong when ERRP
may be null, because errors go undetected when it is.  It's fragile
when proving ERRP non-null involves a non-local argument.  Else, it's
unnecessarily opaque (see commit 84d18f0).

The error_is_set(errp) in qemu_chr_new_from_opts() is merely fragile,
because the callers never pass a null errp argument.

Make the code more robust and more obviously correct: receive the
error in a local variable, then propagate it through the parameter.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-21 11:57:58 +02:00
Markus Armbruster
5f758366c0 char: Use return values instead of error_is_set(errp)
Using error_is_set(errp) to check whether a function call failed is
fragile: it breaks when errp is null.  Check perfectly suitable return
values instead when possible.  As far as I can tell, errp can't be
null there, but this is more robust and more obviously correct

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-21 11:57:57 +02:00
Markus Armbruster
3f9286b721 qemu-socket: Clean up inet_connect_opts()
Separate the search for a working addrinfo from the code that does
something with it.  Makes for a clearer search loop.

Use a local Error * to simplify resetting the error in the search
loop.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-21 11:57:57 +02:00
Peter Feiner
3b69595068 doc: add "setup" to list of migration states
On a slow VM (e.g., nested), you see the "setup" state when you query the
migration status.

Signed-off-by: Peter Feiner <peter@gridcentric.ca>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-20 14:39:19 -04:00
Olaf Hering
5a7733b0b7 megasas: remove buildtime strings
Using __DATE__ or __TIME__ in binary pkgs changes the checksum of
compiled binaries if they get rebuilt, even if there are no other
source changes.  Replace the dynamic strings with some equally
informative static strings.

Signed-off-by: Olaf Hering <olaf@aepfle.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-05-20 16:14:29 +02:00
David Hildenbrand
770a63792b s390x/kvm: hw debugging support via guest PER facility
This patch makes use of the hw debugging support in kvm (provided by the guest's
PER facility) on s390. It enables the following features, available using the
gdbserver:
- single-stepping
- hw breakpoints
- hw watchpoints

Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
2014-05-20 13:05:58 +02:00
David Hildenbrand
b30f4dfbda s390x/kvm: software breakpoint support
This patch allows to insert and remove sw breakpoints using the QEMU gdbserver
on s390 as well as to interrupt execution on a breakpoint hit when running
with KVM enabled.

Whenever a software breakpoint is inserted, common code calls kvm ioctl
KVM_UPDATE_GUEST_DEBUG. As this method's default on s390 is to return an error
if not implement, the insertion will fail. Therefore, KVM also has to be
updated in order to make use of software breakpoints.

Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
2014-05-20 13:05:58 +02:00
David Hildenbrand
8e4e86afa5 s390x: remove duplicate definitions of DIAG 501
When restoring the previously saved instruction in
kvm_arch_remove_sw_breakpoint(), we only restored one byte. Let's use
the sizeof() operator to make sure we restore the entire instruction.

While we are at it, let's remove the duplicate definitions of DIAG 501
and replace its size (used when reading/writing the instruction) with
a sizeof() operator to make the code self explaining and less error-prone.

Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
2014-05-20 13:05:58 +02:00
Jens Freimann
76eb98d51c linux-headers: update
Sync linux-headers with kvm/next (87c00572ba05aa8c9db118da75c608f47eb10b9e)

Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
2014-05-20 13:05:58 +02:00
Cornelia Huck
d426d9fba8 s390x/virtio-ccw: wire up irq routing and irqfds
Make use of the new s390 adapter irq routing support to enable real
in-kernel irqfds for virtio-ccw with adapter interrupts.

Note that s390 doesn't provide the common KVM_CAP_IRQCHIP capability, but
rather needs KVM_CAP_S390_IRQCHIP to be enabled. This is to ensure backward
compatibility.

Reviewed-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
2014-05-20 13:05:58 +02:00
Cornelia Huck
7bca3892cb s390x/virtio-ccw: reference-counted indicators
Make code using the same indicators point to a single allocated structure
that is freed when the last user goes away.

This will be used by the irqfd code to unmap addresses after the last user
is gone.

Reviewed-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
2014-05-20 13:05:58 +02:00
Cornelia Huck
03cf077ac9 s390x: add I/O adapter registration
Register an I/O adapter interrupt source for when virtio-ccw devices start
using adapter interrupts.

Reviewed-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
2014-05-20 13:05:58 +02:00
Cornelia Huck
7b35d0c44c s390x: split flic into kvm and non-kvm parts
Introduce a common parent class for both cases, where kvm and non-kvm
can hook up callbacks. This will be used by follow-on patches for
adapter registration and mapping.

We now always have a flic, regardless of whether we use kvm; the
non-kvm implementation just doesn't do anything.

Reviewed-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
2014-05-20 13:05:57 +02:00
Alexander Graf
61c7bbd236 kvm: Fix enable_cap helpers on older gcc
Commit 40f1ee27aa introduced handy helpers for enable_cap calls on
vcpu and vm level. Unfortunately some older gcc versions (4.7.1, 4.6)
seem to choke on signedness detection in inline created variables:

target-ppc/kvm.c: In function 'kvmppc_booke_watchdog_enable':
target-ppc/kvm.c:1302:21: error: comparison of unsigned expression < 0 is always false [-Werror=type-limits]
target-ppc/kvm.c: In function 'kvmppc_set_papr':
target-ppc/kvm.c:1504:21: error: comparison of unsigned expression < 0 is always false [-Werror=type-limits]

However - thanks to Thomas Huth for the suggestion - we can just cast the
offending potentially 0 value to a signed type, making the comparison signed.

Reviewed-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
2014-05-20 13:05:57 +02:00
Peter Maydell
ca8c0fab95 Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block patches

# gpg: Signature made Mon 19 May 2014 15:21:14 BST using RSA key ID C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"

* remotes/kevin/tags/for-upstream: (22 commits)
  block: optimize zero writes with bdrv_write_zeroes
  blockdev: add a function to parse enum ids from strings
  util: add qemu_iovec_is_zero
  qcow1: Stricter backing file length check
  qcow1: Validate image size (CVE-2014-0223)
  qcow1: Validate L2 table size (CVE-2014-0222)
  qcow1: Check maximum cluster size
  qcow1: Make padding in the header explicit
  curl: Add usage documentation
  curl: Add sslverify option
  curl: Remove broken parsing of options from url
  curl: Fix build when curl_multi_socket_action isn't available
  qemu-iotests: Fix blkdebug in VM drive in 030
  qemu-iotests: Fix core dump suppression in test 039
  iotests: Add test for the JSON protocol
  block: Allow JSON filenames
  check-qdict: Add test for qdict_join()
  qdict: Add qdict_join()
  block: add test for vhdx image created by Disk2VHD
  block: vhdx - account for identical header sections
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-05-20 11:57:52 +01:00
Jeff Cody
f2564d88fe block: iscsi build fix if LIBISCSI_FEATURE_IOVECTOR is not defined
Commit b03c380 introduced the function
iscsi_allocationmap_is_allocated(), however it is only used within a
code block that is conditionally compiled.  This produces a warning
(error with -werror) of "defined but not used" for the the function, if
LIBISCSI_FEATURE_IOVECTOR is not defined.

This wraps iscsi_allocationmap_is_allocated() in the same conditional.

Signed-off-by: Jeff Cody <jcody@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-05-20 10:09:45 +02:00
Peter Maydell
b1fe60cd35 hw/audio/intel-hda: Avoid shift into sign bit
Add a U suffix to avoid shifting into the sign bit (which is
undefined behaviour in C).

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-20 08:49:21 +02:00
Stanislav Vorobiov
a2554a334a audio/intel-hda: support FIFORDY
linux kernel 3.12 has changed intel-hda
driver to always check for FIFORDY, this
causes long hangs in guest since QEMU
always has this bit set to 0. We now simply set
it to 1 always, since we're synchronous anyway
and always ready to receive the stream

Signed-off-by: Stanislav Vorobiov <s.vorobiov@samsung.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-20 08:49:21 +02:00
Peter Maydell
c5fa6c86d0 Merge remote-tracking branch 'remotes/qmp-unstable/queue/qmp' into staging
* remotes/qmp-unstable/queue/qmp:
  qapi: skip redundant includes
  monitor: Add netdev_del id argument completion.
  monitor: Add netdev_add type argument completion.
  monitor: Add set_link arguments completion.
  monitor: Add chardev-add backend argument completion.
  monitor: Add chardev-remove command completion.
  monitor: Convert sendkey to use command_completion.
  qapi: Show qapi-commands.py invocation in qapi-code-gen.txt
  qapi: Replace uncommon use of the error API by the common one
  tests: Don't call visit_end_struct() after visit_start_struct() fails
  hw: Don't call visit_end_struct() after visit_start_struct() fails
  hmp: Call visit_end_struct() after visit_start_struct() succeeds
  qapi: Un-inline visit of implicit struct
  qapi-visit.py: Clean up a sloppy use of field prefix
  qapi: Clean up shadowing of parameters and locals in inner scopes
  qapi-visit.py: Clean up confusing push_indent() / pop_indent() use
  qapi: Replace start_optional()/end_optional() by optional()
  qapi: Remove unused Visitor callbacks start_handle(), end_handle()
  qapi: Normalize marshalling's visitor initialization and cleanup
  qapi: Update qapi-code-gen.txt example to match current code

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-05-19 14:10:01 +01:00
Peter Maydell
5bc8f026dd Merge remote-tracking branch 'remotes/kraxel/tags/pull-input-8' into staging
Input code update:
 - add keycode mapping helpers to core.
 - start switching devices to new input api.
 - misc bugfixes.

# gpg: Signature made Fri 16 May 2014 07:43:45 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-input-8:
  input: sparc32 kbd: claim en-us layout
  input: sparc32 kbd: fix some key mappings
  input: remove sparc keymap hack
  input: switch sparc32 kbd to new input api
  input: switch ps/2 mouse to new input api
  input: switch ps/2 kbd to new input api
  input: use KeyValue directly in sendkey monitor command
  input: add qemu_input_handler_deactivate
  input: key mapping helpers
  ps2: set ps/2 output buffer size as the same as kernel

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-05-19 12:53:07 +01:00
Peter Lieven
465bee1da8 block: optimize zero writes with bdrv_write_zeroes
this patch tries to optimize zero write requests
by automatically using bdrv_write_zeroes if it is
supported by the format.

This significantly speeds up file system initialization and
should speed zero write test used to test backend storage
performance.

I ran the following 2 tests on my internal SSD with a
50G QCOW2 container and on an attached iSCSI storage.

a) mkfs.ext4 -E lazy_itable_init=0,lazy_journal_init=0 /dev/vdX

QCOW2         [off]     [on]     [unmap]
-----
runtime:       14secs    1.1secs  1.1secs
filesize:      937M      18M      18M

iSCSI         [off]     [on]     [unmap]
----
runtime:       9.3s      0.9s     0.9s

b) dd if=/dev/zero of=/dev/vdX bs=1M oflag=direct

QCOW2         [off]     [on]     [unmap]
-----
runtime:       246secs   18secs   18secs
filesize:      51G       192K     192K
throughput:    203M/s    2.3G/s   2.3G/s

iSCSI*        [off]     [on]     [unmap]
----
runtime:       8mins     45secs   33secs
throughput:    106M/s    1.2G/s   1.6G/s
allocated:     100%      100%     0%

* The storage was connected via an 1Gbit interface.
  It seems to internally handle writing zeroes
  via WRITESAME16 very fast.

Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 13:42:27 +02:00
Peter Maydell
6a23082b4e Merge remote-tracking branch 'remotes/bonzini/scsi-next' into staging
* remotes/bonzini/scsi-next:
  [PATCH] block/iscsi: bump year in copyright notice
  block/iscsi: allow cluster_size of 4K and greater
  block/iscsi: clarify the meaning of ISCSI_CHECKALLOC_THRES
  block/iscsi: speed up read for unallocated sectors
  block/iscsi: allow fall back to WRITE SAME without UNMAP
  MAINTAINERS: mark megasas as maintained
  megasas: Add MSI support
  megasas: Enable MSI-X support
  megasas: Implement LD_LIST_QUERY
  scsi: Improve error messages more
  scsi-disk: Improve error messager if can't get version number

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-05-19 12:30:06 +01:00
Peter Lieven
82a402e99f blockdev: add a function to parse enum ids from strings
this adds a generic function to recover the enum id of a parameter
given as a string.

Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 12:21:17 +02:00
Peter Lieven
43f35cb5e0 util: add qemu_iovec_is_zero
Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 12:20:19 +02:00
Kevin Wolf
d66e5cee00 qcow1: Stricter backing file length check
Like qcow2 since commit 6d33e8e7, error out on invalid lengths instead
of silently truncating them to 1023.

Also don't rely on bdrv_pread() catching integer overflows that make len
negative, but use unsigned variables in the first place.

Cc: qemu-stable@nongnu.org
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Benoit Canet <benoit@irqsave.net>
2014-05-19 11:36:49 +02:00
Kevin Wolf
46485de0cb qcow1: Validate image size (CVE-2014-0223)
A huge image size could cause s->l1_size to overflow. Make sure that
images never require a L1 table larger than what fits in s->l1_size.

This cannot only cause unbounded allocations, but also the allocation of
a too small L1 table, resulting in out-of-bounds array accesses (both
reads and writes).

Cc: qemu-stable@nongnu.org
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 11:36:49 +02:00
Kevin Wolf
42eb58179b qcow1: Validate L2 table size (CVE-2014-0222)
Too large L2 table sizes cause unbounded allocations. Images actually
created by qemu-img only have 512 byte or 4k L2 tables.

To keep things consistent with cluster sizes, allow ranges between 512
bytes and 64k (in fact, down to 1 entry = 8 bytes is technically
working, but L2 table sizes smaller than a cluster don't make a lot of
sense).

This also means that the number of bytes on the virtual disk that are
described by the same L2 table is limited to at most 8k * 64k or 2^29,
preventively avoiding any integer overflows.

Cc: qemu-stable@nongnu.org
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Benoit Canet <benoit@irqsave.net>
2014-05-19 11:36:49 +02:00
Kevin Wolf
7159a45b2b qcow1: Check maximum cluster size
Huge values for header.cluster_bits cause unbounded allocations (e.g.
for s->cluster_cache) and crash qemu this way. Less huge values may
survive those allocations, but can cause integer overflows later on.

The only cluster sizes that qemu can create are 4k (for standalone
images) and 512 (for images with backing files), so we can limit it
to 64k.

Cc: qemu-stable@nongnu.org
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Benoit Canet <benoit@irqsave.net>
2014-05-19 11:36:49 +02:00
Kevin Wolf
ea54feff58 qcow1: Make padding in the header explicit
We were relying on all compilers inserting the same padding in the
header struct that is used for the on-disk format. Let's not do that.
Mark the struct as packed and insert an explicit padding field for
compatibility.

Cc: qemu-stable@nongnu.org
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Benoit Canet <benoit@irqsave.net>
2014-05-19 11:36:49 +02:00
Matthew Booth
0a86cb7317 curl: Add usage documentation
Signed-off-by: Matthew Booth <mbooth@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 11:36:49 +02:00
Matthew Booth
97a3ea5719 curl: Add sslverify option
This allows qemu to use images over https with a self-signed certificate. It
defaults to verifying the certificate.

Signed-off-by: Matthew Booth <mbooth@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 11:36:49 +02:00
Matthew Booth
e3542c67af curl: Remove broken parsing of options from url
The block layer now supports a generic json syntax for passing option parameters
explicitly, making parsing of options from the url redundant.

Signed-off-by: Matthew Booth <mbooth@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 11:36:49 +02:00
Matthew Booth
9aedd5a5d6 curl: Fix build when curl_multi_socket_action isn't available
Signed-off-by: Matthew Booth <mbooth@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 11:36:49 +02:00
Fam Zheng
b5e51dd714 qemu-iotests: Fix blkdebug in VM drive in 030
The test test_stream_pause in this class uses vm.pause_drive, which
requires a blkdebug driver on top of image, otherwise it's no-op and the
test running is undeterministic.

So add it.

Signed-off-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 11:36:49 +02:00
Markus Armbruster
d530e34232 qemu-iotests: Fix core dump suppression in test 039
The shell script attempts to suppress core dumps like this:

    old_ulimit=$(ulimit -c)
    ulimit -c 0
    $QEMU_IO arg...
    ulimit -c "$old_ulimit"

This breaks the test hard unless the limit was zero to begin with!
ulimit sets both hard and soft limit by default, and (re-)raising the
hard limit requires privileges.  Broken since it was added in commit
dc68afe.

Could be fixed by adding -S to set only the soft limit, but I'm not
sure how portable that is in practice.  Simply do it in a subshell
instead, like this:

    (ulimit -c 0; exec $QEMU_IO arg...)

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 11:36:49 +02:00
Max Reitz
4ad303369c iotests: Add test for the JSON protocol
Add a test for the JSON protocol driver.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 11:36:49 +02:00
Max Reitz
4993f7ea7e block: Allow JSON filenames
If the filename given to bdrv_open() is prefixed with "json:", parse the
rest as a JSON object and merge the result into the options QDict. If
there are conflicts, the options QDict takes precedence.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 11:36:49 +02:00
Max Reitz
8a5eb36a1c check-qdict: Add test for qdict_join()
Add some test cases for qdict_join().

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Benoit Canet <benoit@irqsave.net>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 11:36:48 +02:00
Max Reitz
9c52681277 qdict: Add qdict_join()
This function joins two QDicts by absorbing one into the other.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Benoit Canet <benoit@irqsave.net>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 11:36:48 +02:00
Jeff Cody
26e2da7279 block: add test for vhdx image created by Disk2VHD
This adds a test for VHDX images created by Microsoft's tool, Disk2VHD.

VHDX images created by this tool have 2 identical header sections, with
identical sequence numbers.  This makes sure we detect VHDX images with
identical headers, and do not flag them as corrupt.

Signed-off-by: Jeff Cody <jcody@redhat.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 11:36:48 +02:00
Jeff Cody
6906046169 block: vhdx - account for identical header sections
The VHDX spec v1.00 declares that "a header is current if it is the only
valid header or if it is valid and its SequenceNumber field is greater
than the other header’s SequenceNumber field. The parser must only use
data from the current header. If there is no current header, then the
VHDX file is corrupt."

However, the Disk2VHD tool from Microsoft creates a VHDX image file that
has 2 identical headers, including matching checksums and matching
sequence numbers.  Likely, as a shortcut the tool is just writing the
header twice, for the active and inactive headers, during the image
creation.  Technically, this should be considered a corrupt VHDX file
(at least per the 1.00 spec, and that is how we currently treat it).

But in order to accomodate images created with Disk2VHD, we can safely
create an exception for this case.  If we find identical sequence
numbers, then we check the VHDXHeader-sized chunks of each 64KB header
sections (we won't rely just on the crc32c to indicate the headers are
the same).  If they are identical, then we go ahead and use the first
one.

Reported-by: Nerijus Baliūnas <nerijus@users.sourceforge.net>
Signed-off-by: Jeff Cody <jcody@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 11:36:48 +02:00
Mike Day
395071a763 Remove g_sequence_lookup from qemu-img help function
g_sequence_lookup is not supported by glib < 2.28. The usage
of g_sequence_lookup is not essential in this context (it's a
safeguard against duplicate values in the help message).
Removing the call enables the build on all platforms and
does not change the operation of the help function.

Signed-off-by: Mike Day <ncmike@ncultra.org>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-05-19 11:36:48 +02:00
Kevin Wolf
e88ae2264d block: Fix bdrv_is_allocated() for short backing files
bdrv_is_allocated() shouldn't return true for sectors that are
unallocated, but after the end of a short backing file, even though
such sectors are (correctly) marked as containing zeros.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
2014-05-19 11:36:48 +02:00
Markus Armbruster
91e7fcca47 virtio-scsi: Plug memory leak on virtio_scsi_push_event() error path
Spotted by Coverity.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-05-16 17:52:28 +02:00
Markus Armbruster
c4ce4c4b1f scsi: Document intentional fall through in scsi_req_length()
For clarity, and to hush up Coverity.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-05-16 17:52:14 +02:00
Benoît Canet
24fd848950 qapi: skip redundant includes
The purpose of this change is to help create a json file containing
common definitions; each bit of generated C code must be emitted
only one time.

A second history global to all QAPISchema instances has been added
to detect when a file is included more than one time and skip these
includes.
It does not act as a stack and the changes made to it by the
__init__ function are propagated back to the caller so it's really
a global state.

Signed-off-by: Benoit Canet <benoit@irqsave.net>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-16 10:35:59 -04:00
Hani Benhabiles
11b389f21e monitor: Add netdev_del id argument completion.
Signed-off-by: Hani Benhabiles <hani@linux.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 15:16:02 -04:00
Hani Benhabiles
b162b49adc monitor: Add netdev_add type argument completion.
Also update the command's documentation.

Signed-off-by: Hani Benhabiles <hani@linux.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 15:16:02 -04:00
Hani Benhabiles
40d19394b7 monitor: Add set_link arguments completion.
Make it possible to query all net clients without specifying an ID when calling
qemu_find_net_clients_except().

This also adds the add_completion_option() function which is to be used for
other commands completions as well.

Signed-off-by: Hani Benhabiles <hani@linux.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 15:16:02 -04:00
Hani Benhabiles
13e315dada monitor: Add chardev-add backend argument completion.
Signed-off-by: Hani Benhabiles <hani@linux.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 15:16:01 -04:00
Hani Benhabiles
6297d9a279 monitor: Add chardev-remove command completion.
Signed-off-by: Hani Benhabiles <hani@linux.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 15:16:01 -04:00
Hani Benhabiles
29136cd8a4 monitor: Convert sendkey to use command_completion.
Signed-off-by: Hani Benhabiles <hani@linux.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 15:16:01 -04:00
Markus Armbruster
87a560c455 qapi: Show qapi-commands.py invocation in qapi-code-gen.txt
While there, pare down the shell prompts.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 15:16:01 -04:00
Markus Armbruster
297a3646c2 qapi: Replace uncommon use of the error API by the common one
We commonly use the error API like this:

    err = NULL;
    foo(..., &err);
    if (err) {
        goto out;
    }
    bar(..., &err);

Every error source is checked separately.  The second function is only
called when the first one succeeds.  Both functions are free to pass
their argument to error_set().  Because error_set() asserts no error
has been set, this effectively means they must not be called with an
error set.

The qapi-generated code uses the error API differently:

    // *errp was initialized to NULL somewhere up the call chain
    frob(..., errp);
    gnat(..., errp);

Errors accumulate in *errp: first error wins, subsequent errors get
dropped.  To make this work, the second function does nothing when
called with an error set.  Requires non-null errp, or else the second
function can't see the first one fail.

This usage has also bled into visitor tests, and two device model
object property getters rtc_get_date() and balloon_stats_get_all().

With the "accumulate" technique, you need fewer error checks in
callers, and buy that with an error check in every callee.  Can be
nice.

However, mixing the two techniques is confusing.  You can't use the
"accumulate" technique with functions designed for the "check
separately" technique.  You can use the "check separately" technique
with functions designed for the "accumulate" technique, but then
error_set() can't catch you setting an error more than once.

Standardize on the "check separately" technique for now, because it's
overwhelmingly prevalent.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 14:00:46 -04:00
Markus Armbruster
cdaec3808e tests: Don't call visit_end_struct() after visit_start_struct() fails
When visit_start_struct() fails, visit_end_struct() must not be
called.  Three out of four visit_type_TestStruct() call it anyway.  As
far as I can tell, visit_start_struct() doesn't actually fail there.
Fix them anyway.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 14:00:46 -04:00
Markus Armbruster
2ddb16a95f hw: Don't call visit_end_struct() after visit_start_struct() fails
When visit_start_struct() fails, visit_end_struct() must not be
called.  rtc_get_date() and balloon_stats_all() call it anyway.  As
far as I can tell, they're only used with the string output visitor,
which doesn't care.  Fix them anyway.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 14:00:46 -04:00
Markus Armbruster
f9f3a5ecde hmp: Call visit_end_struct() after visit_start_struct() succeeds
When visit_start_struct() succeeds, visit_end_struct() must be called.
hmp_object_add() doesn't when a member visit fails.  As far as I can
tell, the opts visitor copes okay with the misuse.  Fix it anyway.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 14:00:46 -04:00
Markus Armbruster
be3c771796 qapi: Un-inline visit of implicit struct
In preparation of error handling changes.  Bonus: generates less
duplicated code.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 14:00:46 -04:00
Markus Armbruster
192cca60ae qapi-visit.py: Clean up a sloppy use of field prefix
generate_visit_struct_fields() generates the base type's struct member
name both with and without the field prefix.  Harmless, because the
field prefix is always empty there: only unboxed complex members have
a prefix, and those can't have a base type.

Clean it up anyway.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 14:00:46 -04:00
Markus Armbruster
4fa953f20d qapi: Clean up shadowing of parameters and locals in inner scopes
By un-inlining the visit of nested complex types.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 14:00:45 -04:00
Markus Armbruster
468866b816 qapi-visit.py: Clean up confusing push_indent() / pop_indent() use
Changing implicit indentation in the middle of generating a block
makes following the code being generated unnecessarily hard.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 14:00:45 -04:00
Markus Armbruster
e2cd0f4fb4 qapi: Replace start_optional()/end_optional() by optional()
Semantics of end_optional() differ subtly from the other end_FOO()
callbacks: when start_FOO() succeeds, the matching end_FOO() gets
called regardless of what happens in between.  end_optional() gets
called only when everything in between succeeds as well.  Entirely
undocumented, like all of the visitor API.

The only user of Visitor Callback end_optional() never did anything,
and was removed in commit 9f9ab46.

I'm about to clean up error handling in the generated visitor code,
and end_optional() is in my way.  No users mean no test cases, and
making non-trivial cleanup transformations without test cases doesn't
strike me as a good idea.

Drop end_optional(), and rename start_optional() to optional().  We
can always go back to a pair of callbacks when we have an actual need.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 14:00:45 -04:00
Markus Armbruster
cbc95538ed qapi: Remove unused Visitor callbacks start_handle(), end_handle()
These have never been called or implemented by anything, and their
intended use is undocumented, like all of the visitor API.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 14:00:45 -04:00
Markus Armbruster
f9bee751be qapi: Normalize marshalling's visitor initialization and cleanup
Input and output marshalling functions do it differently.  Change them
to work the same: initialize the I/O visitor, use it, clean it up,
initialize the dealloc visitor, use it, clean it up.

This delays dealloc visitor initialization in output marshalling
functions, and input visitor cleanup in input marshalling functions.
No functional change, but the latter will be convenient when I change
the error handling.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 14:00:45 -04:00
Markus Armbruster
6e2bb3ec70 qapi: Update qapi-code-gen.txt example to match current code
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-15 14:00:45 -04:00
Peter Lieven
6a86dec619 [PATCH] block/iscsi: bump year in copyright notice
Signed-off-by: Peter Lieven <pl@kamp.de>
2014-05-05 10:04:30 +02:00
Peter Lieven
3d2acaa308 block/iscsi: allow cluster_size of 4K and greater
depending on the target the opt_unmap_gran might be as low
as 4K. As we know use this also as a knob to activate the allocationmap
feature lower the barrier. The limit 4K (and not 512) is choosen
to avoid a potentially too big allocationmap.

Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-04-29 11:15:01 +02:00
Peter Lieven
5917af812e block/iscsi: clarify the meaning of ISCSI_CHECKALLOC_THRES
Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-04-29 11:14:41 +02:00
Peter Lieven
b03c38057b block/iscsi: speed up read for unallocated sectors
this patch implements a cache that tracks if a page on the
iscsi target is allocated or not. The cache is implemented in
a way that it allows for false positives
(e.g. pretending a page is allocated, but it isn't), but
no false negatives.

The cached allocation info is then used to speed up the
read process for unallocated sectors by issueing a GET_LBA_STATUS
request for all sectors that are not yet known to be allocated.
If the read request is confirmed to fall into an unallocated
range we directly return zeroes and do not transfer the
data over the wire.

Tests have shown that a relatively small amount of GET_LBA_STATUS
requests happens a vServer boot time to fill the allocation cache
(all those blocks are not queried again).

Not to transfer all the data of unallocated sectors saves a lot
of time, bandwidth and storage I/O load during block jobs or storage
migration and it saves a lot of bandwidth as well for any big sequential
read of the whole disk (e.g. block copy or speed tests) if a significant
number of blocks is unallocated.

Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-04-29 11:14:25 +02:00
Peter Lieven
dbe5c58f2a block/iscsi: allow fall back to WRITE SAME without UNMAP
if the iscsi driver receives a write zeroes request with
the BDRV_REQ_MAY_UNMAP flag set it fails with -ENOTSUP
if the iscsi target does not support WRITE SAME with
UNMAP. However, the BDRV_REQ_MAY_UNMAP is only a hint
and writing zeroes with WRITE SAME will still be
better than falling back to writing zeroes with WRITE16.

Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-04-28 15:04:17 +02:00
Hannes Reinecke
d383c625e2 MAINTAINERS: mark megasas as maintained
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-04-28 13:51:23 +02:00
Hannes Reinecke
4522b69c6c megasas: Add MSI support
Some hardware instances do support MSI, so we should do likewise.

Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-04-28 13:51:13 +02:00
Hannes Reinecke
23335f6273 megasas: Enable MSI-X support
MSI-X support has been fixed in qemu, so we can enable it again.

Signed-off-by: Hannes Reinecke <hare@suse.de>
[Do not change VMSTATE_PCI_DEVICE to PCIE. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-04-28 13:50:01 +02:00
Hannes Reinecke
34bb4d02e0 megasas: Implement LD_LIST_QUERY
Newer firmware implement a LD_LIST_QUERY command, and due to a driver
issue no drives might be detected if this command isn't supported.
So add emulation for this command, too.

Cc: qemu-stable@nongnu.org
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-04-28 13:48:41 +02:00
Paolo Bonzini
6ee143a0a4 scsi: Improve error messages more
Remove the "scsi-block:" prefix for error messages as suggested
by Markus.

Improve the previous patch by making the message the same for both
scsi-block and scsi-generic, including the strerror() output in both
and making an explicit reference to SG_IO.  Also s/can not/cannot/.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-04-28 13:38:00 +02:00
Fam Zheng
4bbeb8b173 scsi-disk: Improve error messager if can't get version number
More often it is that bdrv_ioctl fails due to not supported by driver or
whatever reason, in this case we should be specific, because "interface
too old" is very confusing.

Signed-off-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-04-28 12:09:12 +02:00
99 changed files with 3350 additions and 1157 deletions

View File

@@ -659,6 +659,12 @@ S: Supported
F: hw/block/nvme* F: hw/block/nvme*
F: tests/nvme-test.c F: tests/nvme-test.c
megasas
M: Hannes Reinecke <hare@suse.de>
S: Supported
F: hw/scsi/megasas.c
F: hw/scsi/mfi.h
Xilinx EDK Xilinx EDK
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com> M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
M: Edgar E. Iglesias <edgar.iglesias@gmail.com> M: Edgar E. Iglesias <edgar.iglesias@gmail.com>

60
block.c
View File

@@ -1274,6 +1274,33 @@ out:
g_free(tmp_filename); g_free(tmp_filename);
} }
static QDict *parse_json_filename(const char *filename, Error **errp)
{
QObject *options_obj;
QDict *options;
int ret;
ret = strstart(filename, "json:", &filename);
assert(ret);
options_obj = qobject_from_json(filename);
if (!options_obj) {
error_setg(errp, "Could not parse the JSON options");
return NULL;
}
if (qobject_type(options_obj) != QTYPE_QDICT) {
qobject_decref(options_obj);
error_setg(errp, "Invalid JSON object given");
return NULL;
}
options = qobject_to_qdict(options_obj);
qdict_flatten(options);
return options;
}
/* /*
* Opens a disk image (raw, qcow2, vmdk, ...) * Opens a disk image (raw, qcow2, vmdk, ...)
* *
@@ -1337,6 +1364,20 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
options = qdict_new(); options = qdict_new();
} }
if (filename && g_str_has_prefix(filename, "json:")) {
QDict *json_options = parse_json_filename(filename, &local_err);
if (local_err) {
ret = -EINVAL;
goto fail;
}
/* Options given in the filename have lower priority than options
* specified directly */
qdict_join(options, json_options, false);
QDECREF(json_options);
filename = NULL;
}
bs->options = options; bs->options = options;
options = qdict_clone_shallow(options); options = qdict_clone_shallow(options);
@@ -3248,6 +3289,15 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req); ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
if (!ret && bs->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF &&
!(flags & BDRV_REQ_ZERO_WRITE) && drv->bdrv_co_write_zeroes &&
qemu_iovec_is_zero(qiov)) {
flags |= BDRV_REQ_ZERO_WRITE;
if (bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP) {
flags |= BDRV_REQ_MAY_UNMAP;
}
}
if (ret < 0) { if (ret < 0) {
/* Do nothing, write notifier decided to fail this request */ /* Do nothing, write notifier decided to fail this request */
} else if (flags & BDRV_REQ_ZERO_WRITE) { } else if (flags & BDRV_REQ_ZERO_WRITE) {
@@ -3864,7 +3914,7 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
if (!bs->drv->bdrv_co_get_block_status) { if (!bs->drv->bdrv_co_get_block_status) {
*pnum = nb_sectors; *pnum = nb_sectors;
ret = BDRV_BLOCK_DATA; ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
if (bs->drv->protocol_name) { if (bs->drv->protocol_name) {
ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE); ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE);
} }
@@ -3883,6 +3933,10 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
*pnum, pnum); *pnum, pnum);
} }
if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
ret |= BDRV_BLOCK_ALLOCATED;
}
if (!(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO)) { if (!(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO)) {
if (bdrv_unallocated_blocks_are_zero(bs)) { if (bdrv_unallocated_blocks_are_zero(bs)) {
ret |= BDRV_BLOCK_ZERO; ret |= BDRV_BLOCK_ZERO;
@@ -3959,9 +4013,7 @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num,
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
return return (ret & BDRV_BLOCK_ALLOCATED);
(ret & BDRV_BLOCK_DATA) ||
((ret & BDRV_BLOCK_ZERO) && !bdrv_has_zero_init(bs));
} }
/* /*

View File

@@ -23,6 +23,7 @@
*/ */
#include "qemu-common.h" #include "qemu-common.h"
#include "block/block_int.h" #include "block/block_int.h"
#include "qapi/qmp/qbool.h"
#include <curl/curl.h> #include <curl/curl.h>
// #define DEBUG // #define DEBUG
@@ -37,6 +38,21 @@
#if LIBCURL_VERSION_NUM >= 0x071000 #if LIBCURL_VERSION_NUM >= 0x071000
/* The multi interface timer callback was introduced in 7.16.0 */ /* The multi interface timer callback was introduced in 7.16.0 */
#define NEED_CURL_TIMER_CALLBACK #define NEED_CURL_TIMER_CALLBACK
#define HAVE_SOCKET_ACTION
#endif
#ifndef HAVE_SOCKET_ACTION
/* If curl_multi_socket_action isn't available, define it statically here in
* terms of curl_multi_socket. Note that ev_bitmask will be ignored, which is
* less efficient but still safe. */
static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
curl_socket_t sockfd,
int ev_bitmask,
int *running_handles)
{
return curl_multi_socket(multi_handle, sockfd, running_handles);
}
#define curl_multi_socket_action __curl_multi_socket_action
#endif #endif
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \ #define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
@@ -46,12 +62,16 @@
#define CURL_NUM_STATES 8 #define CURL_NUM_STATES 8
#define CURL_NUM_ACB 8 #define CURL_NUM_ACB 8
#define SECTOR_SIZE 512 #define SECTOR_SIZE 512
#define READ_AHEAD_SIZE (256 * 1024) #define READ_AHEAD_DEFAULT (256 * 1024)
#define FIND_RET_NONE 0 #define FIND_RET_NONE 0
#define FIND_RET_OK 1 #define FIND_RET_OK 1
#define FIND_RET_WAIT 2 #define FIND_RET_WAIT 2
#define CURL_BLOCK_OPT_URL "url"
#define CURL_BLOCK_OPT_READAHEAD "readahead"
#define CURL_BLOCK_OPT_SSLVERIFY "sslverify"
struct BDRVCURLState; struct BDRVCURLState;
typedef struct CURLAIOCB { typedef struct CURLAIOCB {
@@ -88,6 +108,7 @@ typedef struct BDRVCURLState {
CURLState states[CURL_NUM_STATES]; CURLState states[CURL_NUM_STATES];
char *url; char *url;
size_t readahead_size; size_t readahead_size;
bool sslverify;
bool accept_range; bool accept_range;
} BDRVCURLState; } BDRVCURLState;
@@ -354,6 +375,8 @@ static CURLState *curl_init_state(BDRVCURLState *s)
return NULL; return NULL;
} }
curl_easy_setopt(state->curl, CURLOPT_URL, s->url); curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER,
(long) s->sslverify);
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5); curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
(void *)curl_read_cb); (void *)curl_read_cb);
@@ -396,43 +419,7 @@ static void curl_clean_state(CURLState *s)
static void curl_parse_filename(const char *filename, QDict *options, static void curl_parse_filename(const char *filename, QDict *options,
Error **errp) Error **errp)
{ {
qdict_put(options, CURL_BLOCK_OPT_URL, qstring_from_str(filename));
#define RA_OPTSTR ":readahead="
char *file;
char *ra;
const char *ra_val;
int parse_state = 0;
file = g_strdup(filename);
/* Parse a trailing ":readahead=#:" param, if present. */
ra = file + strlen(file) - 1;
while (ra >= file) {
if (parse_state == 0) {
if (*ra == ':') {
parse_state++;
} else {
break;
}
} else if (parse_state == 1) {
if (*ra > '9' || *ra < '0') {
char *opt_start = ra - strlen(RA_OPTSTR) + 1;
if (opt_start > file &&
strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) {
ra_val = ra + 1;
ra -= strlen(RA_OPTSTR) - 1;
*ra = '\0';
qdict_put(options, "readahead", qstring_from_str(ra_val));
}
break;
}
}
ra--;
}
qdict_put(options, "url", qstring_from_str(file));
g_free(file);
} }
static QemuOptsList runtime_opts = { static QemuOptsList runtime_opts = {
@@ -440,15 +427,20 @@ static QemuOptsList runtime_opts = {
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
.desc = { .desc = {
{ {
.name = "url", .name = CURL_BLOCK_OPT_URL,
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
.help = "URL to open", .help = "URL to open",
}, },
{ {
.name = "readahead", .name = CURL_BLOCK_OPT_READAHEAD,
.type = QEMU_OPT_SIZE, .type = QEMU_OPT_SIZE,
.help = "Readahead size", .help = "Readahead size",
}, },
{
.name = CURL_BLOCK_OPT_SSLVERIFY,
.type = QEMU_OPT_BOOL,
.help = "Verify SSL certificate"
},
{ /* end of list */ } { /* end of list */ }
}, },
}; };
@@ -477,14 +469,17 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
goto out_noclean; goto out_noclean;
} }
s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE); s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
READ_AHEAD_DEFAULT);
if ((s->readahead_size & 0x1ff) != 0) { if ((s->readahead_size & 0x1ff) != 0) {
error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512", error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
s->readahead_size); s->readahead_size);
goto out_noclean; goto out_noclean;
} }
file = qemu_opt_get(opts, "url"); s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true);
file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL);
if (file == NULL) { if (file == NULL) {
error_setg(errp, "curl block driver requires an 'url' option"); error_setg(errp, "curl block driver requires an 'url' option");
goto out_noclean; goto out_noclean;

View File

@@ -30,6 +30,8 @@
#include "qemu-common.h" #include "qemu-common.h"
#include "qemu/config-file.h" #include "qemu/config-file.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/bitops.h"
#include "qemu/bitmap.h"
#include "block/block_int.h" #include "block/block_int.h"
#include "trace.h" #include "trace.h"
#include "block/scsi.h" #include "block/scsi.h"
@@ -59,6 +61,8 @@ typedef struct IscsiLun {
struct scsi_inquiry_logical_block_provisioning lbp; struct scsi_inquiry_logical_block_provisioning lbp;
struct scsi_inquiry_block_limits bl; struct scsi_inquiry_block_limits bl;
unsigned char *zeroblock; unsigned char *zeroblock;
unsigned long *allocationmap;
int cluster_sectors;
} IscsiLun; } IscsiLun;
typedef struct IscsiTask { typedef struct IscsiTask {
@@ -92,6 +96,15 @@ typedef struct IscsiAIOCB {
#define MAX_NOP_FAILURES 3 #define MAX_NOP_FAILURES 3
#define ISCSI_CMD_RETRIES 5 #define ISCSI_CMD_RETRIES 5
/* this threshhold is a trade-off knob to choose between
* the potential additional overhead of an extra GET_LBA_STATUS request
* vs. unnecessarily reading a lot of zero sectors over the wire.
* If a read request is greater or equal than ISCSI_CHECKALLOC_THRES
* sectors we check the allocation status of the area covered by the
* request first if the allocationmap indicates that the area might be
* unallocated. */
#define ISCSI_CHECKALLOC_THRES 64
static void static void
iscsi_bh_cb(void *p) iscsi_bh_cb(void *p)
{ {
@@ -273,6 +286,32 @@ static bool is_request_lun_aligned(int64_t sector_num, int nb_sectors,
return 1; return 1;
} }
static void iscsi_allocationmap_set(IscsiLun *iscsilun, int64_t sector_num,
int nb_sectors)
{
if (iscsilun->allocationmap == NULL) {
return;
}
bitmap_set(iscsilun->allocationmap,
sector_num / iscsilun->cluster_sectors,
DIV_ROUND_UP(nb_sectors, iscsilun->cluster_sectors));
}
static void iscsi_allocationmap_clear(IscsiLun *iscsilun, int64_t sector_num,
int nb_sectors)
{
int64_t cluster_num, nb_clusters;
if (iscsilun->allocationmap == NULL) {
return;
}
cluster_num = DIV_ROUND_UP(sector_num, iscsilun->cluster_sectors);
nb_clusters = (sector_num + nb_sectors) / iscsilun->cluster_sectors
- cluster_num;
if (nb_clusters > 0) {
bitmap_clear(iscsilun->allocationmap, cluster_num, nb_clusters);
}
}
static int coroutine_fn iscsi_co_writev(BlockDriverState *bs, static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, int64_t sector_num, int nb_sectors,
QEMUIOVector *iov) QEMUIOVector *iov)
@@ -336,9 +375,125 @@ retry:
return -EIO; return -EIO;
} }
iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors);
return 0; return 0;
} }
#if defined(LIBISCSI_FEATURE_IOVECTOR)
static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun,
int64_t sector_num, int nb_sectors)
{
unsigned long size;
if (iscsilun->allocationmap == NULL) {
return true;
}
size = DIV_ROUND_UP(sector_num + nb_sectors, iscsilun->cluster_sectors);
return !(find_next_bit(iscsilun->allocationmap, size,
sector_num / iscsilun->cluster_sectors) == size);
}
static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
int64_t sector_num,
int nb_sectors, int *pnum)
{
IscsiLun *iscsilun = bs->opaque;
struct scsi_get_lba_status *lbas = NULL;
struct scsi_lba_status_descriptor *lbasd = NULL;
struct IscsiTask iTask;
int64_t ret;
iscsi_co_init_iscsitask(iscsilun, &iTask);
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
ret = -EINVAL;
goto out;
}
/* default to all sectors allocated */
ret = BDRV_BLOCK_DATA;
ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID;
*pnum = nb_sectors;
/* LUN does not support logical block provisioning */
if (iscsilun->lbpme == 0) {
goto out;
}
retry:
if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
sector_qemu2lun(sector_num, iscsilun),
8 + 16, iscsi_co_generic_cb,
&iTask) == NULL) {
ret = -ENOMEM;
goto out;
}
while (!iTask.complete) {
iscsi_set_events(iscsilun);
qemu_coroutine_yield();
}
if (iTask.do_retry) {
if (iTask.task != NULL) {
scsi_free_scsi_task(iTask.task);
iTask.task = NULL;
}
iTask.complete = 0;
goto retry;
}
if (iTask.status != SCSI_STATUS_GOOD) {
/* in case the get_lba_status_callout fails (i.e.
* because the device is busy or the cmd is not
* supported) we pretend all blocks are allocated
* for backwards compatibility */
goto out;
}
lbas = scsi_datain_unmarshall(iTask.task);
if (lbas == NULL) {
ret = -EIO;
goto out;
}
lbasd = &lbas->descriptors[0];
if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
ret = -EIO;
goto out;
}
*pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED ||
lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) {
ret &= ~BDRV_BLOCK_DATA;
if (iscsilun->lbprz) {
ret |= BDRV_BLOCK_ZERO;
}
}
if (ret & BDRV_BLOCK_ZERO) {
iscsi_allocationmap_clear(iscsilun, sector_num, *pnum);
} else {
iscsi_allocationmap_set(iscsilun, sector_num, *pnum);
}
if (*pnum > nb_sectors) {
*pnum = nb_sectors;
}
out:
if (iTask.task != NULL) {
scsi_free_scsi_task(iTask.task);
}
return ret;
}
#endif /* LIBISCSI_FEATURE_IOVECTOR */
static int coroutine_fn iscsi_co_readv(BlockDriverState *bs, static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, int64_t sector_num, int nb_sectors,
QEMUIOVector *iov) QEMUIOVector *iov)
@@ -355,6 +510,22 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
return -EINVAL; return -EINVAL;
} }
#if defined(LIBISCSI_FEATURE_IOVECTOR)
if (iscsilun->lbprz && nb_sectors >= ISCSI_CHECKALLOC_THRES &&
!iscsi_allocationmap_is_allocated(iscsilun, sector_num, nb_sectors)) {
int64_t ret;
int pnum;
ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum);
if (ret < 0) {
return ret;
}
if (ret & BDRV_BLOCK_ZERO && pnum >= nb_sectors) {
qemu_iovec_memset(iov, 0, 0x00, iov->size);
return 0;
}
}
#endif
lba = sector_qemu2lun(sector_num, iscsilun); lba = sector_qemu2lun(sector_num, iscsilun);
num_sectors = sector_qemu2lun(nb_sectors, iscsilun); num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
@@ -643,101 +814,6 @@ iscsi_getlength(BlockDriverState *bs)
return len; return len;
} }
#if defined(LIBISCSI_FEATURE_IOVECTOR)
static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
int64_t sector_num,
int nb_sectors, int *pnum)
{
IscsiLun *iscsilun = bs->opaque;
struct scsi_get_lba_status *lbas = NULL;
struct scsi_lba_status_descriptor *lbasd = NULL;
struct IscsiTask iTask;
int64_t ret;
iscsi_co_init_iscsitask(iscsilun, &iTask);
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
ret = -EINVAL;
goto out;
}
/* default to all sectors allocated */
ret = BDRV_BLOCK_DATA;
ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID;
*pnum = nb_sectors;
/* LUN does not support logical block provisioning */
if (iscsilun->lbpme == 0) {
goto out;
}
retry:
if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
sector_qemu2lun(sector_num, iscsilun),
8 + 16, iscsi_co_generic_cb,
&iTask) == NULL) {
ret = -ENOMEM;
goto out;
}
while (!iTask.complete) {
iscsi_set_events(iscsilun);
qemu_coroutine_yield();
}
if (iTask.do_retry) {
if (iTask.task != NULL) {
scsi_free_scsi_task(iTask.task);
iTask.task = NULL;
}
iTask.complete = 0;
goto retry;
}
if (iTask.status != SCSI_STATUS_GOOD) {
/* in case the get_lba_status_callout fails (i.e.
* because the device is busy or the cmd is not
* supported) we pretend all blocks are allocated
* for backwards compatibility */
goto out;
}
lbas = scsi_datain_unmarshall(iTask.task);
if (lbas == NULL) {
ret = -EIO;
goto out;
}
lbasd = &lbas->descriptors[0];
if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
ret = -EIO;
goto out;
}
*pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
if (*pnum > nb_sectors) {
*pnum = nb_sectors;
}
if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED ||
lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) {
ret &= ~BDRV_BLOCK_DATA;
if (iscsilun->lbprz) {
ret |= BDRV_BLOCK_ZERO;
}
}
out:
if (iTask.task != NULL) {
scsi_free_scsi_task(iTask.task);
}
return ret;
}
#endif /* LIBISCSI_FEATURE_IOVECTOR */
static int static int
coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num, coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num,
int nb_sectors) int nb_sectors)
@@ -791,6 +867,8 @@ retry:
return -EIO; return -EIO;
} }
iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors);
return 0; return 0;
} }
@@ -809,13 +887,14 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
return -EINVAL; return -EINVAL;
} }
if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) { if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) {
/* WRITE SAME without UNMAP is not supported by the target */ /* WRITE SAME with UNMAP is not supported by the target,
return -ENOTSUP; * fall back and try WRITE SAME without UNMAP */
flags &= ~BDRV_REQ_MAY_UNMAP;
} }
if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) { if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) {
/* WRITE SAME with UNMAP is not supported by the target */ /* WRITE SAME without UNMAP is not supported by the target */
return -ENOTSUP; return -ENOTSUP;
} }
@@ -864,6 +943,12 @@ retry:
return -EIO; return -EIO;
} }
if (flags & BDRV_REQ_MAY_UNMAP) {
iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors);
} else {
iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors);
}
return 0; return 0;
} }
@@ -1295,6 +1380,22 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL); timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
#endif #endif
/* Guess the internal cluster (page) size of the iscsi target by the means
* of opt_unmap_gran. Transfer the unmap granularity only if it has a
* reasonable size */
if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 4 * 1024 &&
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
iscsilun->cluster_sectors = (iscsilun->bl.opt_unmap_gran *
iscsilun->block_size) >> BDRV_SECTOR_BITS;
#if defined(LIBISCSI_FEATURE_IOVECTOR)
if (iscsilun->lbprz && !(bs->open_flags & BDRV_O_NOCACHE)) {
iscsilun->allocationmap =
bitmap_new(DIV_ROUND_UP(bs->total_sectors,
iscsilun->cluster_sectors));
}
#endif
}
out: out:
qemu_opts_del(opts); qemu_opts_del(opts);
if (initiator_name != NULL) { if (initiator_name != NULL) {
@@ -1328,6 +1429,7 @@ static void iscsi_close(BlockDriverState *bs)
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL); qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL);
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
g_free(iscsilun->zeroblock); g_free(iscsilun->zeroblock);
g_free(iscsilun->allocationmap);
memset(iscsilun, 0, sizeof(IscsiLun)); memset(iscsilun, 0, sizeof(IscsiLun));
} }
@@ -1388,6 +1490,13 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
return -EINVAL; return -EINVAL;
} }
if (iscsilun->allocationmap != NULL) {
g_free(iscsilun->allocationmap);
iscsilun->allocationmap =
bitmap_new(DIV_ROUND_UP(bs->total_sectors,
iscsilun->cluster_sectors));
}
return 0; return 0;
} }
@@ -1450,13 +1559,7 @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
IscsiLun *iscsilun = bs->opaque; IscsiLun *iscsilun = bs->opaque;
bdi->unallocated_blocks_are_zero = !!iscsilun->lbprz; bdi->unallocated_blocks_are_zero = !!iscsilun->lbprz;
bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws; bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws;
/* Guess the internal cluster (page) size of the iscsi target by the means bdi->cluster_size = iscsilun->cluster_sectors * BDRV_SECTOR_SIZE;
* of opt_unmap_gran. Transfer the unmap granularity only if it has a
* reasonable size for bdi->cluster_size */
if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 64 * 1024 &&
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
bdi->cluster_size = iscsilun->bl.opt_unmap_gran * iscsilun->block_size;
}
return 0; return 0;
} }

View File

@@ -50,6 +50,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
} }
info->backing_file_depth = bdrv_get_backing_file_depth(bs); info->backing_file_depth = bdrv_get_backing_file_depth(bs);
info->detect_zeroes = bs->detect_zeroes;
if (bs->io_limits_enabled) { if (bs->io_limits_enabled) {
ThrottleConfig cfg; ThrottleConfig cfg;

View File

@@ -48,9 +48,10 @@ typedef struct QCowHeader {
uint64_t size; /* in bytes */ uint64_t size; /* in bytes */
uint8_t cluster_bits; uint8_t cluster_bits;
uint8_t l2_bits; uint8_t l2_bits;
uint16_t padding;
uint32_t crypt_method; uint32_t crypt_method;
uint64_t l1_table_offset; uint64_t l1_table_offset;
} QCowHeader; } QEMU_PACKED QCowHeader;
#define L2_CACHE_SIZE 16 #define L2_CACHE_SIZE 16
@@ -60,7 +61,7 @@ typedef struct BDRVQcowState {
int cluster_sectors; int cluster_sectors;
int l2_bits; int l2_bits;
int l2_size; int l2_size;
int l1_size; unsigned int l1_size;
uint64_t cluster_offset_mask; uint64_t cluster_offset_mask;
uint64_t l1_table_offset; uint64_t l1_table_offset;
uint64_t *l1_table; uint64_t *l1_table;
@@ -96,7 +97,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp) Error **errp)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcowState *s = bs->opaque;
int len, i, shift, ret; unsigned int len, i, shift;
int ret;
QCowHeader header; QCowHeader header;
ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
@@ -127,11 +129,25 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
goto fail; goto fail;
} }
if (header.size <= 1 || header.cluster_bits < 9) { if (header.size <= 1) {
error_setg(errp, "invalid value in qcow header"); error_setg(errp, "Image size is too small (must be at least 2 bytes)");
ret = -EINVAL; ret = -EINVAL;
goto fail; goto fail;
} }
if (header.cluster_bits < 9 || header.cluster_bits > 16) {
error_setg(errp, "Cluster size must be between 512 and 64k");
ret = -EINVAL;
goto fail;
}
/* l2_bits specifies number of entries; storing a uint64_t in each entry,
* so bytes = num_entries << 3. */
if (header.l2_bits < 9 - 3 || header.l2_bits > 16 - 3) {
error_setg(errp, "L2 table size must be between 512 and 64k");
ret = -EINVAL;
goto fail;
}
if (header.crypt_method > QCOW_CRYPT_AES) { if (header.crypt_method > QCOW_CRYPT_AES) {
error_setg(errp, "invalid encryption method in qcow header"); error_setg(errp, "invalid encryption method in qcow header");
ret = -EINVAL; ret = -EINVAL;
@@ -151,7 +167,19 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
/* read the level 1 table */ /* read the level 1 table */
shift = s->cluster_bits + s->l2_bits; shift = s->cluster_bits + s->l2_bits;
s->l1_size = (header.size + (1LL << shift) - 1) >> shift; if (header.size > UINT64_MAX - (1LL << shift)) {
error_setg(errp, "Image too large");
ret = -EINVAL;
goto fail;
} else {
uint64_t l1_size = (header.size + (1LL << shift) - 1) >> shift;
if (l1_size > INT_MAX / sizeof(uint64_t)) {
error_setg(errp, "Image too large");
ret = -EINVAL;
goto fail;
}
s->l1_size = l1_size;
}
s->l1_table_offset = header.l1_table_offset; s->l1_table_offset = header.l1_table_offset;
s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t)); s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
@@ -175,7 +203,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
if (header.backing_file_offset != 0) { if (header.backing_file_offset != 0) {
len = header.backing_file_size; len = header.backing_file_size;
if (len > 1023) { if (len > 1023) {
len = 1023; error_setg(errp, "Backing file name too long");
ret = -EINVAL;
goto fail;
} }
ret = bdrv_pread(bs->file, header.backing_file_offset, ret = bdrv_pread(bs->file, header.backing_file_offset,
bs->backing_file, len); bs->backing_file, len);

View File

@@ -473,7 +473,14 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
} else if (h2_seq > h1_seq) { } else if (h2_seq > h1_seq) {
s->curr_header = 1; s->curr_header = 1;
} else { } else {
goto fail; /* The Microsoft Disk2VHD tool will create 2 identical
* headers, with identical sequence numbers. If the headers are
* identical, don't consider the file corrupt */
if (!memcmp(header1, header2, sizeof(VHDXHeader))) {
s->curr_header = 0;
} else {
goto fail;
}
} }
} }

View File

@@ -288,6 +288,25 @@ static int parse_block_error_action(const char *buf, bool is_read, Error **errp)
} }
} }
static inline int parse_enum_option(const char *lookup[], const char *buf,
int max, int def, Error **errp)
{
int i;
if (!buf) {
return def;
}
for (i = 0; i < max; i++) {
if (!strcmp(buf, lookup[i])) {
return i;
}
}
error_setg(errp, "invalid parameter value: %s", buf);
return def;
}
static bool check_throttle_config(ThrottleConfig *cfg, Error **errp) static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
{ {
if (throttle_conflicting(cfg)) { if (throttle_conflicting(cfg)) {
@@ -324,6 +343,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
QemuOpts *opts; QemuOpts *opts;
const char *id; const char *id;
bool has_driver_specific_opts; bool has_driver_specific_opts;
BlockdevDetectZeroesOptions detect_zeroes;
BlockDriver *drv = NULL; BlockDriver *drv = NULL;
/* Check common options by copying from bs_opts to opts, all other options /* Check common options by copying from bs_opts to opts, all other options
@@ -452,6 +472,24 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
} }
} }
detect_zeroes =
parse_enum_option(BlockdevDetectZeroesOptions_lookup,
qemu_opt_get(opts, "detect-zeroes"),
BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
&error);
if (error) {
error_propagate(errp, error);
goto early_err;
}
if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
!(bdrv_flags & BDRV_O_UNMAP)) {
error_setg(errp, "setting detect-zeroes to unmap is not allowed "
"without setting discard operation to unmap");
goto early_err;
}
/* init */ /* init */
dinfo = g_malloc0(sizeof(*dinfo)); dinfo = g_malloc0(sizeof(*dinfo));
dinfo->id = g_strdup(qemu_opts_id(opts)); dinfo->id = g_strdup(qemu_opts_id(opts));
@@ -462,6 +500,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
} }
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0; dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
dinfo->bdrv->read_only = ro; dinfo->bdrv->read_only = ro;
dinfo->bdrv->detect_zeroes = detect_zeroes;
dinfo->refcount = 1; dinfo->refcount = 1;
if (serial != NULL) { if (serial != NULL) {
dinfo->serial = g_strdup(serial); dinfo->serial = g_strdup(serial);
@@ -2455,6 +2494,10 @@ QemuOptsList qemu_common_drive_opts = {
.name = "copy-on-read", .name = "copy-on-read",
.type = QEMU_OPT_BOOL, .type = QEMU_OPT_BOOL,
.help = "copy read data from backing file into image file", .help = "copy read data from backing file into image file",
},{
.name = "detect-zeroes",
.type = QEMU_OPT_STRING,
.help = "try to optimize zero writes (off, on, unmap)",
}, },
{ /* end of list */ } { /* end of list */ }
}, },

View File

@@ -1,3 +1,4 @@
CONFIG_VIRTIO=y CONFIG_VIRTIO=y
CONFIG_SCLPCONSOLE=y CONFIG_SCLPCONSOLE=y
CONFIG_S390_FLIC=$(CONFIG_KVM) CONFIG_S390_FLIC=y
CONFIG_S390_FLIC_KVM=$(CONFIG_KVM)

76
docs/multiseat.txt Normal file
View File

@@ -0,0 +1,76 @@
multiseat howto (with some multihead coverage)
==============================================
host side
---------
First you must compile qemu with a user interface supporting
multihead/multiseat and input event routing. Right now this list is
pretty short: sdl2.
./configure --enable-sdl --with-sdlabi=2.0
Next put together the qemu command line:
qemu -enable-kvm -usb $memory $disk $whatever \
-display sdl \
-vga std \
-device usb-tablet
That is it for the first head, which will use the standard vga, the
standard ps/2 keyboard (implicitly there) and the usb-tablet. Now the
additional switches for the second head:
-device pci-bridge,addr=12.0,chassis_nr=2,id=head.2 \
-device secondary-vga,bus=head.2,addr=02.0,id=video.2 \
-device nec-usb-xhci,bus=head.2,addr=0f.0,id=usb.2 \
-device usb-kbd,bus=usb.2.0,port=1,display=video.2 \
-device usb-tablet,bus=usb.2.0,port=2,display=video.2
This places a pci bridge in slot 12, connects a display adapter and
xhci (usb) controller to the bridge. Then it adds a usb keyboard and
usb mouse, both connected to the xhci and linked to the display.
The "display=video2" sets up the input routing. Any input coming from
the window which belongs to the video.2 display adapter will be routed
to these input devices.
guest side
----------
You need a pretty recent linux guest. systemd with loginctl. kernel
3.14+ with CONFIG_DRM_BOCHS enabled. Fedora 20 will do. Must be
fully updated for the new kernel though, i.e. the live iso doesn't cut
it.
Now we'll have to configure the guest. Boot and login. By default
all devices belong to seat0. You can use "loginctl seat-status seat0"
to list them all (and to get the sysfs paths for cut+paste). Now
we'll go assign all pci devices connected the pci bridge in slot 12 to
a new head:
loginctl attach seat-qemu \
/sys/devices/pci0000:00/0000:00:12.0/0000:01:02.0/drm/card1
loginctl attach seat-qemu \
/sys/devices/pci0000:00/0000:00:12.0/0000:01:02.0/graphics/fb1
loginctl attach seat-qemu \
/sys/devices/pci0000:00/0000:00:12.0/0000:01:0f.0/usb2
Use "loginctl seat-status seat-qemu" to check the result. It isn't
needed to assign the usb devices to the head individually, assigning a
usb (root) hub will automatically assign all usb devices connected to
it too.
BTW: loginctl writes udev rules to /etc/udev/rules.d to make these
device assignments permanent, so you need to do this only once.
Now simply restart gdm (rebooting will do too), and a login screen
should show up on the second head.
Enjoy!
--
Gerd Hoffmann <kraxel@redhat.com>

View File

@@ -48,7 +48,7 @@ The QAPI schema definitions can be modularized using the 'include' directive:
{ 'include': 'path/to/file.json'} { 'include': 'path/to/file.json'}
The directive is evaluated recursively, and include paths are relative to the The directive is evaluated recursively, and include paths are relative to the
file using the directive. file using the directive. Multiple includes of the same file are safe.
=== Complex types === === Complex types ===
@@ -230,14 +230,13 @@ node structure that can be used to chain together a list of such types in
case we want to accept/return a list of this type with a command), and a case we want to accept/return a list of this type with a command), and a
command which takes that type as a parameter and returns the same type: command which takes that type as a parameter and returns the same type:
mdroth@illuin:~/w/qemu2.git$ cat example-schema.json $ cat example-schema.json
{ 'type': 'UserDefOne', { 'type': 'UserDefOne',
'data': { 'integer': 'int', 'string': 'str' } } 'data': { 'integer': 'int', 'string': 'str' } }
{ 'command': 'my-command', { 'command': 'my-command',
'data': {'arg1': 'UserDefOne'}, 'data': {'arg1': 'UserDefOne'},
'returns': 'UserDefOne' } 'returns': 'UserDefOne' }
mdroth@illuin:~/w/qemu2.git$
=== scripts/qapi-types.py === === scripts/qapi-types.py ===
@@ -255,14 +254,25 @@ created code.
Example: Example:
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-types.py \ $ python scripts/qapi-types.py --output-dir="qapi-generated" \
--output-dir="qapi-generated" --prefix="example-" --input-file=example-schema.json --prefix="example-" --input-file=example-schema.json
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c $ cat qapi-generated/example-qapi-types.c
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ [Uninteresting stuff omitted...]
#include "qapi/qapi-dealloc-visitor.h" void qapi_free_UserDefOneList(UserDefOneList * obj)
#include "example-qapi-types.h" {
#include "example-qapi-visit.h" QapiDeallocVisitor *md;
Visitor *v;
if (!obj) {
return;
}
md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md);
visit_type_UserDefOneList(v, &obj, NULL, NULL);
qapi_dealloc_visitor_cleanup(md);
}
void qapi_free_UserDefOne(UserDefOne * obj) void qapi_free_UserDefOne(UserDefOne * obj)
{ {
@@ -279,32 +289,38 @@ Example:
qapi_dealloc_visitor_cleanup(md); qapi_dealloc_visitor_cleanup(md);
} }
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.h $ cat qapi-generated/example-qapi-types.h
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ [Uninteresting stuff omitted...]
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_TYPES
#define QAPI_GENERATED_EXAMPLE_QAPI_TYPES
#include "qapi/qapi-types-core.h" #ifndef EXAMPLE_QAPI_TYPES_H
#define EXAMPLE_QAPI_TYPES_H
[Builtin types omitted...]
typedef struct UserDefOne UserDefOne; typedef struct UserDefOne UserDefOne;
typedef struct UserDefOneList typedef struct UserDefOneList
{ {
UserDefOne *value; union {
UserDefOne *value;
uint64_t padding;
};
struct UserDefOneList *next; struct UserDefOneList *next;
} UserDefOneList; } UserDefOneList;
[Functions on builtin types omitted...]
struct UserDefOne struct UserDefOne
{ {
int64_t integer; int64_t integer;
char * string; char * string;
}; };
void qapi_free_UserDefOneList(UserDefOneList * obj);
void qapi_free_UserDefOne(UserDefOne * obj); void qapi_free_UserDefOne(UserDefOne * obj);
#endif #endif
=== scripts/qapi-visit.py === === scripts/qapi-visit.py ===
Used to generate the visitor functions used to walk through and convert Used to generate the visitor functions used to walk through and convert
@@ -325,51 +341,78 @@ $(prefix)qapi-visit.h: declarations for previously mentioned visitor
Example: Example:
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \ $ python scripts/qapi-visit.py --output-dir="qapi-generated"
--output-dir="qapi-generated" --prefix="example-" --input-file=example-schema.json --prefix="example-" --input-file=example-schema.json
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c $ cat qapi-generated/example-qapi-visit.c
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ [Uninteresting stuff omitted...]
#include "example-qapi-visit.h" static void visit_type_UserDefOne_fields(Visitor *m, UserDefOne ** obj, Error **errp)
{
Error *err = NULL;
visit_type_int(m, &(*obj)->integer, "integer", &err);
if (err) {
goto out;
}
visit_type_str(m, &(*obj)->string, "string", &err);
if (err) {
goto out;
}
out:
error_propagate(errp, err);
}
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp) void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
{ {
visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), errp); Error *err = NULL;
visit_type_int(m, (obj && *obj) ? &(*obj)->integer : NULL, "integer", errp);
visit_type_str(m, (obj && *obj) ? &(*obj)->string : NULL, "string", errp); visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), &err);
visit_end_struct(m, errp); if (!err) {
if (*obj) {
visit_type_UserDefOne_fields(m, obj, errp);
}
visit_end_struct(m, &err);
}
error_propagate(errp, err);
} }
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp) void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
{ {
GenericList *i, **prev = (GenericList **)obj; Error *err = NULL;
GenericList *i, **prev;
visit_start_list(m, name, errp); visit_start_list(m, name, &err);
if (err) {
for (; (i = visit_next_list(m, prev, errp)) != NULL; prev = &i) { goto out;
UserDefOneList *native_i = (UserDefOneList *)i;
visit_type_UserDefOne(m, &native_i->value, NULL, errp);
} }
visit_end_list(m, errp); for (prev = (GenericList **)obj;
!err && (i = visit_next_list(m, prev, &err)) != NULL;
prev = &i) {
UserDefOneList *native_i = (UserDefOneList *)i;
visit_type_UserDefOne(m, &native_i->value, NULL, &err);
}
error_propagate(errp, err);
err = NULL;
visit_end_list(m, &err);
out:
error_propagate(errp, err);
} }
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h $ python scripts/qapi-commands.py --output-dir="qapi-generated" \
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ --prefix="example-" --input-file=example-schema.json
$ cat qapi-generated/example-qapi-visit.h
[Uninteresting stuff omitted...]
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_VISIT #ifndef EXAMPLE_QAPI_VISIT_H
#define QAPI_GENERATED_EXAMPLE_QAPI_VISIT #define EXAMPLE_QAPI_VISIT_H
#include "qapi/qapi-visit-core.h" [Visitors for builtin types omitted...]
#include "example-qapi-types.h"
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp); void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp); void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
#endif #endif
mdroth@illuin:~/w/qemu2.git$
(The actual structure of the visit_type_* functions is a bit more complex
in order to propagate errors correctly and avoid leaking memory).
=== scripts/qapi-commands.py === === scripts/qapi-commands.py ===
@@ -390,77 +433,80 @@ $(prefix)qmp-commands.h: Function prototypes for the QMP commands
Example: Example:
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-marshal.c $ cat qapi-generated/example-qmp-marshal.c
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ [Uninteresting stuff omitted...]
#include "qemu-objects.h"
#include "qapi/qmp-core.h"
#include "qapi/qapi-visit-core.h"
#include "qapi/qmp-output-visitor.h"
#include "qapi/qmp-input-visitor.h"
#include "qapi/qapi-dealloc-visitor.h"
#include "example-qapi-types.h"
#include "example-qapi-visit.h"
#include "example-qmp-commands.h"
static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp) static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
{ {
QapiDeallocVisitor *md = qapi_dealloc_visitor_new(); Error *local_err = NULL;
QmpOutputVisitor *mo = qmp_output_visitor_new(); QmpOutputVisitor *mo = qmp_output_visitor_new();
QapiDeallocVisitor *md;
Visitor *v; Visitor *v;
v = qmp_output_get_visitor(mo); v = qmp_output_get_visitor(mo);
visit_type_UserDefOne(v, &ret_in, "unused", errp); visit_type_UserDefOne(v, &ret_in, "unused", &local_err);
v = qapi_dealloc_get_visitor(md); if (local_err) {
visit_type_UserDefOne(v, &ret_in, "unused", errp); goto out;
qapi_dealloc_visitor_cleanup(md); }
*ret_out = qmp_output_get_qobject(mo); *ret_out = qmp_output_get_qobject(mo);
out:
error_propagate(errp, local_err);
qmp_output_visitor_cleanup(mo);
md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md);
visit_type_UserDefOne(v, &ret_in, "unused", NULL);
qapi_dealloc_visitor_cleanup(md);
} }
static void qmp_marshal_input_my_command(QmpState *qmp__sess, QDict *args, QObject **ret, Error **errp) static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp)
{ {
Error *local_err = NULL;
UserDefOne * retval = NULL; UserDefOne * retval = NULL;
QmpInputVisitor *mi; QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
QapiDeallocVisitor *md; QapiDeallocVisitor *md;
Visitor *v; Visitor *v;
UserDefOne * arg1 = NULL; UserDefOne * arg1 = NULL;
mi = qmp_input_visitor_new(QOBJECT(args));
v = qmp_input_get_visitor(mi); v = qmp_input_get_visitor(mi);
visit_type_UserDefOne(v, &arg1, "arg1", errp); visit_type_UserDefOne(v, &arg1, "arg1", &local_err);
if (local_err) {
if (error_is_set(errp)) {
goto out; goto out;
} }
retval = qmp_my_command(arg1, errp);
qmp_marshal_output_my_command(retval, ret, errp); retval = qmp_my_command(arg1, &local_err);
if (local_err) {
goto out;
}
qmp_marshal_output_my_command(retval, ret, &local_err);
out: out:
error_propagate(errp, local_err);
qmp_input_visitor_cleanup(mi);
md = qapi_dealloc_visitor_new(); md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md); v = qapi_dealloc_get_visitor(md);
visit_type_UserDefOne(v, &arg1, "arg1", errp); visit_type_UserDefOne(v, &arg1, "arg1", NULL);
qapi_dealloc_visitor_cleanup(md); qapi_dealloc_visitor_cleanup(md);
return; return;
} }
static void qmp_init_marshal(void) static void qmp_init_marshal(void)
{ {
qmp_register_command("my-command", qmp_marshal_input_my_command); qmp_register_command("my-command", qmp_marshal_input_my_command, QCO_NO_OPTIONS);
} }
qapi_init(qmp_init_marshal); qapi_init(qmp_init_marshal);
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-commands.h $ cat qapi-generated/example-qmp-commands.h
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ [Uninteresting stuff omitted...]
#ifndef QAPI_GENERATED_EXAMPLE_QMP_COMMANDS #ifndef EXAMPLE_QMP_COMMANDS_H
#define QAPI_GENERATED_EXAMPLE_QMP_COMMANDS #define EXAMPLE_QMP_COMMANDS_H
#include "example-qapi-types.h" #include "example-qapi-types.h"
#include "error.h" #include "qapi/qmp/qdict.h"
#include "qapi/error.h"
UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp); UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
#endif #endif
mdroth@illuin:~/w/qemu2.git$

View File

@@ -556,6 +556,7 @@ ETEXI
.params = "keys [hold_ms]", .params = "keys [hold_ms]",
.help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)", .help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)",
.mhandler.cmd = hmp_send_key, .mhandler.cmd = hmp_send_key,
.command_completion = sendkey_completion,
}, },
STEXI STEXI
@@ -1233,9 +1234,10 @@ ETEXI
{ {
.name = "netdev_add", .name = "netdev_add",
.args_type = "netdev:O", .args_type = "netdev:O",
.params = "[user|tap|socket|hubport|netmap],id=str[,prop=value][,...]", .params = "[user|tap|socket|vde|bridge|hubport|netmap],id=str[,prop=value][,...]",
.help = "add host network device", .help = "add host network device",
.mhandler.cmd = hmp_netdev_add, .mhandler.cmd = hmp_netdev_add,
.command_completion = netdev_add_completion,
}, },
STEXI STEXI
@@ -1250,6 +1252,7 @@ ETEXI
.params = "id", .params = "id",
.help = "remove host network device", .help = "remove host network device",
.mhandler.cmd = hmp_netdev_del, .mhandler.cmd = hmp_netdev_del,
.command_completion = netdev_del_completion,
}, },
STEXI STEXI
@@ -1339,6 +1342,7 @@ ETEXI
.params = "name on|off", .params = "name on|off",
.help = "change the link status of a network adapter", .help = "change the link status of a network adapter",
.mhandler.cmd = hmp_set_link, .mhandler.cmd = hmp_set_link,
.command_completion = set_link_completion,
}, },
STEXI STEXI
@@ -1622,6 +1626,7 @@ ETEXI
.params = "args", .params = "args",
.help = "add chardev", .help = "add chardev",
.mhandler.cmd = hmp_chardev_add, .mhandler.cmd = hmp_chardev_add,
.command_completion = chardev_add_completion,
}, },
STEXI STEXI
@@ -1638,6 +1643,7 @@ ETEXI
.params = "id", .params = "id",
.help = "remove chardev", .help = "remove chardev",
.mhandler.cmd = hmp_chardev_remove, .mhandler.cmd = hmp_chardev_remove,
.command_completion = chardev_remove_completion,
}, },
STEXI STEXI

21
hmp.c
View File

@@ -341,6 +341,11 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
info->value->inserted->backing_file_depth); info->value->inserted->backing_file_depth);
} }
if (info->value->inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
monitor_printf(mon, " Detect zeroes: %s\n",
BlockdevDetectZeroesOptions_lookup[info->value->inserted->detect_zeroes]);
}
if (info->value->inserted->bps if (info->value->inserted->bps
|| info->value->inserted->bps_rd || info->value->inserted->bps_rd
|| info->value->inserted->bps_wr || info->value->inserted->bps_wr
@@ -1388,6 +1393,7 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict)
void hmp_object_add(Monitor *mon, const QDict *qdict) void hmp_object_add(Monitor *mon, const QDict *qdict)
{ {
Error *err = NULL; Error *err = NULL;
Error *err_end = NULL;
QemuOpts *opts; QemuOpts *opts;
char *type = NULL; char *type = NULL;
char *id = NULL; char *id = NULL;
@@ -1411,24 +1417,23 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
qdict_del(pdict, "qom-type"); qdict_del(pdict, "qom-type");
visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err); visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err);
if (err) { if (err) {
goto out_clean; goto out_end;
} }
qdict_del(pdict, "id"); qdict_del(pdict, "id");
visit_type_str(opts_get_visitor(ov), &id, "id", &err); visit_type_str(opts_get_visitor(ov), &id, "id", &err);
if (err) { if (err) {
goto out_clean; goto out_end;
} }
object_add(type, id, pdict, opts_get_visitor(ov), &err); object_add(type, id, pdict, opts_get_visitor(ov), &err);
if (err) {
goto out_clean; out_end:
} visit_end_struct(opts_get_visitor(ov), &err_end);
visit_end_struct(opts_get_visitor(ov), &err); if (!err && err_end) {
if (err) {
qmp_object_del(id, NULL); qmp_object_del(id, NULL);
} }
error_propagate(&err, err_end);
out_clean: out_clean:
opts_visitor_cleanup(ov); opts_visitor_cleanup(ov);

6
hmp.h
View File

@@ -97,5 +97,11 @@ void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
void object_del_completion(ReadLineState *rs, int nb_args, const char *str); void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
void device_add_completion(ReadLineState *rs, int nb_args, const char *str); void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
void device_del_completion(ReadLineState *rs, int nb_args, const char *str); void device_del_completion(ReadLineState *rs, int nb_args, const char *str);
void sendkey_completion(ReadLineState *rs, int nb_args, const char *str);
void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str);
void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str);
void set_link_completion(ReadLineState *rs, int nb_args, const char *str);
void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str);
void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str);
#endif #endif

View File

@@ -245,7 +245,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d)
/* update global status */ /* update global status */
if (sts & d->int_ctl) { if (sts & d->int_ctl) {
sts |= (1 << 31); sts |= (1U << 31);
} }
d->int_sts = sts; d->int_sts = sts;
@@ -257,7 +257,7 @@ static void intel_hda_update_irq(IntelHDAState *d)
int level; int level;
intel_hda_update_int_sts(d); intel_hda_update_int_sts(d);
if (d->int_sts & (1 << 31) && d->int_ctl & (1 << 31)) { if (d->int_sts & (1U << 31) && d->int_ctl & (1U << 31)) {
level = 1; level = 1;
} else { } else {
level = 0; level = 0;
@@ -574,7 +574,7 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3
if (st->ctl & 0x01) { if (st->ctl & 0x01) {
/* reset */ /* reset */
dprint(d, 1, "st #%d: reset\n", reg->stream); dprint(d, 1, "st #%d: reset\n", reg->stream);
st->ctl = 0; st->ctl = SD_STS_FIFO_READY << 24;
} }
if ((st->ctl & 0x02) != (old & 0x02)) { if ((st->ctl & 0x02) != (old & 0x02)) {
uint32_t stnr = (st->ctl >> 20) & 0x0f; uint32_t stnr = (st->ctl >> 20) & 0x0f;
@@ -829,6 +829,7 @@ static const struct IntelHDAReg regtab[] = {
.wclear = 0x1c000000, \ .wclear = 0x1c000000, \
.offset = offsetof(IntelHDAState, st[_i].ctl), \ .offset = offsetof(IntelHDAState, st[_i].ctl), \
.whandler = intel_hda_set_st_ctl, \ .whandler = intel_hda_set_st_ctl, \
.reset = SD_STS_FIFO_READY << 24 \
}, \ }, \
[ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \ [ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \
.stream = _i, \ .stream = _i, \

View File

@@ -105,70 +105,135 @@ void hid_set_next_idle(HIDState *hs)
} }
} }
static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons) static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
InputEvent *evt)
{ {
e->xdx = e->ydy = e->dz = 0; static const int bmap[INPUT_BUTTON_MAX] = {
e->buttons_state = buttons; [INPUT_BUTTON_LEFT] = 0x01,
[INPUT_BUTTON_RIGHT] = 0x02,
[INPUT_BUTTON_MIDDLE] = 0x04,
};
HIDState *hs = (HIDState *)dev;
HIDPointerEvent *e;
assert(hs->n < QUEUE_LENGTH);
e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
switch (evt->kind) {
case INPUT_EVENT_KIND_REL:
if (evt->rel->axis == INPUT_AXIS_X) {
e->xdx += evt->rel->value;
} else if (evt->rel->axis == INPUT_AXIS_Y) {
e->ydy -= evt->rel->value;
}
break;
case INPUT_EVENT_KIND_ABS:
if (evt->rel->axis == INPUT_AXIS_X) {
e->xdx = evt->rel->value;
} else if (evt->rel->axis == INPUT_AXIS_Y) {
e->ydy = evt->rel->value;
}
break;
case INPUT_EVENT_KIND_BTN:
if (evt->btn->down) {
e->buttons_state |= bmap[evt->btn->button];
if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) {
e->dz--;
} else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) {
e->dz++;
}
} else {
e->buttons_state &= ~bmap[evt->btn->button];
}
break;
default:
/* keep gcc happy */
break;
}
} }
static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel, static void hid_pointer_sync(DeviceState *dev)
int x1, int y1, int z1) { {
if (xyrel) { HIDState *hs = (HIDState *)dev;
e->xdx += x1; HIDPointerEvent *prev, *curr, *next;
e->ydy += y1; bool event_compression = false;
} else {
e->xdx = x1; if (hs->n == QUEUE_LENGTH-1) {
e->ydy = y1; /*
/* Windows drivers do not like the 0/0 position and ignore such * Queue full. We are loosing information, but we at least
* events. */ * keep track of most recent button state.
if (!(x1 | y1)) { */
e->xdx = 1; return;
}
prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK];
curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK];
if (hs->n > 0) {
/*
* No button state change between previous and current event
* (and previous wasn't seen by the guest yet), so there is
* motion information only and we can combine the two event
* into one.
*/
if (curr->buttons_state == prev->buttons_state) {
event_compression = true;
} }
} }
e->dz += z1;
}
static void hid_pointer_event(void *opaque, if (event_compression) {
int x1, int y1, int z1, int buttons_state) /* add current motion to previous, clear current */
{ if (hs->kind == HID_MOUSE) {
HIDState *hs = opaque; prev->xdx += curr->xdx;
unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK; curr->xdx = 0;
unsigned previous_slot = (use_slot - 1) & QUEUE_MASK; prev->ydy -= curr->ydy;
curr->ydy = 0;
/* We combine events where feasible to keep the queue small. We shouldn't } else {
* combine anything with the first event of a particular button state, as prev->xdx = curr->xdx;
* that would change the location of the button state change. When the prev->ydy = curr->ydy;
* queue is empty, a second event is needed because we don't know if }
* the first event changed the button state. */ prev->dz += curr->dz;
if (hs->n == QUEUE_LENGTH) { curr->dz = 0;
/* Queue full. Discard old button state, combine motion normally. */ } else {
hs->ptr.queue[use_slot].buttons_state = buttons_state; /* prepate next (clear rel, copy abs + btns) */
} else if (hs->n < 2 || if (hs->kind == HID_MOUSE) {
hs->ptr.queue[use_slot].buttons_state != buttons_state || next->xdx = 0;
hs->ptr.queue[previous_slot].buttons_state != next->ydy = 0;
hs->ptr.queue[use_slot].buttons_state) { } else {
/* Cannot or should not combine, so add an empty item to the queue. */ next->xdx = curr->xdx;
QUEUE_INCR(use_slot); next->ydy = curr->ydy;
}
next->dz = 0;
next->buttons_state = curr->buttons_state;
/* make current guest visible, notify guest */
hs->n++; hs->n++;
hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state); hs->event(hs);
} }
hid_pointer_event_combine(&hs->ptr.queue[use_slot],
hs->kind == HID_MOUSE,
x1, y1, z1);
hs->event(hs);
} }
static void hid_keyboard_event(void *opaque, int keycode) static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
InputEvent *evt)
{ {
HIDState *hs = opaque; HIDState *hs = (HIDState *)dev;
int scancodes[3], i, count;
int slot; int slot;
if (hs->n == QUEUE_LENGTH) { count = qemu_input_key_value_to_scancode(evt->key->key,
evt->key->down,
scancodes);
if (hs->n + count > QUEUE_LENGTH) {
fprintf(stderr, "usb-kbd: warning: key event queue full\n"); fprintf(stderr, "usb-kbd: warning: key event queue full\n");
return; return;
} }
slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++; for (i = 0; i < count; i++) {
hs->kbd.keycodes[slot] = keycode; slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
hs->kbd.keycodes[slot] = scancodes[i];
}
hs->event(hs); hs->event(hs);
} }
@@ -247,14 +312,14 @@ static inline int int_clamp(int val, int vmin, int vmax)
void hid_pointer_activate(HIDState *hs) void hid_pointer_activate(HIDState *hs)
{ {
if (!hs->ptr.mouse_grabbed) { if (!hs->ptr.mouse_grabbed) {
qemu_activate_mouse_event_handler(hs->ptr.eh_entry); qemu_input_handler_activate(hs->s);
hs->ptr.mouse_grabbed = 1; hs->ptr.mouse_grabbed = 1;
} }
} }
int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
{ {
int dx, dy, dz, b, l; int dx, dy, dz, l;
int index; int index;
HIDPointerEvent *e; HIDPointerEvent *e;
@@ -279,17 +344,6 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
dz = int_clamp(e->dz, -127, 127); dz = int_clamp(e->dz, -127, 127);
e->dz -= dz; e->dz -= dz;
b = 0;
if (e->buttons_state & MOUSE_EVENT_LBUTTON) {
b |= 0x01;
}
if (e->buttons_state & MOUSE_EVENT_RBUTTON) {
b |= 0x02;
}
if (e->buttons_state & MOUSE_EVENT_MBUTTON) {
b |= 0x04;
}
if (hs->n && if (hs->n &&
!e->dz && !e->dz &&
(hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) { (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
@@ -304,7 +358,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
switch (hs->kind) { switch (hs->kind) {
case HID_MOUSE: case HID_MOUSE:
if (len > l) { if (len > l) {
buf[l++] = b; buf[l++] = e->buttons_state;
} }
if (len > l) { if (len > l) {
buf[l++] = dx; buf[l++] = dx;
@@ -319,7 +373,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
case HID_TABLET: case HID_TABLET:
if (len > l) { if (len > l) {
buf[l++] = b; buf[l++] = e->buttons_state;
} }
if (len > l) { if (len > l) {
buf[l++] = dx & 0xff; buf[l++] = dx & 0xff;
@@ -413,31 +467,45 @@ void hid_reset(HIDState *hs)
void hid_free(HIDState *hs) void hid_free(HIDState *hs)
{ {
switch (hs->kind) { qemu_input_handler_unregister(hs->s);
case HID_KEYBOARD:
qemu_remove_kbd_event_handler(hs->kbd.eh_entry);
break;
case HID_MOUSE:
case HID_TABLET:
qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
break;
}
hid_del_idle_timer(hs); hid_del_idle_timer(hs);
} }
static QemuInputHandler hid_keyboard_handler = {
.name = "QEMU HID Keyboard",
.mask = INPUT_EVENT_MASK_KEY,
.event = hid_keyboard_event,
};
static QemuInputHandler hid_mouse_handler = {
.name = "QEMU HID Mouse",
.mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
.event = hid_pointer_event,
.sync = hid_pointer_sync,
};
static QemuInputHandler hid_tablet_handler = {
.name = "QEMU HID Tablet",
.mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
.event = hid_pointer_event,
.sync = hid_pointer_sync,
};
void hid_init(HIDState *hs, int kind, HIDEventFunc event) void hid_init(HIDState *hs, int kind, HIDEventFunc event)
{ {
hs->kind = kind; hs->kind = kind;
hs->event = event; hs->event = event;
if (hs->kind == HID_KEYBOARD) { if (hs->kind == HID_KEYBOARD) {
hs->kbd.eh_entry = qemu_add_kbd_event_handler(hid_keyboard_event, hs); hs->s = qemu_input_handler_register((DeviceState *)hs,
&hid_keyboard_handler);
qemu_input_handler_activate(hs->s);
} else if (hs->kind == HID_MOUSE) { } else if (hs->kind == HID_MOUSE) {
hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, hs->s = qemu_input_handler_register((DeviceState *)hs,
0, "QEMU HID Mouse"); &hid_mouse_handler);
} else if (hs->kind == HID_TABLET) { } else if (hs->kind == HID_TABLET) {
hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, hs->s = qemu_input_handler_register((DeviceState *)hs,
1, "QEMU HID Tablet"); &hid_tablet_handler);
} }
} }

View File

@@ -26,3 +26,4 @@ obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_XICS_KVM) += xics_kvm.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
obj-$(CONFIG_S390_FLIC) += s390_flic.o obj-$(CONFIG_S390_FLIC) += s390_flic.o
obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o

View File

@@ -1,322 +1,103 @@
/* /*
* QEMU S390x KVM floating interrupt controller (flic) * QEMU S390x floating interrupt controller (flic)
* *
* Copyright 2014 IBM Corp. * Copyright 2014 IBM Corp.
* Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com> * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
* Cornelia Huck <cornelia.huck@de.ibm.com>
* *
* This work is licensed under the terms of the GNU GPL, version 2 or (at * This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level * your option) any later version. See the COPYING file in the top-level
* directory. * directory.
*/ */
#include <sys/ioctl.h>
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "sysemu/kvm.h"
#include "migration/qemu-file.h" #include "migration/qemu-file.h"
#include "hw/s390x/s390_flic.h" #include "hw/s390x/s390_flic.h"
#include "trace.h" #include "trace.h"
#define FLIC_SAVE_INITIAL_SIZE getpagesize() S390FLICState *s390_get_flic(void)
#define FLIC_FAILED (-1UL) {
#define FLIC_SAVEVM_VERSION 1 S390FLICState *fs;
fs = S390_FLIC_COMMON(object_resolve_path(TYPE_KVM_S390_FLIC, NULL));
if (!fs) {
fs = S390_FLIC_COMMON(object_resolve_path(TYPE_QEMU_S390_FLIC, NULL));
}
return fs;
}
void s390_flic_init(void) void s390_flic_init(void)
{ {
DeviceState *dev; DeviceState *dev;
int r; int r;
if (kvm_enabled()) { dev = s390_flic_kvm_create();
dev = qdev_create(NULL, "s390-flic"); if (!dev) {
object_property_add_child(qdev_get_machine(), "s390-flic", dev = qdev_create(NULL, TYPE_QEMU_S390_FLIC);
OBJECT(dev), NULL); object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC,
r = qdev_init(dev); OBJECT(dev), NULL);
if (r) { }
error_report("flic: couldn't create qdev"); r = qdev_init(dev);
} if (r) {
error_report("flic: couldn't create qdev");
} }
} }
/** static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
* flic_get_all_irqs - store all pending irqs in buffer uint8_t isc, bool swap,
* @buf: pointer to buffer which is passed to kernel bool is_maskable)
* @len: length of buffer
* @flic: pointer to flic device state
*
* Returns: -ENOMEM if buffer is too small,
* -EINVAL if attr.group is invalid,
* -EFAULT if copying to userspace failed,
* on success return number of stored interrupts
*/
static int flic_get_all_irqs(KVMS390FLICState *flic,
void *buf, int len)
{ {
struct kvm_device_attr attr = { /* nothing to do */
.group = KVM_DEV_FLIC_GET_ALL_IRQS, return 0;
.addr = (uint64_t) buf,
.attr = len,
};
int rc;
rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
return rc == -1 ? -errno : rc;
} }
static void flic_enable_pfault(KVMS390FLICState *flic) static int qemu_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
uint64_t map_addr, bool do_map)
{ {
struct kvm_device_attr attr = { /* nothing to do */
.group = KVM_DEV_FLIC_APF_ENABLE, return 0;
};
int rc;
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
if (rc) {
fprintf(stderr, "flic: couldn't enable pfault\n");
}
} }
static void flic_disable_wait_pfault(KVMS390FLICState *flic) static int qemu_s390_add_adapter_routes(S390FLICState *fs,
AdapterRoutes *routes)
{ {
struct kvm_device_attr attr = { return -ENOSYS;
.group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
};
int rc;
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
if (rc) {
fprintf(stderr, "flic: couldn't disable pfault\n");
}
} }
/** flic_enqueue_irqs - returns 0 on success static void qemu_s390_release_adapter_routes(S390FLICState *fs,
* @buf: pointer to buffer which is passed to kernel AdapterRoutes *routes)
* @len: length of buffer
* @flic: pointer to flic device state
*
* Returns: -EINVAL if attr.group is unknown
*/
static int flic_enqueue_irqs(void *buf, uint64_t len,
KVMS390FLICState *flic)
{ {
int rc;
struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_ENQUEUE,
.addr = (uint64_t) buf,
.attr = len,
};
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
return rc ? -errno : 0;
} }
/** static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
* __get_all_irqs - store all pending irqs in buffer
* @flic: pointer to flic device state
* @buf: pointer to pointer to a buffer
* @len: length of buffer
*
* Returns: return value of flic_get_all_irqs
* Note: Retry and increase buffer size until flic_get_all_irqs
* either returns a value >= 0 or a negative error code.
* -ENOMEM is an exception, which means the buffer is too small
* and we should try again. Other negative error codes can be
* -EFAULT and -EINVAL which we ignore at this point
*/
static int __get_all_irqs(KVMS390FLICState *flic,
void **buf, int len)
{ {
int r; S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
do { fsc->register_io_adapter = qemu_s390_register_io_adapter;
/* returns -ENOMEM if buffer is too small and number fsc->io_adapter_map = qemu_s390_io_adapter_map;
* of queued interrupts on success */ fsc->add_adapter_routes = qemu_s390_add_adapter_routes;
r = flic_get_all_irqs(flic, *buf, len); fsc->release_adapter_routes = qemu_s390_release_adapter_routes;
if (r >= 0) {
break;
}
len *= 2;
*buf = g_try_realloc(*buf, len);
if (!buf) {
return -ENOMEM;
}
} while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
return r;
} }
/** static const TypeInfo qemu_s390_flic_info = {
* kvm_flic_save - Save pending floating interrupts .name = TYPE_QEMU_S390_FLIC,
* @f: QEMUFile containing migration state .parent = TYPE_S390_FLIC_COMMON,
* @opaque: pointer to flic device state .instance_size = sizeof(QEMUS390FLICState),
* .class_init = qemu_s390_flic_class_init,
* Note: Pass buf and len to kernel. Start with one page and
* increase until buffer is sufficient or maxium size is
* reached
*/
static void kvm_flic_save(QEMUFile *f, void *opaque)
{
KVMS390FLICState *flic = opaque;
int len = FLIC_SAVE_INITIAL_SIZE;
void *buf;
int count;
flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
buf = g_try_malloc0(len);
if (!buf) {
/* Storing FLIC_FAILED into the count field here will cause the
* target system to fail when attempting to load irqs from the
* migration state */
error_report("flic: couldn't allocate memory");
qemu_put_be64(f, FLIC_FAILED);
return;
}
count = __get_all_irqs(flic, &buf, len);
if (count < 0) {
error_report("flic: couldn't retrieve irqs from kernel, rc %d",
count);
/* Storing FLIC_FAILED into the count field here will cause the
* target system to fail when attempting to load irqs from the
* migration state */
qemu_put_be64(f, FLIC_FAILED);
} else {
qemu_put_be64(f, count);
qemu_put_buffer(f, (uint8_t *) buf,
count * sizeof(struct kvm_s390_irq));
}
g_free(buf);
}
/**
* kvm_flic_load - Load pending floating interrupts
* @f: QEMUFile containing migration state
* @opaque: pointer to flic device state
* @version_id: version id for migration
*
* Returns: value of flic_enqueue_irqs, -EINVAL on error
* Note: Do nothing when no interrupts where stored
* in QEMUFile
*/
static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
{
uint64_t len = 0;
uint64_t count = 0;
void *buf = NULL;
int r = 0;
if (version_id != FLIC_SAVEVM_VERSION) {
r = -EINVAL;
goto out;
}
flic_enable_pfault((struct KVMS390FLICState *) opaque);
count = qemu_get_be64(f);
len = count * sizeof(struct kvm_s390_irq);
if (count == FLIC_FAILED) {
r = -EINVAL;
goto out;
}
if (count == 0) {
r = 0;
goto out;
}
buf = g_try_malloc0(len);
if (!buf) {
r = -ENOMEM;
goto out;
}
if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
r = -EINVAL;
goto out_free;
}
r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
out_free:
g_free(buf);
out:
return r;
}
static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
{
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
struct kvm_create_device cd = {0};
int ret;
flic_state->fd = -1;
if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
trace_flic_no_device_api(errno);
return;
}
cd.type = KVM_DEV_TYPE_FLIC;
ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
if (ret < 0) {
trace_flic_create_device(errno);
return;
}
flic_state->fd = cd.fd;
/* Register savevm handler for floating interrupts */
register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
kvm_flic_load, (void *) flic_state);
}
static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
{
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
}
static void kvm_s390_flic_reset(DeviceState *dev)
{
KVMS390FLICState *flic = KVM_S390_FLIC(dev);
struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_CLEAR_IRQS,
};
int rc = 0;
if (flic->fd == -1) {
return;
}
flic_disable_wait_pfault(flic);
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
if (rc) {
trace_flic_reset_failed(errno);
}
flic_enable_pfault(flic);
}
static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = kvm_s390_flic_realize;
dc->unrealize = kvm_s390_flic_unrealize;
dc->reset = kvm_s390_flic_reset;
}
static const TypeInfo kvm_s390_flic_info = {
.name = TYPE_KVM_S390_FLIC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(KVMS390FLICState),
.class_init = kvm_s390_flic_class_init,
}; };
static void kvm_s390_flic_register_types(void) static const TypeInfo s390_flic_common_info = {
.name = TYPE_S390_FLIC_COMMON,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(S390FLICState),
.class_size = sizeof(S390FLICStateClass),
};
static void qemu_s390_flic_register_types(void)
{ {
type_register_static(&kvm_s390_flic_info); type_register_static(&s390_flic_common_info);
type_register_static(&qemu_s390_flic_info);
} }
type_init(kvm_s390_flic_register_types) type_init(qemu_s390_flic_register_types)

420
hw/intc/s390_flic_kvm.c Normal file
View File

@@ -0,0 +1,420 @@
/*
* QEMU S390x KVM floating interrupt controller (flic)
*
* Copyright 2014 IBM Corp.
* Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
* Cornelia Huck <cornelia.huck@de.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#include <sys/ioctl.h>
#include "qemu/error-report.h"
#include "hw/sysbus.h"
#include "sysemu/kvm.h"
#include "migration/qemu-file.h"
#include "hw/s390x/s390_flic.h"
#include "hw/s390x/adapter.h"
#include "trace.h"
#define FLIC_SAVE_INITIAL_SIZE getpagesize()
#define FLIC_FAILED (-1UL)
#define FLIC_SAVEVM_VERSION 1
typedef struct KVMS390FLICState {
S390FLICState parent_obj;
uint32_t fd;
} KVMS390FLICState;
DeviceState *s390_flic_kvm_create(void)
{
DeviceState *dev = NULL;
if (kvm_enabled()) {
dev = qdev_create(NULL, TYPE_KVM_S390_FLIC);
object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC,
OBJECT(dev), NULL);
}
return dev;
}
/**
* flic_get_all_irqs - store all pending irqs in buffer
* @buf: pointer to buffer which is passed to kernel
* @len: length of buffer
* @flic: pointer to flic device state
*
* Returns: -ENOMEM if buffer is too small,
* -EINVAL if attr.group is invalid,
* -EFAULT if copying to userspace failed,
* on success return number of stored interrupts
*/
static int flic_get_all_irqs(KVMS390FLICState *flic,
void *buf, int len)
{
struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_GET_ALL_IRQS,
.addr = (uint64_t) buf,
.attr = len,
};
int rc;
rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
return rc == -1 ? -errno : rc;
}
static void flic_enable_pfault(KVMS390FLICState *flic)
{
struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_APF_ENABLE,
};
int rc;
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
if (rc) {
fprintf(stderr, "flic: couldn't enable pfault\n");
}
}
static void flic_disable_wait_pfault(KVMS390FLICState *flic)
{
struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
};
int rc;
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
if (rc) {
fprintf(stderr, "flic: couldn't disable pfault\n");
}
}
/** flic_enqueue_irqs - returns 0 on success
* @buf: pointer to buffer which is passed to kernel
* @len: length of buffer
* @flic: pointer to flic device state
*
* Returns: -EINVAL if attr.group is unknown
*/
static int flic_enqueue_irqs(void *buf, uint64_t len,
KVMS390FLICState *flic)
{
int rc;
struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_ENQUEUE,
.addr = (uint64_t) buf,
.attr = len,
};
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
return rc ? -errno : 0;
}
/**
* __get_all_irqs - store all pending irqs in buffer
* @flic: pointer to flic device state
* @buf: pointer to pointer to a buffer
* @len: length of buffer
*
* Returns: return value of flic_get_all_irqs
* Note: Retry and increase buffer size until flic_get_all_irqs
* either returns a value >= 0 or a negative error code.
* -ENOMEM is an exception, which means the buffer is too small
* and we should try again. Other negative error codes can be
* -EFAULT and -EINVAL which we ignore at this point
*/
static int __get_all_irqs(KVMS390FLICState *flic,
void **buf, int len)
{
int r;
do {
/* returns -ENOMEM if buffer is too small and number
* of queued interrupts on success */
r = flic_get_all_irqs(flic, *buf, len);
if (r >= 0) {
break;
}
len *= 2;
*buf = g_try_realloc(*buf, len);
if (!buf) {
return -ENOMEM;
}
} while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
return r;
}
static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
uint8_t isc, bool swap,
bool is_maskable)
{
struct kvm_s390_io_adapter adapter = {
.id = id,
.isc = isc,
.maskable = is_maskable,
.swap = swap,
};
KVMS390FLICState *flic = KVM_S390_FLIC(fs);
int r, ret;
struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_ADAPTER_REGISTER,
.addr = (uint64_t)&adapter,
};
if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) {
return -ENOSYS;
}
r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
ret = r ? -errno : 0;
return ret;
}
static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
uint64_t map_addr, bool do_map)
{
struct kvm_s390_io_adapter_req req = {
.id = id,
.type = do_map ? KVM_S390_IO_ADAPTER_MAP : KVM_S390_IO_ADAPTER_UNMAP,
.addr = map_addr,
};
struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_ADAPTER_MODIFY,
.addr = (uint64_t)&req,
};
KVMS390FLICState *flic = KVM_S390_FLIC(fs);
int r;
if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) {
return -ENOSYS;
}
r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
return r ? -errno : 0;
}
static int kvm_s390_add_adapter_routes(S390FLICState *fs,
AdapterRoutes *routes)
{
int ret, i;
uint64_t ind_offset = routes->adapter.ind_offset;
for (i = 0; i < routes->num_routes; i++) {
ret = kvm_irqchip_add_adapter_route(kvm_state, &routes->adapter);
if (ret < 0) {
goto out_undo;
}
routes->gsi[i] = ret;
routes->adapter.ind_offset++;
}
/* Restore passed-in structure to original state. */
routes->adapter.ind_offset = ind_offset;
return 0;
out_undo:
while (--i >= 0) {
kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
routes->gsi[i] = -1;
}
routes->adapter.ind_offset = ind_offset;
return ret;
}
static void kvm_s390_release_adapter_routes(S390FLICState *fs,
AdapterRoutes *routes)
{
int i;
for (i = 0; i < routes->num_routes; i++) {
if (routes->gsi[i] >= 0) {
kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
routes->gsi[i] = -1;
}
}
}
/**
* kvm_flic_save - Save pending floating interrupts
* @f: QEMUFile containing migration state
* @opaque: pointer to flic device state
*
* Note: Pass buf and len to kernel. Start with one page and
* increase until buffer is sufficient or maxium size is
* reached
*/
static void kvm_flic_save(QEMUFile *f, void *opaque)
{
KVMS390FLICState *flic = opaque;
int len = FLIC_SAVE_INITIAL_SIZE;
void *buf;
int count;
flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
buf = g_try_malloc0(len);
if (!buf) {
/* Storing FLIC_FAILED into the count field here will cause the
* target system to fail when attempting to load irqs from the
* migration state */
error_report("flic: couldn't allocate memory");
qemu_put_be64(f, FLIC_FAILED);
return;
}
count = __get_all_irqs(flic, &buf, len);
if (count < 0) {
error_report("flic: couldn't retrieve irqs from kernel, rc %d",
count);
/* Storing FLIC_FAILED into the count field here will cause the
* target system to fail when attempting to load irqs from the
* migration state */
qemu_put_be64(f, FLIC_FAILED);
} else {
qemu_put_be64(f, count);
qemu_put_buffer(f, (uint8_t *) buf,
count * sizeof(struct kvm_s390_irq));
}
g_free(buf);
}
/**
* kvm_flic_load - Load pending floating interrupts
* @f: QEMUFile containing migration state
* @opaque: pointer to flic device state
* @version_id: version id for migration
*
* Returns: value of flic_enqueue_irqs, -EINVAL on error
* Note: Do nothing when no interrupts where stored
* in QEMUFile
*/
static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
{
uint64_t len = 0;
uint64_t count = 0;
void *buf = NULL;
int r = 0;
if (version_id != FLIC_SAVEVM_VERSION) {
r = -EINVAL;
goto out;
}
flic_enable_pfault((struct KVMS390FLICState *) opaque);
count = qemu_get_be64(f);
len = count * sizeof(struct kvm_s390_irq);
if (count == FLIC_FAILED) {
r = -EINVAL;
goto out;
}
if (count == 0) {
r = 0;
goto out;
}
buf = g_try_malloc0(len);
if (!buf) {
r = -ENOMEM;
goto out;
}
if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
r = -EINVAL;
goto out_free;
}
r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
out_free:
g_free(buf);
out:
return r;
}
static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
{
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
struct kvm_create_device cd = {0};
int ret;
flic_state->fd = -1;
if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
trace_flic_no_device_api(errno);
return;
}
cd.type = KVM_DEV_TYPE_FLIC;
ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
if (ret < 0) {
trace_flic_create_device(errno);
return;
}
flic_state->fd = cd.fd;
/* Register savevm handler for floating interrupts */
register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
kvm_flic_load, (void *) flic_state);
}
static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
{
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
}
static void kvm_s390_flic_reset(DeviceState *dev)
{
KVMS390FLICState *flic = KVM_S390_FLIC(dev);
struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_CLEAR_IRQS,
};
int rc = 0;
if (flic->fd == -1) {
return;
}
flic_disable_wait_pfault(flic);
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
if (rc) {
trace_flic_reset_failed(errno);
}
flic_enable_pfault(flic);
}
static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
dc->realize = kvm_s390_flic_realize;
dc->unrealize = kvm_s390_flic_unrealize;
dc->reset = kvm_s390_flic_reset;
fsc->register_io_adapter = kvm_s390_register_io_adapter;
fsc->io_adapter_map = kvm_s390_io_adapter_map;
fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
}
static const TypeInfo kvm_s390_flic_info = {
.name = TYPE_KVM_S390_FLIC,
.parent = TYPE_S390_FLIC_COMMON,
.instance_size = sizeof(KVMS390FLICState),
.class_init = kvm_s390_flic_class_init,
};
static void kvm_s390_flic_register_types(void)
{
type_register_static(&kvm_s390_flic_info);
}
type_init(kvm_s390_flic_register_types)

View File

@@ -16,6 +16,7 @@
#include "ioinst.h" #include "ioinst.h"
#include "css.h" #include "css.h"
#include "trace.h" #include "trace.h"
#include "hw/s390x/s390_flic.h"
typedef struct CrwContainer { typedef struct CrwContainer {
CRW crw; CRW crw;
@@ -39,6 +40,13 @@ typedef struct CssImage {
ChpInfo chpids[MAX_CHPID + 1]; ChpInfo chpids[MAX_CHPID + 1];
} CssImage; } CssImage;
typedef struct IoAdapter {
uint32_t id;
uint8_t type;
uint8_t isc;
QTAILQ_ENTRY(IoAdapter) sibling;
} IoAdapter;
typedef struct ChannelSubSys { typedef struct ChannelSubSys {
QTAILQ_HEAD(, CrwContainer) pending_crws; QTAILQ_HEAD(, CrwContainer) pending_crws;
bool do_crw_mchk; bool do_crw_mchk;
@@ -49,6 +57,7 @@ typedef struct ChannelSubSys {
uint64_t chnmon_area; uint64_t chnmon_area;
CssImage *css[MAX_CSSID + 1]; CssImage *css[MAX_CSSID + 1];
uint8_t default_cssid; uint8_t default_cssid;
QTAILQ_HEAD(, IoAdapter) io_adapters;
} ChannelSubSys; } ChannelSubSys;
static ChannelSubSys *channel_subsys; static ChannelSubSys *channel_subsys;
@@ -69,6 +78,46 @@ int css_create_css_image(uint8_t cssid, bool default_image)
return 0; return 0;
} }
int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap,
bool maskable, uint32_t *id)
{
IoAdapter *adapter;
bool found = false;
int ret;
S390FLICState *fs = s390_get_flic();
S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
*id = 0;
QTAILQ_FOREACH(adapter, &channel_subsys->io_adapters, sibling) {
if ((adapter->type == type) && (adapter->isc == isc)) {
*id = adapter->id;
found = true;
ret = 0;
break;
}
if (adapter->id >= *id) {
*id = adapter->id + 1;
}
}
if (found) {
goto out;
}
adapter = g_new0(IoAdapter, 1);
ret = fsc->register_io_adapter(fs, *id, isc, swap, maskable);
if (ret == 0) {
adapter->id = *id;
adapter->isc = isc;
adapter->type = type;
QTAILQ_INSERT_TAIL(&channel_subsys->io_adapters, adapter, sibling);
} else {
g_free(adapter);
fprintf(stderr, "Unexpected error %d when registering adapter %d\n",
ret, *id);
}
out:
return ret;
}
uint16_t css_build_subchannel_id(SubchDev *sch) uint16_t css_build_subchannel_id(SubchDev *sch)
{ {
if (channel_subsys->max_cssid > 0) { if (channel_subsys->max_cssid > 0) {
@@ -1235,6 +1284,7 @@ static void css_init(void)
channel_subsys->do_crw_mchk = true; channel_subsys->do_crw_mchk = true;
channel_subsys->crws_lost = false; channel_subsys->crws_lost = false;
channel_subsys->chnmon_active = false; channel_subsys->chnmon_active = false;
QTAILQ_INIT(&channel_subsys->io_adapters);
} }
machine_init(css_init); machine_init(css_init);

View File

@@ -98,4 +98,8 @@ void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
int hotplugged, int add); int hotplugged, int add);
void css_generate_chp_crws(uint8_t cssid, uint8_t chpid); void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
void css_adapter_interrupt(uint8_t isc); void css_adapter_interrupt(uint8_t isc);
#define CSS_IO_ADAPTER_VIRTIO 1
int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap,
bool maskable, uint32_t *id);
#endif #endif

View File

@@ -21,12 +21,77 @@
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "qemu/bitops.h" #include "qemu/bitops.h"
#include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-bus.h"
#include "hw/s390x/adapter.h"
#include "hw/s390x/s390_flic.h"
#include "ioinst.h" #include "ioinst.h"
#include "css.h" #include "css.h"
#include "virtio-ccw.h" #include "virtio-ccw.h"
#include "trace.h" #include "trace.h"
static QTAILQ_HEAD(, IndAddr) indicator_addresses =
QTAILQ_HEAD_INITIALIZER(indicator_addresses);
static IndAddr *get_indicator(hwaddr ind_addr, int len)
{
IndAddr *indicator;
QTAILQ_FOREACH(indicator, &indicator_addresses, sibling) {
if (indicator->addr == ind_addr) {
indicator->refcnt++;
return indicator;
}
}
indicator = g_new0(IndAddr, 1);
indicator->addr = ind_addr;
indicator->len = len;
indicator->refcnt = 1;
QTAILQ_INSERT_TAIL(&indicator_addresses, indicator, sibling);
return indicator;
}
static int s390_io_adapter_map(AdapterInfo *adapter, uint64_t map_addr,
bool do_map)
{
S390FLICState *fs = s390_get_flic();
S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
return fsc->io_adapter_map(fs, adapter->adapter_id, map_addr, do_map);
}
static void release_indicator(AdapterInfo *adapter, IndAddr *indicator)
{
assert(indicator->refcnt > 0);
indicator->refcnt--;
if (indicator->refcnt > 0) {
return;
}
QTAILQ_REMOVE(&indicator_addresses, indicator, sibling);
if (indicator->map) {
s390_io_adapter_map(adapter, indicator->map, false);
}
g_free(indicator);
}
static int map_indicator(AdapterInfo *adapter, IndAddr *indicator)
{
int ret;
if (indicator->map) {
return 0; /* already mapped is not an error */
}
indicator->map = indicator->addr;
ret = s390_io_adapter_map(adapter, indicator->map, true);
if ((ret != 0) && (ret != -ENOSYS)) {
goto out_err;
}
return 0;
out_err:
indicator->map = 0;
return ret;
}
static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size, static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size,
VirtioCcwDevice *dev); VirtioCcwDevice *dev);
@@ -445,7 +510,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = -EFAULT; ret = -EFAULT;
} else { } else {
indicators = ldq_phys(&address_space_memory, ccw.cda); indicators = ldq_phys(&address_space_memory, ccw.cda);
dev->indicators = indicators; dev->indicators = get_indicator(indicators, sizeof(uint64_t));
sch->curr_status.scsw.count = ccw.count - sizeof(indicators); sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
ret = 0; ret = 0;
} }
@@ -465,7 +530,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = -EFAULT; ret = -EFAULT;
} else { } else {
indicators = ldq_phys(&address_space_memory, ccw.cda); indicators = ldq_phys(&address_space_memory, ccw.cda);
dev->indicators2 = indicators; dev->indicators2 = get_indicator(indicators, sizeof(uint64_t));
sch->curr_status.scsw.count = ccw.count - sizeof(indicators); sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
ret = 0; ret = 0;
} }
@@ -517,13 +582,20 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = -EFAULT; ret = -EFAULT;
} else { } else {
len = hw_len; len = hw_len;
dev->summary_indicator = thinint->summary_indicator; dev->summary_indicator =
dev->indicators = thinint->device_indicator; get_indicator(thinint->summary_indicator, sizeof(uint8_t));
dev->indicators = get_indicator(thinint->device_indicator,
thinint->ind_bit / 8 + 1);
dev->thinint_isc = thinint->isc; dev->thinint_isc = thinint->isc;
dev->ind_bit = thinint->ind_bit; dev->routes.adapter.ind_offset = thinint->ind_bit;
dev->routes.adapter.summary_offset = 7;
cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len); cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len);
sch->thinint_active = ((dev->indicators != 0) && ret = css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO,
(dev->summary_indicator != 0)); dev->thinint_isc, true, false,
&dev->routes.adapter.adapter_id);
assert(ret == 0);
sch->thinint_active = ((dev->indicators != NULL) &&
(dev->summary_indicator != NULL));
sch->curr_status.scsw.count = ccw.count - len; sch->curr_status.scsw.count = ccw.count - len;
ret = 0; ret = 0;
} }
@@ -554,7 +626,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
sch->driver_data = dev; sch->driver_data = dev;
dev->sch = sch; dev->sch = sch;
dev->indicators = 0; dev->indicators = NULL;
/* Initialize subchannel structure. */ /* Initialize subchannel structure. */
sch->channel_prog = 0x0; sch->channel_prog = 0x0;
@@ -693,7 +765,10 @@ static int virtio_ccw_exit(VirtioCcwDevice *dev)
css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
g_free(sch); g_free(sch);
} }
dev->indicators = 0; if (dev->indicators) {
release_indicator(&dev->routes.adapter, dev->indicators);
dev->indicators = NULL;
}
return 0; return 0;
} }
@@ -950,17 +1025,19 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
* ind_bit indicates the start of the indicators in a big * ind_bit indicates the start of the indicators in a big
* endian notation. * endian notation.
*/ */
virtio_set_ind_atomic(sch, dev->indicators + uint64_t ind_bit = dev->routes.adapter.ind_offset;
(dev->ind_bit + vector) / 8,
0x80 >> ((dev->ind_bit + vector) % 8)); virtio_set_ind_atomic(sch, dev->indicators->addr +
if (!virtio_set_ind_atomic(sch, dev->summary_indicator, (ind_bit + vector) / 8,
0x80 >> ((ind_bit + vector) % 8));
if (!virtio_set_ind_atomic(sch, dev->summary_indicator->addr,
0x01)) { 0x01)) {
css_adapter_interrupt(dev->thinint_isc); css_adapter_interrupt(dev->thinint_isc);
} }
} else { } else {
indicators = ldq_phys(&address_space_memory, dev->indicators); indicators = ldq_phys(&address_space_memory, dev->indicators->addr);
indicators |= 1ULL << vector; indicators |= 1ULL << vector;
stq_phys(&address_space_memory, dev->indicators, indicators); stq_phys(&address_space_memory, dev->indicators->addr, indicators);
css_conditional_io_interrupt(sch); css_conditional_io_interrupt(sch);
} }
} else { } else {
@@ -968,9 +1045,9 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
return; return;
} }
vector = 0; vector = 0;
indicators = ldq_phys(&address_space_memory, dev->indicators2); indicators = ldq_phys(&address_space_memory, dev->indicators2->addr);
indicators |= 1ULL << vector; indicators |= 1ULL << vector;
stq_phys(&address_space_memory, dev->indicators2, indicators); stq_phys(&address_space_memory, dev->indicators2->addr, indicators);
css_conditional_io_interrupt(sch); css_conditional_io_interrupt(sch);
} }
} }
@@ -991,9 +1068,18 @@ static void virtio_ccw_reset(DeviceState *d)
virtio_ccw_stop_ioeventfd(dev); virtio_ccw_stop_ioeventfd(dev);
virtio_reset(vdev); virtio_reset(vdev);
css_reset_sch(dev->sch); css_reset_sch(dev->sch);
dev->indicators = 0; if (dev->indicators) {
dev->indicators2 = 0; release_indicator(&dev->routes.adapter, dev->indicators);
dev->summary_indicator = 0; dev->indicators = NULL;
}
if (dev->indicators2) {
release_indicator(&dev->routes.adapter, dev->indicators2);
dev->indicators2 = NULL;
}
if (dev->summary_indicator) {
release_indicator(&dev->routes.adapter, dev->summary_indicator);
dev->summary_indicator = NULL;
}
} }
static void virtio_ccw_vmstate_change(DeviceState *d, bool running) static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
@@ -1027,6 +1113,79 @@ static int virtio_ccw_set_host_notifier(DeviceState *d, int n, bool assign)
return virtio_ccw_set_guest2host_notifier(dev, n, assign, false); return virtio_ccw_set_guest2host_notifier(dev, n, assign, false);
} }
static int virtio_ccw_get_mappings(VirtioCcwDevice *dev)
{
int r;
if (!dev->sch->thinint_active) {
return -EINVAL;
}
r = map_indicator(&dev->routes.adapter, dev->summary_indicator);
if (r) {
return r;
}
r = map_indicator(&dev->routes.adapter, dev->indicators);
if (r) {
return r;
}
dev->routes.adapter.summary_addr = dev->summary_indicator->map;
dev->routes.adapter.ind_addr = dev->indicators->map;
return 0;
}
static int virtio_ccw_setup_irqroutes(VirtioCcwDevice *dev, int nvqs)
{
int i;
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
int ret;
S390FLICState *fs = s390_get_flic();
S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
ret = virtio_ccw_get_mappings(dev);
if (ret) {
return ret;
}
for (i = 0; i < nvqs; i++) {
if (!virtio_queue_get_num(vdev, i)) {
break;
}
}
dev->routes.num_routes = i;
return fsc->add_adapter_routes(fs, &dev->routes);
}
static void virtio_ccw_release_irqroutes(VirtioCcwDevice *dev, int nvqs)
{
S390FLICState *fs = s390_get_flic();
S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
fsc->release_adapter_routes(fs, &dev->routes);
}
static int virtio_ccw_add_irqfd(VirtioCcwDevice *dev, int n)
{
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
VirtQueue *vq = virtio_get_queue(vdev, n);
EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
return kvm_irqchip_add_irqfd_notifier(kvm_state, notifier, NULL,
dev->routes.gsi[n]);
}
static void virtio_ccw_remove_irqfd(VirtioCcwDevice *dev, int n)
{
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
VirtQueue *vq = virtio_get_queue(vdev, n);
EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
int ret;
ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, notifier,
dev->routes.gsi[n]);
assert(ret == 0);
}
static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n, static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
bool assign, bool with_irqfd) bool assign, bool with_irqfd)
{ {
@@ -1042,11 +1201,17 @@ static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
return r; return r;
} }
virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
/* We do not support irqfd for classic I/O interrupts, because the if (with_irqfd) {
* classic interrupts are intermixed with the subchannel status, that r = virtio_ccw_add_irqfd(dev, n);
* is queried with test subchannel. We want to use vhost, though. if (r) {
* Lets make sure to have vhost running and wire up the irq fd to virtio_queue_set_guest_notifier_fd_handler(vq, false,
* land in qemu (and only the irq fd) in this code. with_irqfd);
return r;
}
}
/*
* We do not support individual masking for channel devices, so we
* need to manually trigger any guest masking callbacks here.
*/ */
if (k->guest_notifier_mask) { if (k->guest_notifier_mask) {
k->guest_notifier_mask(vdev, n, false); k->guest_notifier_mask(vdev, n, false);
@@ -1060,6 +1225,9 @@ static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
if (k->guest_notifier_mask) { if (k->guest_notifier_mask) {
k->guest_notifier_mask(vdev, n, true); k->guest_notifier_mask(vdev, n, true);
} }
if (with_irqfd) {
virtio_ccw_remove_irqfd(dev, n);
}
virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
event_notifier_cleanup(notifier); event_notifier_cleanup(notifier);
} }
@@ -1071,24 +1239,39 @@ static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs,
{ {
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
bool with_irqfd = dev->sch->thinint_active && kvm_irqfds_enabled();
int r, n; int r, n;
if (with_irqfd && assigned) {
/* irq routes need to be set up before assigning irqfds */
r = virtio_ccw_setup_irqroutes(dev, nvqs);
if (r < 0) {
goto irqroute_error;
}
}
for (n = 0; n < nvqs; n++) { for (n = 0; n < nvqs; n++) {
if (!virtio_queue_get_num(vdev, n)) { if (!virtio_queue_get_num(vdev, n)) {
break; break;
} }
/* false -> true, as soon as irqfd works */ r = virtio_ccw_set_guest_notifier(dev, n, assigned, with_irqfd);
r = virtio_ccw_set_guest_notifier(dev, n, assigned, false);
if (r < 0) { if (r < 0) {
goto assign_error; goto assign_error;
} }
} }
if (with_irqfd && !assigned) {
/* release irq routes after irqfds have been released */
virtio_ccw_release_irqroutes(dev, nvqs);
}
return 0; return 0;
assign_error: assign_error:
while (--n >= 0) { while (--n >= 0) {
virtio_ccw_set_guest_notifier(dev, n, !assigned, false); virtio_ccw_set_guest_notifier(dev, n, !assigned, false);
} }
irqroute_error:
if (with_irqfd && assigned) {
virtio_ccw_release_irqroutes(dev, nvqs);
}
return r; return r;
} }

View File

@@ -22,6 +22,7 @@
#include <hw/virtio/virtio-balloon.h> #include <hw/virtio/virtio-balloon.h>
#include <hw/virtio/virtio-rng.h> #include <hw/virtio/virtio-rng.h>
#include <hw/virtio/virtio-bus.h> #include <hw/virtio/virtio-bus.h>
#include <hw/s390x/s390_flic.h>
#define VIRTUAL_CSSID 0xfe #define VIRTUAL_CSSID 0xfe
@@ -75,6 +76,14 @@ typedef struct VirtIOCCWDeviceClass {
#define VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT 1 #define VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT 1
#define VIRTIO_CCW_FLAG_USE_IOEVENTFD (1 << VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT) #define VIRTIO_CCW_FLAG_USE_IOEVENTFD (1 << VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT)
typedef struct IndAddr {
hwaddr addr;
uint64_t map;
unsigned long refcnt;
int len;
QTAILQ_ENTRY(IndAddr) sibling;
} IndAddr;
struct VirtioCcwDevice { struct VirtioCcwDevice {
DeviceState parent_obj; DeviceState parent_obj;
SubchDev *sch; SubchDev *sch;
@@ -85,10 +94,11 @@ struct VirtioCcwDevice {
bool ioeventfd_disabled; bool ioeventfd_disabled;
uint32_t flags; uint32_t flags;
uint8_t thinint_isc; uint8_t thinint_isc;
AdapterRoutes routes;
/* Guest provided values: */ /* Guest provided values: */
hwaddr indicators; IndAddr *indicators;
hwaddr indicators2; IndAddr *indicators2;
hwaddr summary_indicator; IndAddr *summary_indicator;
uint64_t ind_bit; uint64_t ind_bit;
}; };

View File

@@ -21,6 +21,7 @@
#include "hw/hw.h" #include "hw/hw.h"
#include "hw/pci/pci.h" #include "hw/pci/pci.h"
#include "sysemu/dma.h" #include "sysemu/dma.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h" #include "hw/pci/msix.h"
#include "qemu/iov.h" #include "qemu/iov.h"
#include "hw/scsi/scsi.h" #include "hw/scsi/scsi.h"
@@ -43,9 +44,11 @@
#define MEGASAS_FLAG_USE_JBOD 0 #define MEGASAS_FLAG_USE_JBOD 0
#define MEGASAS_MASK_USE_JBOD (1 << MEGASAS_FLAG_USE_JBOD) #define MEGASAS_MASK_USE_JBOD (1 << MEGASAS_FLAG_USE_JBOD)
#define MEGASAS_FLAG_USE_MSIX 1 #define MEGASAS_FLAG_USE_MSI 1
#define MEGASAS_MASK_USE_MSI (1 << MEGASAS_FLAG_USE_MSI)
#define MEGASAS_FLAG_USE_MSIX 2
#define MEGASAS_MASK_USE_MSIX (1 << MEGASAS_FLAG_USE_MSIX) #define MEGASAS_MASK_USE_MSIX (1 << MEGASAS_FLAG_USE_MSIX)
#define MEGASAS_FLAG_USE_QUEUE64 2 #define MEGASAS_FLAG_USE_QUEUE64 3
#define MEGASAS_MASK_USE_QUEUE64 (1 << MEGASAS_FLAG_USE_QUEUE64) #define MEGASAS_MASK_USE_QUEUE64 (1 << MEGASAS_FLAG_USE_QUEUE64)
static const char *mfi_frame_desc[] = { static const char *mfi_frame_desc[] = {
@@ -132,6 +135,11 @@ static bool megasas_use_queue64(MegasasState *s)
return s->flags & MEGASAS_MASK_USE_QUEUE64; return s->flags & MEGASAS_MASK_USE_QUEUE64;
} }
static bool megasas_use_msi(MegasasState *s)
{
return s->flags & MEGASAS_MASK_USE_MSI;
}
static bool megasas_use_msix(MegasasState *s) static bool megasas_use_msix(MegasasState *s)
{ {
return s->flags & MEGASAS_MASK_USE_MSIX; return s->flags & MEGASAS_MASK_USE_MSIX;
@@ -538,6 +546,9 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context)
if (msix_enabled(pci_dev)) { if (msix_enabled(pci_dev)) {
trace_megasas_msix_raise(0); trace_megasas_msix_raise(0);
msix_notify(pci_dev, 0); msix_notify(pci_dev, 0);
} else if (msi_enabled(pci_dev)) {
trace_megasas_msi_raise(0);
msi_notify(pci_dev, 0);
} else { } else {
trace_megasas_irq_raise(); trace_megasas_irq_raise();
pci_irq_assert(pci_dev); pci_irq_assert(pci_dev);
@@ -717,8 +728,8 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION); snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION);
memcpy(info.image_component[0].name, "APP", 3); memcpy(info.image_component[0].name, "APP", 3);
memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9); memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9);
memcpy(info.image_component[0].build_date, __DATE__, 11); memcpy(info.image_component[0].build_date, "Apr 1 2014", 11);
memcpy(info.image_component[0].build_time, __TIME__, 8); memcpy(info.image_component[0].build_time, "12:34:56", 8);
info.image_component_count = 1; info.image_component_count = 1;
if (pci_dev->has_rom) { if (pci_dev->has_rom) {
uint8_t biosver[32]; uint8_t biosver[32];
@@ -1106,6 +1117,21 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
return MFI_STAT_OK; return MFI_STAT_OK;
} }
static int megasas_dcmd_ld_list_query(MegasasState *s, MegasasCmd *cmd)
{
uint16_t flags;
/* mbox0 contains flags */
flags = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
trace_megasas_dcmd_ld_list_query(cmd->index, flags);
if (flags == MR_LD_QUERY_TYPE_ALL ||
flags == MR_LD_QUERY_TYPE_EXPOSED_TO_HOST) {
return megasas_dcmd_ld_get_list(s, cmd);
}
return MFI_STAT_OK;
}
static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun, static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
MegasasCmd *cmd) MegasasCmd *cmd)
{ {
@@ -1409,6 +1435,8 @@ static const struct dcmd_cmd_tbl_t {
megasas_dcmd_dummy }, megasas_dcmd_dummy },
{ MFI_DCMD_LD_GET_LIST, "LD_GET_LIST", { MFI_DCMD_LD_GET_LIST, "LD_GET_LIST",
megasas_dcmd_ld_get_list}, megasas_dcmd_ld_get_list},
{ MFI_DCMD_LD_LIST_QUERY, "LD_LIST_QUERY",
megasas_dcmd_ld_list_query },
{ MFI_DCMD_LD_GET_INFO, "LD_GET_INFO", { MFI_DCMD_LD_GET_INFO, "LD_GET_INFO",
megasas_dcmd_ld_get_info }, megasas_dcmd_ld_get_info },
{ MFI_DCMD_LD_GET_PROP, "LD_GET_PROP", { MFI_DCMD_LD_GET_PROP, "LD_GET_PROP",
@@ -1939,12 +1967,20 @@ static void megasas_mmio_write(void *opaque, hwaddr addr,
break; break;
case MFI_OMSK: case MFI_OMSK:
s->intr_mask = val; s->intr_mask = val;
if (!megasas_intr_enabled(s) && !msix_enabled(pci_dev)) { if (!megasas_intr_enabled(s) &&
!msi_enabled(pci_dev) &&
!msix_enabled(pci_dev)) {
trace_megasas_irq_lower(); trace_megasas_irq_lower();
pci_irq_deassert(pci_dev); pci_irq_deassert(pci_dev);
} }
if (megasas_intr_enabled(s)) { if (megasas_intr_enabled(s)) {
trace_megasas_intr_enabled(); if (msix_enabled(pci_dev)) {
trace_megasas_msix_enabled(0);
} else if (msi_enabled(pci_dev)) {
trace_megasas_msi_enabled(0);
} else {
trace_megasas_intr_enabled();
}
} else { } else {
trace_megasas_intr_disabled(); trace_megasas_intr_disabled();
} }
@@ -2068,6 +2104,7 @@ static const VMStateDescription vmstate_megasas = {
.minimum_version_id_old = 0, .minimum_version_id_old = 0,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(parent_obj, MegasasState), VMSTATE_PCI_DEVICE(parent_obj, MegasasState),
VMSTATE_MSIX(parent_obj, MegasasState),
VMSTATE_INT32(fw_state, MegasasState), VMSTATE_INT32(fw_state, MegasasState),
VMSTATE_INT32(intr_mask, MegasasState), VMSTATE_INT32(intr_mask, MegasasState),
@@ -2083,9 +2120,12 @@ static void megasas_scsi_uninit(PCIDevice *d)
{ {
MegasasState *s = MEGASAS(d); MegasasState *s = MEGASAS(d);
#ifdef USE_MSIX if (megasas_use_msix(s)) {
msix_uninit(d, &s->mmio_io); msix_uninit(d, &s->mmio_io, &s->mmio_io);
#endif }
if (megasas_use_msi(s)) {
msi_uninit(d);
}
memory_region_destroy(&s->mmio_io); memory_region_destroy(&s->mmio_io);
memory_region_destroy(&s->port_io); memory_region_destroy(&s->port_io);
memory_region_destroy(&s->queue_io); memory_region_destroy(&s->queue_io);
@@ -2124,15 +2164,15 @@ static int megasas_scsi_init(PCIDevice *dev)
memory_region_init_io(&s->queue_io, OBJECT(s), &megasas_queue_ops, s, memory_region_init_io(&s->queue_io, OBJECT(s), &megasas_queue_ops, s,
"megasas-queue", 0x40000); "megasas-queue", 0x40000);
#ifdef USE_MSIX if (megasas_use_msi(s) &&
/* MSI-X support is currently broken */ msi_init(dev, 0x50, 1, true, false)) {
s->flags &= ~MEGASAS_MASK_USE_MSI;
}
if (megasas_use_msix(s) && if (megasas_use_msix(s) &&
msix_init(dev, 15, &s->mmio_io, 0, 0x2000)) { msix_init(dev, 15, &s->mmio_io, 0, 0x2000,
&s->mmio_io, 0, 0x3800, 0x68)) {
s->flags &= ~MEGASAS_MASK_USE_MSIX; s->flags &= ~MEGASAS_MASK_USE_MSIX;
} }
#else
s->flags &= ~MEGASAS_MASK_USE_MSIX;
#endif
bar_type = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64; bar_type = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64;
pci_register_bar(dev, 0, bar_type, &s->mmio_io); pci_register_bar(dev, 0, bar_type, &s->mmio_io);
@@ -2151,7 +2191,7 @@ static int megasas_scsi_init(PCIDevice *dev)
s->sas_addr |= PCI_FUNC(dev->devfn); s->sas_addr |= PCI_FUNC(dev->devfn);
} }
if (!s->hba_serial) { if (!s->hba_serial) {
s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL); s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL);
} }
if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) { if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {
s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE; s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE;
@@ -2164,7 +2204,6 @@ static int megasas_scsi_init(PCIDevice *dev)
s->fw_cmds = MEGASAS_MAX_FRAMES; s->fw_cmds = MEGASAS_MAX_FRAMES;
} }
trace_megasas_init(s->fw_sge, s->fw_cmds, trace_megasas_init(s->fw_sge, s->fw_cmds,
megasas_use_msix(s) ? "MSI-X" : "INTx",
megasas_is_jbod(s) ? "jbod" : "raid"); megasas_is_jbod(s) ? "jbod" : "raid");
s->fw_luns = (MFI_MAX_LD > MAX_SCSI_DEVS) ? s->fw_luns = (MFI_MAX_LD > MAX_SCSI_DEVS) ?
MAX_SCSI_DEVS : MFI_MAX_LD; MAX_SCSI_DEVS : MFI_MAX_LD;
@@ -2189,6 +2228,13 @@ static int megasas_scsi_init(PCIDevice *dev)
return 0; return 0;
} }
static void
megasas_write_config(PCIDevice *pci, uint32_t addr, uint32_t val, int len)
{
pci_default_write_config(pci, addr, val, len);
msi_write_config(pci, addr, val, len);
}
static Property megasas_properties[] = { static Property megasas_properties[] = {
DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge, DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge,
MEGASAS_DEFAULT_SGE), MEGASAS_DEFAULT_SGE),
@@ -2196,10 +2242,10 @@ static Property megasas_properties[] = {
MEGASAS_DEFAULT_FRAMES), MEGASAS_DEFAULT_FRAMES),
DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial), DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0), DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0),
#ifdef USE_MSIX DEFINE_PROP_BIT("use_msi", MegasasState, flags,
MEGASAS_FLAG_USE_MSI, false),
DEFINE_PROP_BIT("use_msix", MegasasState, flags, DEFINE_PROP_BIT("use_msix", MegasasState, flags,
MEGASAS_FLAG_USE_MSIX, false), MEGASAS_FLAG_USE_MSIX, false),
#endif
DEFINE_PROP_BIT("use_jbod", MegasasState, flags, DEFINE_PROP_BIT("use_jbod", MegasasState, flags,
MEGASAS_FLAG_USE_JBOD, false), MEGASAS_FLAG_USE_JBOD, false),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
@@ -2222,6 +2268,7 @@ static void megasas_class_init(ObjectClass *oc, void *data)
dc->vmsd = &vmstate_megasas; dc->vmsd = &vmstate_megasas;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->desc = "LSI MegaRAID SAS 1078"; dc->desc = "LSI MegaRAID SAS 1078";
pc->config_write = megasas_write_config;
} }
static const TypeInfo megasas_info = { static const TypeInfo megasas_info = {

View File

@@ -164,6 +164,7 @@ typedef enum {
MFI_DCMD_PD_BLINK = 0x02070100, MFI_DCMD_PD_BLINK = 0x02070100,
MFI_DCMD_PD_UNBLINK = 0x02070200, MFI_DCMD_PD_UNBLINK = 0x02070200,
MFI_DCMD_LD_GET_LIST = 0x03010000, MFI_DCMD_LD_GET_LIST = 0x03010000,
MFI_DCMD_LD_LIST_QUERY = 0x03010100,
MFI_DCMD_LD_GET_INFO = 0x03020000, MFI_DCMD_LD_GET_INFO = 0x03020000,
MFI_DCMD_LD_GET_PROP = 0x03030000, MFI_DCMD_LD_GET_PROP = 0x03030000,
MFI_DCMD_LD_SET_PROP = 0x03040000, MFI_DCMD_LD_SET_PROP = 0x03040000,
@@ -411,6 +412,14 @@ typedef enum {
MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5, /*query for system drives */ MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5, /*query for system drives */
} mfi_pd_query_type; } mfi_pd_query_type;
typedef enum {
MR_LD_QUERY_TYPE_ALL = 0,
MR_LD_QUERY_TYPE_EXPOSED_TO_HOST = 1,
MR_LD_QUERY_TYPE_USED_TGT_IDS = 2,
MR_LD_QUERY_TYPE_CLUSTER_ACCESS = 3,
MR_LD_QUERY_TYPE_CLUSTER_LOCALE = 4,
} mfi_ld_query_type;
/* /*
* Other propertities and definitions * Other propertities and definitions
*/ */

View File

@@ -938,6 +938,7 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
if (cmd->xfer == 0) { if (cmd->xfer == 0) {
cmd->xfer = 256; cmd->xfer = 256;
} }
/* fall through */
case WRITE_10: case WRITE_10:
case WRITE_VERIFY_10: case WRITE_VERIFY_10:
case WRITE_12: case WRITE_12:
@@ -952,6 +953,7 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
if (cmd->xfer == 0) { if (cmd->xfer == 0) {
cmd->xfer = 256; cmd->xfer = 256;
} }
/* fall through */
case READ_10: case READ_10:
case RECOVER_BUFFERED_DATA: case RECOVER_BUFFERED_DATA:
case READ_12: case READ_12:

View File

@@ -2458,21 +2458,27 @@ static int scsi_block_initfn(SCSIDevice *dev)
int rc; int rc;
if (!s->qdev.conf.bs) { if (!s->qdev.conf.bs) {
error_report("scsi-block: drive property not set"); error_report("drive property not set");
return -1; return -1;
} }
/* check we are using a driver managing SG_IO (version 3 and after) */ /* check we are using a driver managing SG_IO (version 3 and after) */
if (bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 || rc = bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version);
sg_version < 30000) { if (rc < 0) {
error_report("scsi-block: scsi generic interface too old"); error_report("cannot get SG_IO version number: %s. "
"Is this a SCSI device?",
strerror(-rc));
return -1;
}
if (sg_version < 30000) {
error_report("scsi generic interface too old");
return -1; return -1;
} }
/* get device type from INQUIRY data */ /* get device type from INQUIRY data */
rc = get_device_type(s); rc = get_device_type(s);
if (rc < 0) { if (rc < 0) {
error_report("scsi-block: INQUIRY failed"); error_report("INQUIRY failed");
return -1; return -1;
} }

View File

@@ -394,6 +394,7 @@ static void scsi_destroy(SCSIDevice *s)
static int scsi_generic_initfn(SCSIDevice *s) static int scsi_generic_initfn(SCSIDevice *s)
{ {
int rc;
int sg_version; int sg_version;
struct sg_scsi_id scsiid; struct sg_scsi_id scsiid;
@@ -412,8 +413,11 @@ static int scsi_generic_initfn(SCSIDevice *s)
} }
/* check we are using a driver managing SG_IO (version 3 and after */ /* check we are using a driver managing SG_IO (version 3 and after */
if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0) { rc = bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version);
error_report("scsi generic interface not supported"); if (rc < 0) {
error_report("cannot get SG_IO version number: %s. "
"Is this a SCSI device?",
strerror(-rc));
return -1; return -1;
} }
if (sg_version < 30000) { if (sg_version < 30000) {

View File

@@ -498,7 +498,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
uint32_t event, uint32_t reason) uint32_t event, uint32_t reason)
{ {
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
VirtIOSCSIReq *req = virtio_scsi_pop_req(s, vs->event_vq); VirtIOSCSIReq *req;
VirtIOSCSIEvent *evt; VirtIOSCSIEvent *evt;
VirtIODevice *vdev = VIRTIO_DEVICE(s); VirtIODevice *vdev = VIRTIO_DEVICE(s);
int in_size; int in_size;
@@ -507,6 +507,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
return; return;
} }
req = virtio_scsi_pop_req(s, vs->event_vq);
if (!req) { if (!req) {
s->events_dropped = true; s->events_dropped = true;
return; return;

View File

@@ -793,19 +793,46 @@ static const MemoryRegionOps cmos_ops = {
static void rtc_get_date(Object *obj, Visitor *v, void *opaque, static void rtc_get_date(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp) const char *name, Error **errp)
{ {
Error *err = NULL;
RTCState *s = MC146818_RTC(obj); RTCState *s = MC146818_RTC(obj);
struct tm current_tm; struct tm current_tm;
rtc_update_time(s); rtc_update_time(s);
rtc_get_time(s, &current_tm); rtc_get_time(s, &current_tm);
visit_start_struct(v, NULL, "struct tm", name, 0, errp); visit_start_struct(v, NULL, "struct tm", name, 0, &err);
visit_type_int32(v, &current_tm.tm_year, "tm_year", errp); if (err) {
visit_type_int32(v, &current_tm.tm_mon, "tm_mon", errp); goto out;
visit_type_int32(v, &current_tm.tm_mday, "tm_mday", errp); }
visit_type_int32(v, &current_tm.tm_hour, "tm_hour", errp); visit_type_int32(v, &current_tm.tm_year, "tm_year", &err);
visit_type_int32(v, &current_tm.tm_min, "tm_min", errp); if (err) {
visit_type_int32(v, &current_tm.tm_sec, "tm_sec", errp); goto out_end;
}
visit_type_int32(v, &current_tm.tm_mon, "tm_mon", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &current_tm.tm_mday, "tm_mday", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &current_tm.tm_hour, "tm_hour", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &current_tm.tm_min, "tm_min", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &current_tm.tm_sec, "tm_sec", &err);
if (err) {
goto out_end;
}
out_end:
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, errp); visit_end_struct(v, errp);
out:
error_propagate(errp, err);
} }
static void rtc_realizefn(DeviceState *dev, Error **errp) static void rtc_realizefn(DeviceState *dev, Error **errp)

View File

@@ -47,6 +47,8 @@ typedef struct USBHIDState {
USBEndpoint *intr; USBEndpoint *intr;
HIDState hid; HIDState hid;
uint32_t usb_version; uint32_t usb_version;
char *display;
uint32_t head;
} USBHIDState; } USBHIDState;
enum { enum {
@@ -574,6 +576,9 @@ static int usb_hid_initfn(USBDevice *dev, int kind)
usb_desc_init(dev); usb_desc_init(dev);
us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
hid_init(&us->hid, kind, usb_hid_changed); hid_init(&us->hid, kind, usb_hid_changed);
if (us->display && us->hid.s) {
qemu_input_handler_bind(us->hid.s, us->display, us->head, NULL);
}
return 0; return 0;
} }
@@ -653,6 +658,8 @@ static void usb_hid_class_initfn(ObjectClass *klass, void *data)
static Property usb_tablet_properties[] = { static Property usb_tablet_properties[] = {
DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2), DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
DEFINE_PROP_STRING("display", USBHIDState, display),
DEFINE_PROP_UINT32("head", USBHIDState, head, 0),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@@ -696,6 +703,11 @@ static const TypeInfo usb_mouse_info = {
.class_init = usb_mouse_class_initfn, .class_init = usb_mouse_class_initfn,
}; };
static Property usb_keyboard_properties[] = {
DEFINE_PROP_STRING("display", USBHIDState, display),
DEFINE_PROP_END_OF_LIST(),
};
static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
@@ -706,6 +718,7 @@ static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
uc->product_desc = "QEMU USB Keyboard"; uc->product_desc = "QEMU USB Keyboard";
uc->usb_desc = &desc_keyboard; uc->usb_desc = &desc_keyboard;
dc->vmsd = &vmstate_usb_kbd; dc->vmsd = &vmstate_usb_kbd;
dc->props = usb_keyboard_properties;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories); set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
} }

View File

@@ -108,6 +108,7 @@ static void balloon_stats_poll_cb(void *opaque)
static void balloon_stats_get_all(Object *obj, struct Visitor *v, static void balloon_stats_get_all(Object *obj, struct Visitor *v,
void *opaque, const char *name, Error **errp) void *opaque, const char *name, Error **errp)
{ {
Error *err = NULL;
VirtIOBalloon *s = opaque; VirtIOBalloon *s = opaque;
int i; int i;
@@ -116,17 +117,33 @@ static void balloon_stats_get_all(Object *obj, struct Visitor *v,
return; return;
} }
visit_start_struct(v, NULL, "guest-stats", name, 0, errp); visit_start_struct(v, NULL, "guest-stats", name, 0, &err);
visit_type_int(v, &s->stats_last_update, "last-update", errp); if (err) {
goto out;
visit_start_struct(v, NULL, NULL, "stats", 0, errp); }
for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) { visit_type_int(v, &s->stats_last_update, "last-update", &err);
visit_type_int64(v, (int64_t *) &s->stats[i], balloon_stat_names[i], if (err) {
errp); goto out_end;
} }
visit_end_struct(v, errp);
visit_end_struct(v, errp); visit_start_struct(v, NULL, NULL, "stats", 0, &err);
if (err) {
goto out_end;
}
for (i = 0; !err && i < VIRTIO_BALLOON_S_NR; i++) {
visit_type_int64(v, (int64_t *) &s->stats[i], balloon_stat_names[i],
&err);
}
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
out_end:
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
out:
error_propagate(errp, err);
} }
static void balloon_stats_get_poll_interval(Object *obj, struct Visitor *v, static void balloon_stats_get_poll_interval(Object *obj, struct Visitor *v,

View File

@@ -120,6 +120,8 @@ typedef enum {
/* BDRV_BLOCK_DATA: data is read from bs->file or another file /* BDRV_BLOCK_DATA: data is read from bs->file or another file
* BDRV_BLOCK_ZERO: sectors read as zero * BDRV_BLOCK_ZERO: sectors read as zero
* BDRV_BLOCK_OFFSET_VALID: sector stored in bs->file as raw data * BDRV_BLOCK_OFFSET_VALID: sector stored in bs->file as raw data
* BDRV_BLOCK_ALLOCATED: the content of the block is determined by this
* layer (as opposed to the backing file)
* BDRV_BLOCK_RAW: used internally to indicate that the request * BDRV_BLOCK_RAW: used internally to indicate that the request
* was answered by the raw driver and that one * was answered by the raw driver and that one
* should look in bs->file directly. * should look in bs->file directly.
@@ -141,10 +143,11 @@ typedef enum {
* f t f not allocated or unknown offset, read as zero * f t f not allocated or unknown offset, read as zero
* f f f not allocated or unknown offset, read from backing_hd * f f f not allocated or unknown offset, read from backing_hd
*/ */
#define BDRV_BLOCK_DATA 1 #define BDRV_BLOCK_DATA 0x01
#define BDRV_BLOCK_ZERO 2 #define BDRV_BLOCK_ZERO 0x02
#define BDRV_BLOCK_OFFSET_VALID 4 #define BDRV_BLOCK_OFFSET_VALID 0x04
#define BDRV_BLOCK_RAW 8 #define BDRV_BLOCK_RAW 0x08
#define BDRV_BLOCK_ALLOCATED 0x10
#define BDRV_BLOCK_OFFSET_MASK BDRV_SECTOR_MASK #define BDRV_BLOCK_OFFSET_MASK BDRV_SECTOR_MASK
typedef enum { typedef enum {

View File

@@ -364,6 +364,7 @@ struct BlockDriverState {
BlockJob *job; BlockJob *job;
QDict *options; QDict *options;
BlockdevDetectZeroesOptions detect_zeroes;
}; };
int get_tmp_filename(char *filename, int size); int get_tmp_filename(char *filename, int size);

View File

@@ -2,6 +2,7 @@
#define QEMU_HID_H #define QEMU_HID_H
#include "migration/vmstate.h" #include "migration/vmstate.h"
#include "ui/input.h"
#define HID_MOUSE 1 #define HID_MOUSE 1
#define HID_TABLET 2 #define HID_TABLET 2
@@ -22,7 +23,6 @@ typedef void (*HIDEventFunc)(HIDState *s);
typedef struct HIDMouseState { typedef struct HIDMouseState {
HIDPointerEvent queue[QUEUE_LENGTH]; HIDPointerEvent queue[QUEUE_LENGTH];
int mouse_grabbed; int mouse_grabbed;
QEMUPutMouseEntry *eh_entry;
} HIDMouseState; } HIDMouseState;
typedef struct HIDKeyboardState { typedef struct HIDKeyboardState {
@@ -31,7 +31,6 @@ typedef struct HIDKeyboardState {
uint8_t leds; uint8_t leds;
uint8_t key[16]; uint8_t key[16];
int32_t keys; int32_t keys;
QEMUPutKbdEntry *eh_entry;
} HIDKeyboardState; } HIDKeyboardState;
struct HIDState { struct HIDState {
@@ -47,6 +46,7 @@ struct HIDState {
bool idle_pending; bool idle_pending;
QEMUTimer *idle_timer; QEMUTimer *idle_timer;
HIDEventFunc event; HIDEventFunc event;
QemuInputHandlerState *s;
}; };
void hid_init(HIDState *hs, int kind, HIDEventFunc event); void hid_init(HIDState *hs, int kind, HIDEventFunc event);

View File

@@ -0,0 +1,23 @@
/*
* s390 adapter definitions
*
* Copyright 2013,2014 IBM Corp.
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#ifndef S390X_ADAPTER_H
#define S390X_ADAPTER_H
struct AdapterInfo {
uint64_t ind_addr;
uint64_t summary_addr;
uint64_t ind_offset;
uint32_t summary_offset;
uint32_t adapter_id;
};
#endif

View File

@@ -1,33 +1,76 @@
/* /*
* QEMU S390x KVM floating interrupt controller (flic) * QEMU S390x floating interrupt controller (flic)
* *
* Copyright 2014 IBM Corp. * Copyright 2014 IBM Corp.
* Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com> * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
* Cornelia Huck <cornelia.huck@de.ibm.com>
* *
* This work is licensed under the terms of the GNU GPL, version 2 or (at * This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level * your option) any later version. See the COPYING file in the top-level
* directory. * directory.
*/ */
#ifndef __KVM_S390_FLIC_H #ifndef __HW_S390_FLIC_H
#define __KVM_S390_FLIC_H #define __HW_S390_FLIC_H
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "hw/s390x/adapter.h"
#include "hw/virtio/virtio.h"
#define TYPE_KVM_S390_FLIC "s390-flic" typedef struct AdapterRoutes {
AdapterInfo adapter;
int num_routes;
int gsi[VIRTIO_PCI_QUEUE_MAX];
} AdapterRoutes;
#define TYPE_S390_FLIC_COMMON "s390-flic"
#define S390_FLIC_COMMON(obj) \
OBJECT_CHECK(S390FLICState, (obj), TYPE_S390_FLIC_COMMON)
typedef struct S390FLICState {
SysBusDevice parent_obj;
} S390FLICState;
#define S390_FLIC_COMMON_CLASS(klass) \
OBJECT_CLASS_CHECK(S390FLICStateClass, (klass), TYPE_S390_FLIC_COMMON)
#define S390_FLIC_COMMON_GET_CLASS(obj) \
OBJECT_GET_CLASS(S390FLICStateClass, (obj), TYPE_S390_FLIC_COMMON)
typedef struct S390FLICStateClass {
DeviceClass parent_class;
int (*register_io_adapter)(S390FLICState *fs, uint32_t id, uint8_t isc,
bool swap, bool maskable);
int (*io_adapter_map)(S390FLICState *fs, uint32_t id, uint64_t map_addr,
bool do_map);
int (*add_adapter_routes)(S390FLICState *fs, AdapterRoutes *routes);
void (*release_adapter_routes)(S390FLICState *fs, AdapterRoutes *routes);
} S390FLICStateClass;
#define TYPE_KVM_S390_FLIC "s390-flic-kvm"
#define KVM_S390_FLIC(obj) \ #define KVM_S390_FLIC(obj) \
OBJECT_CHECK(KVMS390FLICState, (obj), TYPE_KVM_S390_FLIC) OBJECT_CHECK(KVMS390FLICState, (obj), TYPE_KVM_S390_FLIC)
typedef struct KVMS390FLICState { #define TYPE_QEMU_S390_FLIC "s390-flic-qemu"
SysBusDevice parent_obj; #define QEMU_S390_FLIC(obj) \
OBJECT_CHECK(QEMUS390FLICState, (obj), TYPE_QEMU_S390_FLIC)
uint32_t fd; typedef struct QEMUS390FLICState {
} KVMS390FLICState; S390FLICState parent_obj;
} QEMUS390FLICState;
void s390_flic_init(void);
S390FLICState *s390_get_flic(void);
#ifdef CONFIG_KVM #ifdef CONFIG_KVM
void s390_flic_init(void); DeviceState *s390_flic_kvm_create(void);
#else #else
static inline void s390_flic_init(void) { } static inline DeviceState *s390_flic_kvm_create(void)
{
return NULL;
}
#endif #endif
#endif /* __KVM_S390_FLIC_H */ #endif /* __HW_S390_FLIC_H */

View File

@@ -67,12 +67,6 @@ void error_set_win32(Error **errp, int win32_err, ErrorClass err_class,
*/ */
void error_setg_file_open(Error **errp, int os_errno, const char *filename); void error_setg_file_open(Error **errp, int os_errno, const char *filename);
/**
* Returns true if an indirect pointer to an error is pointing to a valid
* error object.
*/
bool error_is_set(Error **errp);
/* /*
* Get the error class of an error object. * Get the error class of an error object.
*/ */

View File

@@ -16,6 +16,7 @@
#include "qapi/qmp/qobject.h" #include "qapi/qmp/qobject.h"
#include "qapi/qmp/qlist.h" #include "qapi/qmp/qlist.h"
#include "qemu/queue.h" #include "qemu/queue.h"
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#define QDICT_BUCKET_MAX 512 #define QDICT_BUCKET_MAX 512
@@ -70,4 +71,6 @@ void qdict_flatten(QDict *qdict);
void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start); void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
void qdict_array_split(QDict *src, QList **dst); void qdict_array_split(QDict *src, QList **dst);
void qdict_join(QDict *dest, QDict *src, bool overwrite);
#endif /* QDICT_H */ #endif /* QDICT_H */

View File

@@ -42,13 +42,9 @@ struct Visitor
Error **errp); Error **errp);
/* May be NULL */ /* May be NULL */
void (*start_optional)(Visitor *v, bool *present, const char *name, void (*optional)(Visitor *v, bool *present, const char *name,
Error **errp); Error **errp);
void (*end_optional)(Visitor *v, Error **errp);
void (*start_handle)(Visitor *v, void **obj, const char *kind,
const char *name, Error **errp);
void (*end_handle)(Visitor *v, Error **errp);
void (*type_uint8)(Visitor *v, uint8_t *obj, const char *name, Error **errp); void (*type_uint8)(Visitor *v, uint8_t *obj, const char *name, Error **errp);
void (*type_uint16)(Visitor *v, uint16_t *obj, const char *name, Error **errp); void (*type_uint16)(Visitor *v, uint16_t *obj, const char *name, Error **errp);
void (*type_uint32)(Visitor *v, uint32_t *obj, const char *name, Error **errp); void (*type_uint32)(Visitor *v, uint32_t *obj, const char *name, Error **errp);

View File

@@ -39,9 +39,8 @@ void visit_end_implicit_struct(Visitor *v, Error **errp);
void visit_start_list(Visitor *v, const char *name, Error **errp); void visit_start_list(Visitor *v, const char *name, Error **errp);
GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp); GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
void visit_end_list(Visitor *v, Error **errp); void visit_end_list(Visitor *v, Error **errp);
void visit_start_optional(Visitor *v, bool *present, const char *name, void visit_optional(Visitor *v, bool *present, const char *name,
Error **errp); Error **errp);
void visit_end_optional(Visitor *v, Error **errp);
void visit_get_next_type(Visitor *v, int *obj, const int *qtypes, void visit_get_next_type(Visitor *v, int *obj, const int *qtypes,
const char *name, Error **errp); const char *name, Error **errp);
void visit_type_enum(Visitor *v, int *obj, const char *strings[], void visit_type_enum(Visitor *v, int *obj, const char *strings[],

View File

@@ -318,6 +318,7 @@ void qemu_iovec_concat(QEMUIOVector *dst,
void qemu_iovec_concat_iov(QEMUIOVector *dst, void qemu_iovec_concat_iov(QEMUIOVector *dst,
struct iovec *src_iov, unsigned int src_cnt, struct iovec *src_iov, unsigned int src_cnt,
size_t soffset, size_t sbytes); size_t soffset, size_t sbytes);
bool qemu_iovec_is_zero(QEMUIOVector *qiov);
void qemu_iovec_destroy(QEMUIOVector *qiov); void qemu_iovec_destroy(QEMUIOVector *qiov);
void qemu_iovec_reset(QEMUIOVector *qiov); void qemu_iovec_reset(QEMUIOVector *qiov);
size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset, size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset,

View File

@@ -74,5 +74,6 @@ typedef struct SHPCDevice SHPCDevice;
typedef struct FWCfgState FWCfgState; typedef struct FWCfgState FWCfgState;
typedef struct PcGuestInfo PcGuestInfo; typedef struct PcGuestInfo PcGuestInfo;
typedef struct Range Range; typedef struct Range Range;
typedef struct AdapterInfo AdapterInfo;
#endif /* QEMU_TYPEDEFS_H */ #endif /* QEMU_TYPEDEFS_H */

View File

@@ -300,7 +300,7 @@ int kvm_check_extension(KVMState *s, unsigned int extension);
}; \ }; \
uint64_t args_tmp[] = { __VA_ARGS__ }; \ uint64_t args_tmp[] = { __VA_ARGS__ }; \
int i; \ int i; \
for (i = 0; i < ARRAY_SIZE(args_tmp) && \ for (i = 0; i < (int)ARRAY_SIZE(args_tmp) && \
i < ARRAY_SIZE(cap.args); i++) { \ i < ARRAY_SIZE(cap.args); i++) { \
cap.args[i] = args_tmp[i]; \ cap.args[i] = args_tmp[i]; \
} \ } \
@@ -315,7 +315,7 @@ int kvm_check_extension(KVMState *s, unsigned int extension);
}; \ }; \
uint64_t args_tmp[] = { __VA_ARGS__ }; \ uint64_t args_tmp[] = { __VA_ARGS__ }; \
int i; \ int i; \
for (i = 0; i < ARRAY_SIZE(args_tmp) && \ for (i = 0; i < (int)ARRAY_SIZE(args_tmp) && \
i < ARRAY_SIZE(cap.args); i++) { \ i < ARRAY_SIZE(cap.args); i++) { \
cap.args[i] = args_tmp[i]; \ cap.args[i] = args_tmp[i]; \
} \ } \
@@ -363,6 +363,8 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg);
int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg); int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg);
void kvm_irqchip_release_virq(KVMState *s, int virq); void kvm_irqchip_release_virq(KVMState *s, int virq);
int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter);
int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n,
EventNotifier *rn, int virq); EventNotifier *rn, int virq);
int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq); int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq);

View File

@@ -29,6 +29,9 @@ QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
void qemu_input_handler_activate(QemuInputHandlerState *s); void qemu_input_handler_activate(QemuInputHandlerState *s);
void qemu_input_handler_deactivate(QemuInputHandlerState *s); void qemu_input_handler_deactivate(QemuInputHandlerState *s);
void qemu_input_handler_unregister(QemuInputHandlerState *s); void qemu_input_handler_unregister(QemuInputHandlerState *s);
void qemu_input_handler_bind(QemuInputHandlerState *s,
const char *device_id, int head,
Error **errp);
void qemu_input_event_send(QemuConsole *src, InputEvent *evt); void qemu_input_event_send(QemuConsole *src, InputEvent *evt);
void qemu_input_event_sync(void); void qemu_input_event_sync(void);
@@ -36,6 +39,7 @@ InputEvent *qemu_input_event_new_key(KeyValue *key, bool down);
void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down); void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down);
void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down); void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down);
void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down); void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down);
int qemu_input_key_number_to_qcode(uint8_t nr);
int qemu_input_key_value_to_number(const KeyValue *value); int qemu_input_key_value_to_number(const KeyValue *value);
int qemu_input_key_value_to_qcode(const KeyValue *value); int qemu_input_key_value_to_qcode(const KeyValue *value);
int qemu_input_key_value_to_scancode(const KeyValue *value, bool down, int qemu_input_key_value_to_scancode(const KeyValue *value, bool down,

View File

@@ -27,6 +27,7 @@
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "hw/hw.h" #include "hw/hw.h"
#include "hw/pci/msi.h" #include "hw/pci/msi.h"
#include "hw/s390x/adapter.h"
#include "exec/gdbstub.h" #include "exec/gdbstub.h"
#include "sysemu/kvm.h" #include "sysemu/kvm.h"
#include "qemu/bswap.h" #include "qemu/bswap.h"
@@ -1236,6 +1237,35 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int rfd, int virq,
return kvm_vm_ioctl(s, KVM_IRQFD, &irqfd); return kvm_vm_ioctl(s, KVM_IRQFD, &irqfd);
} }
int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter)
{
struct kvm_irq_routing_entry kroute;
int virq;
if (!kvm_gsi_routing_enabled()) {
return -ENOSYS;
}
virq = kvm_irqchip_get_virq(s);
if (virq < 0) {
return virq;
}
kroute.gsi = virq;
kroute.type = KVM_IRQ_ROUTING_S390_ADAPTER;
kroute.flags = 0;
kroute.u.adapter.summary_addr = adapter->summary_addr;
kroute.u.adapter.ind_addr = adapter->ind_addr;
kroute.u.adapter.summary_offset = adapter->summary_offset;
kroute.u.adapter.ind_offset = adapter->ind_offset;
kroute.u.adapter.adapter_id = adapter->adapter_id;
kvm_add_routing_entry(s, &kroute);
kvm_irqchip_commit_routes(s);
return virq;
}
#else /* !KVM_CAP_IRQ_ROUTING */ #else /* !KVM_CAP_IRQ_ROUTING */
void kvm_init_irq_routing(KVMState *s) void kvm_init_irq_routing(KVMState *s)
@@ -1256,6 +1286,11 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg)
return -ENOSYS; return -ENOSYS;
} }
int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter)
{
return -ENOSYS;
}
static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign) static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign)
{ {
abort(); abort();
@@ -1285,7 +1320,8 @@ static int kvm_irqchip_create(KVMState *s)
int ret; int ret;
if (!qemu_opt_get_bool(qemu_get_machine_opts(), "kernel_irqchip", true) || if (!qemu_opt_get_bool(qemu_get_machine_opts(), "kernel_irqchip", true) ||
!kvm_check_extension(s, KVM_CAP_IRQCHIP)) { (!kvm_check_extension(s, KVM_CAP_IRQCHIP) &&
(kvm_vm_enable_cap(s, KVM_CAP_S390_IRQCHIP, 0) < 0))) {
return 0; return 0;
} }

View File

@@ -136,6 +136,11 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg)
return -ENOSYS; return -ENOSYS;
} }
int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter)
{
return -ENOSYS;
}
int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n,
EventNotifier *rn, int virq) EventNotifier *rn, int virq)
{ {

View File

@@ -15,6 +15,7 @@
#include <linux/types.h> #include <linux/types.h>
#define __KVM_S390 #define __KVM_S390
#define __KVM_HAVE_GUEST_DEBUG
/* Device control API: s390-specific devices */ /* Device control API: s390-specific devices */
#define KVM_DEV_FLIC_GET_ALL_IRQS 1 #define KVM_DEV_FLIC_GET_ALL_IRQS 1
@@ -54,6 +55,13 @@ struct kvm_s390_io_adapter_req {
__u64 addr; __u64 addr;
}; };
/* kvm attr_group on vm fd */
#define KVM_S390_VM_MEM_CTRL 0
/* kvm attributes for mem_ctrl */
#define KVM_S390_VM_MEM_ENABLE_CMMA 0
#define KVM_S390_VM_MEM_CLR_CMMA 1
/* for KVM_GET_REGS and KVM_SET_REGS */ /* for KVM_GET_REGS and KVM_SET_REGS */
struct kvm_regs { struct kvm_regs {
/* general purpose regs for s390 */ /* general purpose regs for s390 */
@@ -72,11 +80,31 @@ struct kvm_fpu {
__u64 fprs[16]; __u64 fprs[16];
}; };
#define KVM_GUESTDBG_USE_HW_BP 0x00010000
#define KVM_HW_BP 1
#define KVM_HW_WP_WRITE 2
#define KVM_SINGLESTEP 4
struct kvm_debug_exit_arch { struct kvm_debug_exit_arch {
__u64 addr;
__u8 type;
__u8 pad[7]; /* Should be set to 0 */
};
struct kvm_hw_breakpoint {
__u64 addr;
__u64 phys_addr;
__u64 len;
__u8 type;
__u8 pad[7]; /* Should be set to 0 */
}; };
/* for KVM_SET_GUEST_DEBUG */ /* for KVM_SET_GUEST_DEBUG */
struct kvm_guest_debug_arch { struct kvm_guest_debug_arch {
__u32 nr_hw_bp;
__u32 pad; /* Should be set to 0 */
struct kvm_hw_breakpoint *hw_bp;
}; };
#define KVM_SYNC_PREFIX (1UL << 0) #define KVM_SYNC_PREFIX (1UL << 0)

View File

@@ -416,6 +416,8 @@ struct kvm_s390_psw {
#define KVM_S390_INT_PFAULT_INIT 0xfffe0004u #define KVM_S390_INT_PFAULT_INIT 0xfffe0004u
#define KVM_S390_INT_PFAULT_DONE 0xfffe0005u #define KVM_S390_INT_PFAULT_DONE 0xfffe0005u
#define KVM_S390_MCHK 0xfffe1000u #define KVM_S390_MCHK 0xfffe1000u
#define KVM_S390_INT_CLOCK_COMP 0xffff1004u
#define KVM_S390_INT_CPU_TIMER 0xffff1005u
#define KVM_S390_INT_VIRTIO 0xffff2603u #define KVM_S390_INT_VIRTIO 0xffff2603u
#define KVM_S390_INT_SERVICE 0xffff2401u #define KVM_S390_INT_SERVICE 0xffff2401u
#define KVM_S390_INT_EMERGENCY 0xffff1201u #define KVM_S390_INT_EMERGENCY 0xffff1201u
@@ -515,6 +517,7 @@ enum {
kvm_ioeventfd_flag_nr_pio, kvm_ioeventfd_flag_nr_pio,
kvm_ioeventfd_flag_nr_deassign, kvm_ioeventfd_flag_nr_deassign,
kvm_ioeventfd_flag_nr_virtio_ccw_notify, kvm_ioeventfd_flag_nr_virtio_ccw_notify,
kvm_ioeventfd_flag_nr_fast_mmio,
kvm_ioeventfd_flag_nr_max, kvm_ioeventfd_flag_nr_max,
}; };
@@ -529,7 +532,7 @@ enum {
struct kvm_ioeventfd { struct kvm_ioeventfd {
__u64 datamatch; __u64 datamatch;
__u64 addr; /* legal pio/mmio address */ __u64 addr; /* legal pio/mmio address */
__u32 len; /* 1, 2, 4, or 8 bytes */ __u32 len; /* 1, 2, 4, or 8 bytes; or 0 to ignore length */
__s32 fd; __s32 fd;
__u32 flags; __u32 flags;
__u8 pad[36]; __u8 pad[36];
@@ -743,6 +746,8 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_IOAPIC_POLARITY_IGNORED 97 #define KVM_CAP_IOAPIC_POLARITY_IGNORED 97
#define KVM_CAP_ENABLE_CAP_VM 98 #define KVM_CAP_ENABLE_CAP_VM 98
#define KVM_CAP_S390_IRQCHIP 99 #define KVM_CAP_S390_IRQCHIP 99
#define KVM_CAP_IOEVENTFD_NO_LENGTH 100
#define KVM_CAP_VM_ATTRIBUTES 101
#ifdef KVM_CAP_IRQ_ROUTING #ifdef KVM_CAP_IRQ_ROUTING

153
monitor.c
View File

@@ -4269,6 +4269,55 @@ static const char *next_arg_type(const char *typestr)
return (p != NULL ? ++p : typestr); return (p != NULL ? ++p : typestr);
} }
static void add_completion_option(ReadLineState *rs, const char *str,
const char *option)
{
if (!str || !option) {
return;
}
if (!strncmp(option, str, strlen(str))) {
readline_add_completion(rs, option);
}
}
void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str)
{
size_t len;
ChardevBackendInfoList *list, *start;
if (nb_args != 2) {
return;
}
len = strlen(str);
readline_set_completion_index(rs, len);
start = list = qmp_query_chardev_backends(NULL);
while (list) {
const char *chr_name = list->value->name;
if (!strncmp(chr_name, str, len)) {
readline_add_completion(rs, chr_name);
}
list = list->next;
}
qapi_free_ChardevBackendInfoList(start);
}
void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str)
{
size_t len;
int i;
if (nb_args != 2) {
return;
}
len = strlen(str);
readline_set_completion_index(rs, len);
for (i = 0; NetClientOptionsKind_lookup[i]; i++) {
add_completion_option(rs, str, NetClientOptionsKind_lookup[i]);
}
}
void device_add_completion(ReadLineState *rs, int nb_args, const char *str) void device_add_completion(ReadLineState *rs, int nb_args, const char *str)
{ {
GSList *list, *elt; GSList *list, *elt;
@@ -4339,6 +4388,29 @@ static void device_del_bus_completion(ReadLineState *rs, BusState *bus,
} }
} }
void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str)
{
size_t len;
ChardevInfoList *list, *start;
if (nb_args != 2) {
return;
}
len = strlen(str);
readline_set_completion_index(rs, len);
start = list = qmp_query_chardev(NULL);
while (list) {
ChardevInfo *chr = list->value;
if (!strncmp(chr->label, str, len)) {
readline_add_completion(rs, chr->label);
}
list = list->next;
}
qapi_free_ChardevInfoList(start);
}
void device_del_completion(ReadLineState *rs, int nb_args, const char *str) void device_del_completion(ReadLineState *rs, int nb_args, const char *str)
{ {
size_t len; size_t len;
@@ -4376,6 +4448,77 @@ void object_del_completion(ReadLineState *rs, int nb_args, const char *str)
qapi_free_ObjectPropertyInfoList(start); qapi_free_ObjectPropertyInfoList(start);
} }
void sendkey_completion(ReadLineState *rs, int nb_args, const char *str)
{
int i;
char *sep;
size_t len;
if (nb_args != 2) {
return;
}
sep = strrchr(str, '-');
if (sep) {
str = sep + 1;
}
len = strlen(str);
readline_set_completion_index(rs, len);
for (i = 0; i < Q_KEY_CODE_MAX; i++) {
if (!strncmp(str, QKeyCode_lookup[i], len)) {
readline_add_completion(rs, QKeyCode_lookup[i]);
}
}
}
void set_link_completion(ReadLineState *rs, int nb_args, const char *str)
{
size_t len;
len = strlen(str);
readline_set_completion_index(rs, len);
if (nb_args == 2) {
NetClientState *ncs[255];
int count, i;
count = qemu_find_net_clients_except(NULL, ncs,
NET_CLIENT_OPTIONS_KIND_NONE, 255);
for (i = 0; i < count; i++) {
const char *name = ncs[i]->name;
if (!strncmp(str, name, len)) {
readline_add_completion(rs, name);
}
}
} else if (nb_args == 3) {
add_completion_option(rs, str, "on");
add_completion_option(rs, str, "off");
}
}
void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)
{
int len, count, i;
NetClientState *ncs[255];
if (nb_args != 2) {
return;
}
len = strlen(str);
readline_set_completion_index(rs, len);
count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_OPTIONS_KIND_NIC,
255);
for (i = 0; i < count; i++) {
QemuOpts *opts;
const char *name = ncs[i]->name;
if (strncmp(str, name, len)) {
continue;
}
opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), name);
if (opts) {
readline_add_completion(rs, name);
}
}
}
static void monitor_find_completion_by_table(Monitor *mon, static void monitor_find_completion_by_table(Monitor *mon,
const mon_cmd_t *cmd_table, const mon_cmd_t *cmd_table,
char **args, char **args,
@@ -4444,15 +4587,7 @@ static void monitor_find_completion_by_table(Monitor *mon,
break; break;
case 's': case 's':
case 'S': case 'S':
if (!strcmp(cmd->name, "sendkey")) { if (!strcmp(cmd->name, "help|?")) {
char *sep = strrchr(str, '-');
if (sep)
str = sep + 1;
readline_set_completion_index(mon->rs, strlen(str));
for (i = 0; i < Q_KEY_CODE_MAX; i++) {
cmd_completion(mon, str, QKeyCode_lookup[i]);
}
} else if (!strcmp(cmd->name, "help|?")) {
monitor_find_completion_by_table(mon, cmd_table, monitor_find_completion_by_table(mon, cmd_table,
&args[1], nb_args - 1); &args[1], nb_args - 1);
} }

View File

@@ -633,7 +633,7 @@ int qemu_find_net_clients_except(const char *id, NetClientState **ncs,
if (nc->info->type == type) { if (nc->info->type == type) {
continue; continue;
} }
if (!strcmp(nc->name, id)) { if (!id || !strcmp(nc->name, id)) {
if (ret < max) { if (ret < max) {
ncs[ret] = nc; ncs[ret] = nc;
} }

View File

@@ -691,7 +691,7 @@
# Information about current migration process. # Information about current migration process.
# #
# @status: #optional string describing the current migration status. # @status: #optional string describing the current migration status.
# As of 0.14.0 this can be 'active', 'completed', 'failed' or # As of 0.14.0 this can be 'setup', 'active', 'completed', 'failed' or
# 'cancelled'. If this field is not returned, no migration process # 'cancelled'. If this field is not returned, no migration process
# has been initiated # has been initiated
# #
@@ -942,6 +942,8 @@
# @encryption_key_missing: true if the backing device is encrypted but an # @encryption_key_missing: true if the backing device is encrypted but an
# valid encryption key is missing # valid encryption key is missing
# #
# @detect_zeroes: detect and optimize zero writes (Since 2.1)
#
# @bps: total throughput limit in bytes per second is specified # @bps: total throughput limit in bytes per second is specified
# #
# @bps_rd: read throughput limit in bytes per second is specified # @bps_rd: read throughput limit in bytes per second is specified
@@ -977,6 +979,7 @@
'data': { 'file': 'str', '*node-name': 'str', 'ro': 'bool', 'drv': 'str', 'data': { 'file': 'str', '*node-name': 'str', 'ro': 'bool', 'drv': 'str',
'*backing_file': 'str', 'backing_file_depth': 'int', '*backing_file': 'str', 'backing_file_depth': 'int',
'encrypted': 'bool', 'encryption_key_missing': 'bool', 'encrypted': 'bool', 'encryption_key_missing': 'bool',
'detect_zeroes': 'BlockdevDetectZeroesOptions',
'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int', 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
'image': 'ImageInfo', 'image': 'ImageInfo',
@@ -4254,6 +4257,22 @@
{ 'enum': 'BlockdevDiscardOptions', { 'enum': 'BlockdevDiscardOptions',
'data': [ 'ignore', 'unmap' ] } 'data': [ 'ignore', 'unmap' ] }
##
# @BlockdevDetectZeroesOptions
#
# Describes the operation mode for the automatic conversion of plain
# zero writes by the OS to driver specific optimized zero write commands.
#
# @off: Disabled (default)
# @on: Enabled
# @unmap: Enabled and even try to unmap blocks if possible. This requires
# also that @BlockdevDiscardOptions is set to unmap for this device.
#
# Since: 2.1
##
{ 'enum': 'BlockdevDetectZeroesOptions',
'data': [ 'off', 'on', 'unmap' ] }
## ##
# @BlockdevAioOptions # @BlockdevAioOptions
# #
@@ -4306,20 +4325,22 @@
# Options that are available for all block devices, independent of the block # Options that are available for all block devices, independent of the block
# driver. # driver.
# #
# @driver: block driver name # @driver: block driver name
# @id: #optional id by which the new block device can be referred to. # @id: #optional id by which the new block device can be referred to.
# This is a required option on the top level of blockdev-add, and # This is a required option on the top level of blockdev-add, and
# currently not allowed on any other level. # currently not allowed on any other level.
# @node-name: #optional the name of a block driver state node (Since 2.0) # @node-name: #optional the name of a block driver state node (Since 2.0)
# @discard: #optional discard-related options (default: ignore) # @discard: #optional discard-related options (default: ignore)
# @cache: #optional cache-related options # @cache: #optional cache-related options
# @aio: #optional AIO backend (default: threads) # @aio: #optional AIO backend (default: threads)
# @rerror: #optional how to handle read errors on the device # @rerror: #optional how to handle read errors on the device
# (default: report) # (default: report)
# @werror: #optional how to handle write errors on the device # @werror: #optional how to handle write errors on the device
# (default: enospc) # (default: enospc)
# @read-only: #optional whether the block device should be read-only # @read-only: #optional whether the block device should be read-only
# (default: false) # (default: false)
# @detect-zeroes: #optional detect and optimize zero writes (Since 2.1)
# (default: off)
# #
# Since: 1.7 # Since: 1.7
## ##
@@ -4332,7 +4353,8 @@
'*aio': 'BlockdevAioOptions', '*aio': 'BlockdevAioOptions',
'*rerror': 'BlockdevOnError', '*rerror': 'BlockdevOnError',
'*werror': 'BlockdevOnError', '*werror': 'BlockdevOnError',
'*read-only': 'bool' } } '*read-only': 'bool',
'*detect-zeroes': 'BlockdevDetectZeroesOptions' } }
## ##
# @BlockdevOptionsFile # @BlockdevOptionsFile

View File

@@ -484,8 +484,7 @@ opts_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp)
static void static void
opts_start_optional(Visitor *v, bool *present, const char *name, opts_optional(Visitor *v, bool *present, const char *name, Error **errp)
Error **errp)
{ {
OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v);
@@ -528,7 +527,7 @@ opts_visitor_new(const QemuOpts *opts)
/* type_number() is not filled in, but this is not the first visitor to /* type_number() is not filled in, but this is not the first visitor to
* skip some mandatory methods... */ * skip some mandatory methods... */
ov->visitor.start_optional = &opts_start_optional; ov->visitor.optional = &opts_optional;
ov->opts_root = opts; ov->opts_root = opts;

View File

@@ -17,46 +17,27 @@
#include "qapi/visitor.h" #include "qapi/visitor.h"
#include "qapi/visitor-impl.h" #include "qapi/visitor-impl.h"
void visit_start_handle(Visitor *v, void **obj, const char *kind,
const char *name, Error **errp)
{
if (!error_is_set(errp) && v->start_handle) {
v->start_handle(v, obj, kind, name, errp);
}
}
void visit_end_handle(Visitor *v, Error **errp)
{
if (!error_is_set(errp) && v->end_handle) {
v->end_handle(v, errp);
}
}
void visit_start_struct(Visitor *v, void **obj, const char *kind, void visit_start_struct(Visitor *v, void **obj, const char *kind,
const char *name, size_t size, Error **errp) const char *name, size_t size, Error **errp)
{ {
if (!error_is_set(errp)) { v->start_struct(v, obj, kind, name, size, errp);
v->start_struct(v, obj, kind, name, size, errp);
}
} }
void visit_end_struct(Visitor *v, Error **errp) void visit_end_struct(Visitor *v, Error **errp)
{ {
assert(!error_is_set(errp));
v->end_struct(v, errp); v->end_struct(v, errp);
} }
void visit_start_implicit_struct(Visitor *v, void **obj, size_t size, void visit_start_implicit_struct(Visitor *v, void **obj, size_t size,
Error **errp) Error **errp)
{ {
if (!error_is_set(errp) && v->start_implicit_struct) { if (v->start_implicit_struct) {
v->start_implicit_struct(v, obj, size, errp); v->start_implicit_struct(v, obj, size, errp);
} }
} }
void visit_end_implicit_struct(Visitor *v, Error **errp) void visit_end_implicit_struct(Visitor *v, Error **errp)
{ {
assert(!error_is_set(errp));
if (v->end_implicit_struct) { if (v->end_implicit_struct) {
v->end_implicit_struct(v, errp); v->end_implicit_struct(v, errp);
} }
@@ -64,45 +45,31 @@ void visit_end_implicit_struct(Visitor *v, Error **errp)
void visit_start_list(Visitor *v, const char *name, Error **errp) void visit_start_list(Visitor *v, const char *name, Error **errp)
{ {
if (!error_is_set(errp)) { v->start_list(v, name, errp);
v->start_list(v, name, errp);
}
} }
GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp) GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp)
{ {
if (!error_is_set(errp)) { return v->next_list(v, list, errp);
return v->next_list(v, list, errp);
}
return 0;
} }
void visit_end_list(Visitor *v, Error **errp) void visit_end_list(Visitor *v, Error **errp)
{ {
assert(!error_is_set(errp));
v->end_list(v, errp); v->end_list(v, errp);
} }
void visit_start_optional(Visitor *v, bool *present, const char *name, void visit_optional(Visitor *v, bool *present, const char *name,
Error **errp) Error **errp)
{ {
if (!error_is_set(errp) && v->start_optional) { if (v->optional) {
v->start_optional(v, present, name, errp); v->optional(v, present, name, errp);
}
}
void visit_end_optional(Visitor *v, Error **errp)
{
if (!error_is_set(errp) && v->end_optional) {
v->end_optional(v, errp);
} }
} }
void visit_get_next_type(Visitor *v, int *obj, const int *qtypes, void visit_get_next_type(Visitor *v, int *obj, const int *qtypes,
const char *name, Error **errp) const char *name, Error **errp)
{ {
if (!error_is_set(errp) && v->get_next_type) { if (v->get_next_type) {
v->get_next_type(v, obj, qtypes, name, errp); v->get_next_type(v, obj, qtypes, name, errp);
} }
} }
@@ -110,192 +77,172 @@ void visit_get_next_type(Visitor *v, int *obj, const int *qtypes,
void visit_type_enum(Visitor *v, int *obj, const char *strings[], void visit_type_enum(Visitor *v, int *obj, const char *strings[],
const char *kind, const char *name, Error **errp) const char *kind, const char *name, Error **errp)
{ {
if (!error_is_set(errp)) { v->type_enum(v, obj, strings, kind, name, errp);
v->type_enum(v, obj, strings, kind, name, errp);
}
} }
void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp) void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
{ {
if (!error_is_set(errp)) { v->type_int(v, obj, name, errp);
v->type_int(v, obj, name, errp);
}
} }
void visit_type_uint8(Visitor *v, uint8_t *obj, const char *name, Error **errp) void visit_type_uint8(Visitor *v, uint8_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_uint8) { if (v->type_uint8) {
v->type_uint8(v, obj, name, errp); v->type_uint8(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
if (value < 0 || value > UINT8_MAX) { if (value < 0 || value > UINT8_MAX) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
"uint8_t"); "uint8_t");
return; return;
}
*obj = value;
} }
*obj = value;
} }
} }
void visit_type_uint16(Visitor *v, uint16_t *obj, const char *name, Error **errp) void visit_type_uint16(Visitor *v, uint16_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_uint16) { if (v->type_uint16) {
v->type_uint16(v, obj, name, errp); v->type_uint16(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
if (value < 0 || value > UINT16_MAX) { if (value < 0 || value > UINT16_MAX) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
"uint16_t"); "uint16_t");
return; return;
}
*obj = value;
} }
*obj = value;
} }
} }
void visit_type_uint32(Visitor *v, uint32_t *obj, const char *name, Error **errp) void visit_type_uint32(Visitor *v, uint32_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_uint32) { if (v->type_uint32) {
v->type_uint32(v, obj, name, errp); v->type_uint32(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
if (value < 0 || value > UINT32_MAX) { if (value < 0 || value > UINT32_MAX) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
"uint32_t"); "uint32_t");
return; return;
}
*obj = value;
} }
*obj = value;
} }
} }
void visit_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp) void visit_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_uint64) { if (v->type_uint64) {
v->type_uint64(v, obj, name, errp); v->type_uint64(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
*obj = value; *obj = value;
}
} }
} }
void visit_type_int8(Visitor *v, int8_t *obj, const char *name, Error **errp) void visit_type_int8(Visitor *v, int8_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_int8) { if (v->type_int8) {
v->type_int8(v, obj, name, errp); v->type_int8(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
if (value < INT8_MIN || value > INT8_MAX) { if (value < INT8_MIN || value > INT8_MAX) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
"int8_t"); "int8_t");
return; return;
}
*obj = value;
} }
*obj = value;
} }
} }
void visit_type_int16(Visitor *v, int16_t *obj, const char *name, Error **errp) void visit_type_int16(Visitor *v, int16_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_int16) { if (v->type_int16) {
v->type_int16(v, obj, name, errp); v->type_int16(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
if (value < INT16_MIN || value > INT16_MAX) { if (value < INT16_MIN || value > INT16_MAX) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
"int16_t"); "int16_t");
return; return;
}
*obj = value;
} }
*obj = value;
} }
} }
void visit_type_int32(Visitor *v, int32_t *obj, const char *name, Error **errp) void visit_type_int32(Visitor *v, int32_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_int32) { if (v->type_int32) {
v->type_int32(v, obj, name, errp); v->type_int32(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
if (value < INT32_MIN || value > INT32_MAX) { if (value < INT32_MIN || value > INT32_MAX) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
"int32_t"); "int32_t");
return; return;
}
*obj = value;
} }
*obj = value;
} }
} }
void visit_type_int64(Visitor *v, int64_t *obj, const char *name, Error **errp) void visit_type_int64(Visitor *v, int64_t *obj, const char *name, Error **errp)
{ {
if (!error_is_set(errp)) { if (v->type_int64) {
if (v->type_int64) { v->type_int64(v, obj, name, errp);
v->type_int64(v, obj, name, errp); } else {
} else { v->type_int(v, obj, name, errp);
v->type_int(v, obj, name, errp);
}
} }
} }
void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp) void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_size) { if (v->type_size) {
v->type_size(v, obj, name, errp); v->type_size(v, obj, name, errp);
} else if (v->type_uint64) { } else if (v->type_uint64) {
v->type_uint64(v, obj, name, errp); v->type_uint64(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
*obj = value; *obj = value;
}
} }
} }
void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp) void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
{ {
if (!error_is_set(errp)) { v->type_bool(v, obj, name, errp);
v->type_bool(v, obj, name, errp);
}
} }
void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp) void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp)
{ {
if (!error_is_set(errp)) { v->type_str(v, obj, name, errp);
v->type_str(v, obj, name, errp);
}
} }
void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp) void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
{ {
if (!error_is_set(errp)) { v->type_number(v, obj, name, errp);
v->type_number(v, obj, name, errp);
}
} }
void output_type_enum(Visitor *v, int *obj, const char *strings[], void output_type_enum(Visitor *v, int *obj, const char *strings[],
@@ -321,13 +268,15 @@ void input_type_enum(Visitor *v, int *obj, const char *strings[],
const char *kind, const char *name, const char *kind, const char *name,
Error **errp) Error **errp)
{ {
Error *local_err = NULL;
int64_t value = 0; int64_t value = 0;
char *enum_str; char *enum_str;
assert(strings); assert(strings);
visit_type_str(v, &enum_str, name, errp); visit_type_str(v, &enum_str, name, &local_err);
if (error_is_set(errp)) { if (local_err) {
error_propagate(errp, local_err);
return; return;
} }

View File

@@ -286,8 +286,8 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
} }
} }
static void qmp_input_start_optional(Visitor *v, bool *present, static void qmp_input_optional(Visitor *v, bool *present, const char *name,
const char *name, Error **errp) Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, true); QObject *qobj = qmp_input_get_object(qiv, name, true);
@@ -329,7 +329,7 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
v->visitor.type_bool = qmp_input_type_bool; v->visitor.type_bool = qmp_input_type_bool;
v->visitor.type_str = qmp_input_type_str; v->visitor.type_str = qmp_input_type_str;
v->visitor.type_number = qmp_input_type_number; v->visitor.type_number = qmp_input_type_number;
v->visitor.start_optional = qmp_input_start_optional; v->visitor.optional = qmp_input_optional;
v->visitor.get_next_type = qmp_input_get_next_type; v->visitor.get_next_type = qmp_input_get_next_type;
qmp_input_push(v, obj, NULL); qmp_input_push(v, obj, NULL);

View File

@@ -120,8 +120,8 @@ static void parse_type_number(Visitor *v, double *obj, const char *name,
*obj = val; *obj = val;
} }
static void parse_start_optional(Visitor *v, bool *present, static void parse_optional(Visitor *v, bool *present, const char *name,
const char *name, Error **errp) Error **errp)
{ {
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
@@ -155,7 +155,7 @@ StringInputVisitor *string_input_visitor_new(const char *str)
v->visitor.type_bool = parse_type_bool; v->visitor.type_bool = parse_type_bool;
v->visitor.type_str = parse_type_str; v->visitor.type_str = parse_type_str;
v->visitor.type_number = parse_type_number; v->visitor.type_number = parse_type_number;
v->visitor.start_optional = parse_start_optional; v->visitor.optional = parse_optional;
v->string = str; v->string = str;
return v; return v;

View File

@@ -3204,6 +3204,7 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
void (*init)(struct CharDriverState *s), void (*init)(struct CharDriverState *s),
Error **errp) Error **errp)
{ {
Error *local_err = NULL;
CharDriver *cd; CharDriver *cd;
CharDriverState *chr; CharDriverState *chr;
GSList *i; GSList *i;
@@ -3245,13 +3246,14 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
chr = NULL; chr = NULL;
backend->kind = cd->kind; backend->kind = cd->kind;
if (cd->parse) { if (cd->parse) {
cd->parse(opts, backend, errp); cd->parse(opts, backend, &local_err);
if (error_is_set(errp)) { if (local_err) {
error_propagate(errp, local_err);
goto qapi_out; goto qapi_out;
} }
} }
ret = qmp_chardev_add(bid ? bid : id, backend, errp); ret = qmp_chardev_add(bid ? bid : id, backend, errp);
if (error_is_set(errp)) { if (!ret) {
goto qapi_out; goto qapi_out;
} }
@@ -3263,7 +3265,7 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
backend->kind = CHARDEV_BACKEND_KIND_MUX; backend->kind = CHARDEV_BACKEND_KIND_MUX;
backend->mux->chardev = g_strdup(bid); backend->mux->chardev = g_strdup(bid);
ret = qmp_chardev_add(id, backend, errp); ret = qmp_chardev_add(id, backend, errp);
if (error_is_set(errp)) { if (!ret) {
chr = qemu_chr_find(bid); chr = qemu_chr_find(bid);
qemu_chr_delete(chr); qemu_chr_delete(chr);
chr = NULL; chr = NULL;
@@ -3620,18 +3622,18 @@ static int qmp_chardev_open_file_source(char *src, int flags,
static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp)
{ {
int flags, in = -1, out = -1; int flags, in = -1, out;
flags = O_WRONLY | O_TRUNC | O_CREAT | O_BINARY; flags = O_WRONLY | O_TRUNC | O_CREAT | O_BINARY;
out = qmp_chardev_open_file_source(file->out, flags, errp); out = qmp_chardev_open_file_source(file->out, flags, errp);
if (error_is_set(errp)) { if (out < 0) {
return NULL; return NULL;
} }
if (file->has_in) { if (file->has_in) {
flags = O_RDONLY; flags = O_RDONLY;
in = qmp_chardev_open_file_source(file->in, flags, errp); in = qmp_chardev_open_file_source(file->in, flags, errp);
if (error_is_set(errp)) { if (in < 0) {
qemu_close(out); qemu_close(out);
return NULL; return NULL;
} }
@@ -3647,7 +3649,7 @@ static CharDriverState *qmp_chardev_open_serial(ChardevHostdev *serial,
int fd; int fd;
fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp); fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp);
if (error_is_set(errp)) { if (fd < 0) {
return NULL; return NULL;
} }
qemu_set_nonblock(fd); qemu_set_nonblock(fd);
@@ -3665,7 +3667,7 @@ static CharDriverState *qmp_chardev_open_parallel(ChardevHostdev *parallel,
int fd; int fd;
fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp); fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
if (error_is_set(errp)) { if (fd < 0) {
return NULL; return NULL;
} }
return qemu_chr_open_pp_fd(fd); return qemu_chr_open_pp_fd(fd);
@@ -3692,7 +3694,7 @@ static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock,
} else { } else {
fd = socket_connect(addr, errp, NULL, NULL); fd = socket_connect(addr, errp, NULL, NULL);
} }
if (error_is_set(errp)) { if (fd < 0) {
return NULL; return NULL;
} }
return qemu_chr_open_socket_fd(fd, do_nodelay, is_listen, return qemu_chr_open_socket_fd(fd, do_nodelay, is_listen,
@@ -3705,7 +3707,7 @@ static CharDriverState *qmp_chardev_open_udp(ChardevUdp *udp,
int fd; int fd;
fd = socket_dgram(udp->remote, udp->local, errp); fd = socket_dgram(udp->remote, udp->local, errp);
if (error_is_set(errp)) { if (fd < 0) {
return NULL; return NULL;
} }
return qemu_chr_open_udp_fd(fd); return qemu_chr_open_udp_fd(fd);
@@ -3796,7 +3798,13 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
break; break;
} }
if (chr == NULL && !error_is_set(errp)) { /*
* Character backend open hasn't been fully converted to the Error
* API. Some opens fail without setting an error. Set a generic
* error then.
* TODO full conversion to Error API
*/
if (chr == NULL && errp && !*errp) {
error_setg(errp, "Failed to create chardev"); error_setg(errp, "Failed to create chardev");
} }
if (chr) { if (chr) {

View File

@@ -70,11 +70,8 @@ static void add_format_to_seq(void *opaque, const char *fmt_name)
{ {
GSequence *seq = opaque; GSequence *seq = opaque;
if (!g_sequence_lookup(seq, (gpointer)fmt_name, g_sequence_insert_sorted(seq, (gpointer)fmt_name,
compare_data, NULL)) { compare_data, NULL);
g_sequence_insert_sorted(seq, (gpointer)fmt_name,
compare_data, NULL);
}
} }
static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...) static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...)

View File

@@ -414,6 +414,7 @@ DEF("drive", HAS_ARG, QEMU_OPTION_drive,
" [,serial=s][,addr=A][,rerror=ignore|stop|report]\n" " [,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n" " [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
" [,readonly=on|off][,copy-on-read=on|off]\n" " [,readonly=on|off][,copy-on-read=on|off]\n"
" [,detect-zeroes=on|off|unmap]\n"
" [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]]\n" " [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]]\n"
" [[,iops=i]|[[,iops_rd=r][,iops_wr=w]]]\n" " [[,iops=i]|[[,iops_rd=r][,iops_wr=w]]]\n"
" [[,bps_max=bm]|[[,bps_rd_max=rm][,bps_wr_max=wm]]]\n" " [[,bps_max=bm]|[[,bps_rd_max=rm][,bps_wr_max=wm]]]\n"
@@ -475,6 +476,11 @@ Open drive @option{file} as read-only. Guest write attempts will fail.
@item copy-on-read=@var{copy-on-read} @item copy-on-read=@var{copy-on-read}
@var{copy-on-read} is "on" or "off" and enables whether to copy read backing @var{copy-on-read} is "on" or "off" and enables whether to copy read backing
file sectors into the image file. file sectors into the image file.
@item detect-zeroes=@var{detect-zeroes}
@var{detect-zeroes} is "off", "on" or "unmap" and enables the automatic
conversion of plain zero writes by the OS to driver specific optimized
zero write commands. You may even choose "unmap" if @var{discard} is set
to "unmap" to allow a zero write to be converted to an UNMAP operation.
@end table @end table
By default, the @option{cache=writeback} mode is used. It will report data By default, the @option{cache=writeback} mode is used. It will report data
@@ -2191,6 +2197,74 @@ qemu-system-x86_64 --drive file=gluster://192.0.2.1/testvol/a.img
@end example @end example
See also @url{http://www.gluster.org}. See also @url{http://www.gluster.org}.
@item HTTP/HTTPS/FTP/FTPS/TFTP
QEMU supports read-only access to files accessed over http(s), ftp(s) and tftp.
Syntax using a single filename:
@example
<protocol>://[<username>[:<password>]@@]<host>/<path>
@end example
where:
@table @option
@item protocol
'http', 'https', 'ftp', 'ftps', or 'tftp'.
@item username
Optional username for authentication to the remote server.
@item password
Optional password for authentication to the remote server.
@item host
Address of the remote server.
@item path
Path on the remote server, including any query string.
@end table
The following options are also supported:
@table @option
@item url
The full URL when passing options to the driver explicitly.
@item readahead
The amount of data to read ahead with each range request to the remote server.
This value may optionally have the suffix 'T', 'G', 'M', 'K', 'k' or 'b'. If it
does not have a suffix, it will be assumed to be in bytes. The value must be a
multiple of 512 bytes. It defaults to 256k.
@item sslverify
Whether to verify the remote server's certificate when connecting over SSL. It
can have the value 'on' or 'off'. It defaults to 'on'.
@end table
Note that when passing options to qemu explicitly, @option{driver} is the value
of <protocol>.
Example: boot from a remote Fedora 20 live ISO image
@example
qemu-system-x86_64 --drive media=cdrom,file=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly
qemu-system-x86_64 --drive media=cdrom,file.driver=http,file.url=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly
@end example
Example: boot from a remote Fedora 20 cloud image using a local overlay for
writes, copy-on-read, and a readahead of 64k
@example
qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"http",, "file.url":"https://dl.fedoraproject.org/pub/fedora/linux/releases/20/Images/x86_64/Fedora-x86_64-20-20131211.1-sda.qcow2",, "file.readahead":"64k"@}' /tmp/Fedora-x86_64-20-20131211.1-sda.qcow2
qemu-system-x86_64 -drive file=/tmp/Fedora-x86_64-20-20131211.1-sda.qcow2,copy-on-read=on
@end example
Example: boot from an image stored on a VMware vSphere server with a self-signed
certificate using a local overlay for writes and a readahead of 64k
@example
qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"https",, "file.url":"https://user:password@@vsphere.example.com/folder/test/test-flat.vmdk?dcPath=Datacenter&dsName=datastore1",, "file.sslverify":"off",, "file.readahead":"64k"@}' /tmp/test.qcow2
qemu-system-x86_64 -drive file=/tmp/test.qcow2
@end example
ETEXI ETEXI
STEXI STEXI

View File

@@ -2032,6 +2032,8 @@ Each json-object contain the following:
- "iops_rd_max": read I/O operations max (json-int) - "iops_rd_max": read I/O operations max (json-int)
- "iops_wr_max": write I/O operations max (json-int) - "iops_wr_max": write I/O operations max (json-int)
- "iops_size": I/O size when limiting by iops (json-int) - "iops_size": I/O size when limiting by iops (json-int)
- "detect_zeroes": detect and optimize zero writing (json-string)
- Possible values: "off", "on", "unmap"
- "image": the detail of the image, it is a json-object containing - "image": the detail of the image, it is a json-object containing
the following: the following:
- "filename": image file name (json-string) - "filename": image file name (json-string)
@@ -2108,6 +2110,7 @@ Example:
"iops_rd_max": 0, "iops_rd_max": 0,
"iops_wr_max": 0, "iops_wr_max": 0,
"iops_size": 0, "iops_size": 0,
"detect_zeroes": "on",
"image":{ "image":{
"filename":"disks/test.qcow2", "filename":"disks/test.qcow2",
"format":"qcow2", "format":"qcow2",
@@ -2937,7 +2940,7 @@ block migration status.
The main json-object contains the following: The main json-object contains the following:
- "status": migration status (json-string) - "status": migration status (json-string)
- Possible values: "active", "completed", "failed", "cancelled" - Possible values: "setup", "active", "completed", "failed", "cancelled"
- "total-time": total amount of ms since migration started. If - "total-time": total amount of ms since migration started. If
migration has ended, it returns the total migration migration has ended, it returns the total migration
time (json-int) time (json-int)

View File

@@ -665,3 +665,35 @@ void qdict_array_split(QDict *src, QList **dst)
qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict)); qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict));
} }
} }
/**
* qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
* elements from src to dest.
*
* If an element from src has a key already present in dest, it will not be
* moved unless overwrite is true.
*
* If overwrite is true, the conflicting values in dest will be discarded and
* replaced by the corresponding values from src.
*
* Therefore, with overwrite being true, the src QDict will always be empty when
* this function returns. If overwrite is false, the src QDict will be empty
* iff there were no conflicts.
*/
void qdict_join(QDict *dest, QDict *src, bool overwrite)
{
const QDictEntry *entry, *next;
entry = qdict_first(src);
while (entry) {
next = qdict_next(src, entry);
if (overwrite || !qdict_haskey(dest, entry->key)) {
qobject_incref(entry->value);
qdict_put_obj(dest, entry->key, entry->value);
qdict_del(src, entry->key);
}
entry = next;
}
}

View File

@@ -2,16 +2,19 @@
# QAPI command marshaller generator # QAPI command marshaller generator
# #
# Copyright IBM, Corp. 2011 # Copyright IBM, Corp. 2011
# Copyright (C) 2014 Red Hat, Inc.
# #
# Authors: # Authors:
# Anthony Liguori <aliguori@us.ibm.com> # Anthony Liguori <aliguori@us.ibm.com>
# Michael Roth <mdroth@linux.vnet.ibm.com> # Michael Roth <mdroth@linux.vnet.ibm.com>
# Markus Armbruster <armbru@redhat.com>
# #
# This work is licensed under the terms of the GNU GPL, version 2. # This work is licensed under the terms of the GNU GPL, version 2.
# See the COPYING file in the top-level directory. # See the COPYING file in the top-level directory.
from ordereddict import OrderedDict from ordereddict import OrderedDict
from qapi import * from qapi import *
import re
import sys import sys
import os import os
import getopt import getopt
@@ -37,6 +40,15 @@ def generate_command_decl(name, args, ret_type):
''', ''',
ret_type=c_type(ret_type), name=c_fun(name), args=arglist).strip() ret_type=c_type(ret_type), name=c_fun(name), args=arglist).strip()
def gen_err_check(errvar):
if errvar:
return mcgen('''
if (local_err) {
goto out;
}
''')
return ''
def gen_sync_call(name, args, ret_type, indent=0): def gen_sync_call(name, args, ret_type, indent=0):
ret = "" ret = ""
arglist="" arglist=""
@@ -49,15 +61,14 @@ def gen_sync_call(name, args, ret_type, indent=0):
arglist += "%s, " % (c_var(argname)) arglist += "%s, " % (c_var(argname))
push_indent(indent) push_indent(indent)
ret = mcgen(''' ret = mcgen('''
%(retval)sqmp_%(name)s(%(args)serrp); %(retval)sqmp_%(name)s(%(args)s&local_err);
''', ''',
name=c_fun(name), args=arglist, retval=retval).rstrip() name=c_fun(name), args=arglist, retval=retval).rstrip()
if ret_type: if ret_type:
ret += "\n" + gen_err_check('local_err')
ret += "\n" + mcgen('''' ret += "\n" + mcgen(''''
if (!error_is_set(errp)) { %(marshal_output_call)s
%(marshal_output_call)s
}
''', ''',
marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip() marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip()
pop_indent(indent) pop_indent(indent)
@@ -67,18 +78,19 @@ if (!error_is_set(errp)) {
def gen_marshal_output_call(name, ret_type): def gen_marshal_output_call(name, ret_type):
if not ret_type: if not ret_type:
return "" return ""
return "qmp_marshal_output_%s(retval, ret, errp);" % c_fun(name) return "qmp_marshal_output_%s(retval, ret, &local_err);" % c_fun(name)
def gen_visitor_input_containers_decl(args): def gen_visitor_input_containers_decl(args, obj):
ret = "" ret = ""
push_indent() push_indent()
if len(args) > 0: if len(args) > 0:
ret += mcgen(''' ret += mcgen('''
QmpInputVisitor *mi; QmpInputVisitor *mi = qmp_input_visitor_new_strict(%(obj)s);
QapiDeallocVisitor *md; QapiDeallocVisitor *md;
Visitor *v; Visitor *v;
''') ''',
obj=obj)
pop_indent() pop_indent()
return ret.rstrip() return ret.rstrip()
@@ -99,16 +111,17 @@ bool has_%(argname)s = false;
argname=c_var(argname), argtype=c_type(argtype)) argname=c_var(argname), argtype=c_type(argtype))
else: else:
ret += mcgen(''' ret += mcgen('''
%(argtype)s %(argname)s; %(argtype)s %(argname)s = {0};
''', ''',
argname=c_var(argname), argtype=c_type(argtype)) argname=c_var(argname), argtype=c_type(argtype))
pop_indent() pop_indent()
return ret.rstrip() return ret.rstrip()
def gen_visitor_input_block(args, obj, dealloc=False): def gen_visitor_input_block(args, dealloc=False):
ret = "" ret = ""
errparg = 'errp' errparg = '&local_err'
errarg = 'local_err'
if len(args) == 0: if len(args) == 0:
return ret return ret
@@ -117,44 +130,44 @@ def gen_visitor_input_block(args, obj, dealloc=False):
if dealloc: if dealloc:
errparg = 'NULL' errparg = 'NULL'
errarg = None;
ret += mcgen(''' ret += mcgen('''
qmp_input_visitor_cleanup(mi);
md = qapi_dealloc_visitor_new(); md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md); v = qapi_dealloc_get_visitor(md);
''') ''')
else: else:
ret += mcgen(''' ret += mcgen('''
mi = qmp_input_visitor_new_strict(%(obj)s);
v = qmp_input_get_visitor(mi); v = qmp_input_get_visitor(mi);
''', ''')
obj=obj)
for argname, argtype, optional, structured in parse_args(args): for argname, argtype, optional, structured in parse_args(args):
if optional: if optional:
ret += mcgen(''' ret += mcgen('''
visit_start_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s); visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s);
if (has_%(c_name)s) {
''', ''',
c_name=c_var(argname), name=argname, errp=errparg) c_name=c_var(argname), name=argname, errp=errparg)
ret += gen_err_check(errarg)
ret += mcgen('''
if (has_%(c_name)s) {
''',
c_name=c_var(argname))
push_indent() push_indent()
ret += mcgen(''' ret += mcgen('''
%(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s); %(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s);
''', ''',
c_name=c_var(argname), name=argname, argtype=argtype, c_name=c_var(argname), name=argname, argtype=argtype,
visitor=type_visitor(argtype), errp=errparg) visitor=type_visitor(argtype), errp=errparg)
ret += gen_err_check(errarg)
if optional: if optional:
pop_indent() pop_indent()
ret += mcgen(''' ret += mcgen('''
} }
visit_end_optional(v, %(errp)s); ''')
''', errp=errparg)
if dealloc: if dealloc:
ret += mcgen(''' ret += mcgen('''
qapi_dealloc_visitor_cleanup(md); qapi_dealloc_visitor_cleanup(md);
''')
else:
ret += mcgen('''
qmp_input_visitor_cleanup(mi);
''') ''')
pop_indent() pop_indent()
return ret.rstrip() return ret.rstrip()
@@ -166,16 +179,22 @@ def gen_marshal_output(name, args, ret_type, middle_mode):
ret = mcgen(''' ret = mcgen('''
static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp) static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
{ {
QapiDeallocVisitor *md = qapi_dealloc_visitor_new(); Error *local_err = NULL;
QmpOutputVisitor *mo = qmp_output_visitor_new(); QmpOutputVisitor *mo = qmp_output_visitor_new();
QapiDeallocVisitor *md;
Visitor *v; Visitor *v;
v = qmp_output_get_visitor(mo); v = qmp_output_get_visitor(mo);
%(visitor)s(v, &ret_in, "unused", errp); %(visitor)s(v, &ret_in, "unused", &local_err);
if (!error_is_set(errp)) { if (local_err) {
*ret_out = qmp_output_get_qobject(mo); goto out;
} }
*ret_out = qmp_output_get_qobject(mo);
out:
error_propagate(errp, local_err);
qmp_output_visitor_cleanup(mo); qmp_output_visitor_cleanup(mo);
md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md); v = qapi_dealloc_get_visitor(md);
%(visitor)s(v, &ret_in, "unused", NULL); %(visitor)s(v, &ret_in, "unused", NULL);
qapi_dealloc_visitor_cleanup(md); qapi_dealloc_visitor_cleanup(md);
@@ -200,13 +219,12 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
ret = mcgen(''' ret = mcgen('''
%(header)s %(header)s
{ {
Error *local_err = NULL;
''', ''',
header=hdr) header=hdr)
if middle_mode: if middle_mode:
ret += mcgen(''' ret += mcgen('''
Error *local_err = NULL;
Error **errp = &local_err;
QDict *args = (QDict *)qdict; QDict *args = (QDict *)qdict;
''') ''')
@@ -228,29 +246,32 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
%(visitor_input_block)s %(visitor_input_block)s
''', ''',
visitor_input_containers_decl=gen_visitor_input_containers_decl(args), visitor_input_containers_decl=gen_visitor_input_containers_decl(args, "QOBJECT(args)"),
visitor_input_vars_decl=gen_visitor_input_vars_decl(args), visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)")) visitor_input_block=gen_visitor_input_block(args))
else: else:
ret += mcgen(''' ret += mcgen('''
(void)args; (void)args;
''') ''')
ret += mcgen(''' ret += mcgen('''
if (error_is_set(errp)) {
goto out;
}
%(sync_call)s %(sync_call)s
''', ''',
sync_call=gen_sync_call(name, args, ret_type, indent=4)) sync_call=gen_sync_call(name, args, ret_type, indent=4))
ret += mcgen(''' if re.search('^ *goto out\\;', ret, re.MULTILINE):
ret += mcgen('''
out: out:
''')
if not middle_mode:
ret += mcgen('''
error_propagate(errp, local_err);
''') ''')
ret += mcgen(''' ret += mcgen('''
%(visitor_input_block_cleanup)s %(visitor_input_block_cleanup)s
''', ''',
visitor_input_block_cleanup=gen_visitor_input_block(args, None, visitor_input_block_cleanup=gen_visitor_input_block(args,
dealloc=True)) dealloc=True))
if middle_mode: if middle_mode:

View File

@@ -2,21 +2,47 @@
# QAPI visitor generator # QAPI visitor generator
# #
# Copyright IBM, Corp. 2011 # Copyright IBM, Corp. 2011
# Copyright (C) 2014 Red Hat, Inc.
# #
# Authors: # Authors:
# Anthony Liguori <aliguori@us.ibm.com> # Anthony Liguori <aliguori@us.ibm.com>
# Michael Roth <mdroth@linux.vnet.ibm.com> # Michael Roth <mdroth@linux.vnet.ibm.com>
# Markus Armbruster <armbru@redhat.com>
# #
# This work is licensed under the terms of the GNU GPL, version 2. # This work is licensed under the terms of the GNU GPL, version 2.
# See the COPYING file in the top-level directory. # See the COPYING file in the top-level directory.
from ordereddict import OrderedDict from ordereddict import OrderedDict
from qapi import * from qapi import *
import re
import sys import sys
import os import os
import getopt import getopt
import errno import errno
implicit_structs = []
def generate_visit_implicit_struct(type):
global implicit_structs
if type in implicit_structs:
return ''
implicit_structs.append(type)
return mcgen('''
static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
{
Error *err = NULL;
visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
if (!err) {
visit_type_%(c_type)s_fields(m, obj, errp);
visit_end_implicit_struct(m, &err);
}
error_propagate(errp, err);
}
''',
c_type=type_name(type))
def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = None): def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = None):
substructs = [] substructs = []
ret = '' ret = ''
@@ -35,6 +61,19 @@ def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base =
nested_field_prefix = "%s%s." % (field_prefix, argname) nested_field_prefix = "%s%s." % (field_prefix, argname)
ret += generate_visit_struct_fields(name, nested_field_prefix, ret += generate_visit_struct_fields(name, nested_field_prefix,
nested_fn_prefix, argentry) nested_fn_prefix, argentry)
ret += mcgen('''
static void visit_type_%(full_name)s_field_%(c_name)s(Visitor *m, %(name)s **obj, Error **errp)
{
''',
name=name, full_name=full_name, c_name=c_var(argname))
ret += generate_visit_struct_body(full_name, argname, argentry)
ret += mcgen('''
}
''')
if base:
ret += generate_visit_implicit_struct(base)
ret += mcgen(''' ret += mcgen('''
@@ -47,12 +86,9 @@ static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s ** obj, Error *
if base: if base:
ret += mcgen(''' ret += mcgen('''
visit_start_implicit_struct(m, (void**) &(*obj)->%(c_name)s, sizeof(%(type)s), &err); visit_type_implicit_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, &err);
if (!err) { if (err) {
visit_type_%(type)s_fields(m, &(*obj)->%(c_prefix)s%(c_name)s, &err); goto out;
error_propagate(errp, err);
err = NULL;
visit_end_implicit_struct(m, &err);
} }
''', ''',
c_prefix=c_var(field_prefix), c_prefix=c_var(field_prefix),
@@ -61,15 +97,18 @@ if (!err) {
for argname, argentry, optional, structured in parse_args(members): for argname, argentry, optional, structured in parse_args(members):
if optional: if optional:
ret += mcgen(''' ret += mcgen('''
visit_start_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err); visit_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err);
if ((*obj)->%(prefix)shas_%(c_name)s) { if (!err && (*obj)->%(prefix)shas_%(c_name)s) {
''', ''',
c_prefix=c_var(field_prefix), prefix=field_prefix, c_prefix=c_var(field_prefix), prefix=field_prefix,
c_name=c_var(argname), name=argname) c_name=c_var(argname), name=argname)
push_indent() push_indent()
if structured: if structured:
ret += generate_visit_struct_body(full_name, argname, argentry) ret += mcgen('''
visit_type_%(full_name)s_field_%(c_name)s(m, obj, &err);
''',
full_name=full_name, c_name=c_var(argname))
else: else:
ret += mcgen(''' ret += mcgen('''
visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err); visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err);
@@ -82,12 +121,20 @@ visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err);
pop_indent() pop_indent()
ret += mcgen(''' ret += mcgen('''
} }
visit_end_optional(m, &err); ''')
ret += mcgen('''
if (err) {
goto out;
}
''') ''')
pop_indent() pop_indent()
ret += mcgen(''' if re.search('^ *goto out\\;', ret, re.MULTILINE):
ret += mcgen('''
out:
''')
ret += mcgen('''
error_propagate(errp, err); error_propagate(errp, err);
} }
''') ''')
@@ -96,9 +143,9 @@ visit_end_optional(m, &err);
def generate_visit_struct_body(field_prefix, name, members): def generate_visit_struct_body(field_prefix, name, members):
ret = mcgen(''' ret = mcgen('''
if (!error_is_set(errp)) { Error *err = NULL;
''') ''')
push_indent()
if not field_prefix: if not field_prefix:
full_name = name full_name = name
@@ -107,36 +154,26 @@ if (!error_is_set(errp)) {
if len(field_prefix): if len(field_prefix):
ret += mcgen(''' ret += mcgen('''
Error **errp = &err; /* from outer scope */ visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
Error *err = NULL;
visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
''', ''',
name=name) name=name)
else: else:
ret += mcgen(''' ret += mcgen('''
Error *err = NULL; visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
''', ''',
name=name) name=name)
ret += mcgen(''' ret += mcgen('''
if (!err) { if (!err) {
if (*obj) { if (*obj) {
visit_type_%(name)s_fields(m, obj, &err); visit_type_%(name)s_fields(m, obj, errp);
error_propagate(errp, err); }
err = NULL;
}
''',
name=full_name)
pop_indent()
ret += mcgen('''
/* Always call end_struct if start_struct succeeded. */
visit_end_struct(m, &err); visit_end_struct(m, &err);
} }
error_propagate(errp, err); error_propagate(errp, err);
} ''',
''') name=full_name)
return ret return ret
def generate_visit_struct(expr): def generate_visit_struct(expr):
@@ -154,9 +191,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
''', ''',
name=name) name=name)
push_indent()
ret += generate_visit_struct_body("", name, members) ret += generate_visit_struct_body("", name, members)
pop_indent()
ret += mcgen(''' ret += mcgen('''
} }
@@ -168,24 +203,26 @@ def generate_visit_list(name, members):
void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp) void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
{ {
GenericList *i, **prev = (GenericList **)obj;
Error *err = NULL; Error *err = NULL;
GenericList *i, **prev;
if (!error_is_set(errp)) { visit_start_list(m, name, &err);
visit_start_list(m, name, &err); if (err) {
if (!err) { goto out;
for (; (i = visit_next_list(m, prev, &err)) != NULL; prev = &i) {
%(name)sList *native_i = (%(name)sList *)i;
visit_type_%(name)s(m, &native_i->value, NULL, &err);
}
error_propagate(errp, err);
err = NULL;
/* Always call end_list if start_list succeeded. */
visit_end_list(m, &err);
}
error_propagate(errp, err);
} }
for (prev = (GenericList **)obj;
!err && (i = visit_next_list(m, prev, &err)) != NULL;
prev = &i) {
%(name)sList *native_i = (%(name)sList *)i;
visit_type_%(name)s(m, &native_i->value, NULL, &err);
}
error_propagate(errp, err);
err = NULL;
visit_end_list(m, &err);
out:
error_propagate(errp, err);
} }
''', ''',
name=name) name=name)
@@ -207,10 +244,15 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
{ {
Error *err = NULL; Error *err = NULL;
if (!error_is_set(errp)) { visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err); if (err) {
visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err); goto out;
switch ((*obj)->kind) { }
visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
if (err) {
goto out_end;
}
switch ((*obj)->kind) {
''', ''',
name=name) name=name)
@@ -225,22 +267,24 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
enum_full_value = generate_enum_full_value(disc_type, key) enum_full_value = generate_enum_full_value(disc_type, key)
ret += mcgen(''' ret += mcgen('''
case %(enum_full_value)s: case %(enum_full_value)s:
visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
break; break;
''', ''',
enum_full_value = enum_full_value, enum_full_value = enum_full_value,
c_type = type_name(members[key]), c_type = type_name(members[key]),
c_name = c_fun(key)) c_name = c_fun(key))
ret += mcgen(''' ret += mcgen('''
default: default:
abort(); abort();
}
error_propagate(errp, err);
err = NULL;
visit_end_implicit_struct(m, &err);
} }
out_end:
error_propagate(errp, err);
err = NULL;
visit_end_implicit_struct(m, &err);
out:
error_propagate(errp, err);
} }
''') ''')
@@ -277,40 +321,43 @@ def generate_visit_union(expr):
del base_fields[discriminator] del base_fields[discriminator]
ret += generate_visit_struct_fields(name, "", "", base_fields) ret += generate_visit_struct_fields(name, "", "", base_fields)
if discriminator:
for key in members:
ret += generate_visit_implicit_struct(members[key])
ret += mcgen(''' ret += mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp) void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
{ {
Error *err = NULL; Error *err = NULL;
if (!error_is_set(errp)) { visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); if (err) {
if (!err) { goto out;
if (*obj) { }
if (*obj) {
''', ''',
name=name) name=name)
push_indent()
push_indent()
push_indent()
if base: if base:
ret += mcgen(''' ret += mcgen('''
visit_type_%(name)s_fields(m, obj, &err); visit_type_%(name)s_fields(m, obj, &err);
if (err) {
goto out_obj;
}
''', ''',
name=name) name=name)
pop_indent()
if not discriminator: if not discriminator:
disc_key = "type" disc_key = "type"
else: else:
disc_key = discriminator disc_key = discriminator
ret += mcgen(''' ret += mcgen('''
visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err); visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
if (!err) { if (err) {
switch ((*obj)->kind) { goto out_obj;
}
switch ((*obj)->kind) {
''', ''',
disc_type = disc_type, disc_type = disc_type,
disc_key = disc_key) disc_key = disc_key)
@@ -319,45 +366,30 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
if not discriminator: if not discriminator:
fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);' fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
else: else:
fmt = '''visit_start_implicit_struct(m, (void**) &(*obj)->%(c_name)s, sizeof(%(c_type)s), &err); fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
if (!err) {
visit_type_%(c_type)s_fields(m, &(*obj)->%(c_name)s, &err);
error_propagate(errp, err);
err = NULL;
visit_end_implicit_struct(m, &err);
}'''
enum_full_value = generate_enum_full_value(disc_type, key) enum_full_value = generate_enum_full_value(disc_type, key)
ret += mcgen(''' ret += mcgen('''
case %(enum_full_value)s: case %(enum_full_value)s:
''' + fmt + ''' ''' + fmt + '''
break; break;
''', ''',
enum_full_value = enum_full_value, enum_full_value = enum_full_value,
c_type=type_name(members[key]), c_type=type_name(members[key]),
c_name=c_fun(key)) c_name=c_fun(key))
ret += mcgen(''' ret += mcgen('''
default: default:
abort(); abort();
}
} }
out_obj:
error_propagate(errp, err); error_propagate(errp, err);
err = NULL; err = NULL;
} }
''') visit_end_struct(m, &err);
pop_indent() out:
ret += mcgen('''
/* Always call end_struct if start_struct succeeded. */
visit_end_struct(m, &err);
}
error_propagate(errp, err); error_propagate(errp, err);
} }
''')
pop_indent();
ret += mcgen('''
}
''') ''')
return ret return ret
@@ -476,7 +508,7 @@ fdecl.write(mcgen('''
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
/* /*
* schema-defined QAPI visitor function * schema-defined QAPI visitor functions
* *
* Copyright IBM, Corp. 2011 * Copyright IBM, Corp. 2011
* *

View File

@@ -73,13 +73,18 @@ class QAPIExprError(Exception):
class QAPISchema: class QAPISchema:
def __init__(self, fp, input_relname=None, include_hist=[], parent_info=None): def __init__(self, fp, input_relname=None, include_hist=[],
previously_included=[], parent_info=None):
""" include_hist is a stack used to detect inclusion cycles
previously_included is a global state used to avoid multiple
inclusions of the same file"""
input_fname = os.path.abspath(fp.name) input_fname = os.path.abspath(fp.name)
if input_relname is None: if input_relname is None:
input_relname = fp.name input_relname = fp.name
self.input_dir = os.path.dirname(input_fname) self.input_dir = os.path.dirname(input_fname)
self.input_file = input_relname self.input_file = input_relname
self.include_hist = include_hist + [(input_relname, input_fname)] self.include_hist = include_hist + [(input_relname, input_fname)]
previously_included.append(input_fname)
self.parent_info = parent_info self.parent_info = parent_info
self.src = fp.read() self.src = fp.read()
if self.src == '' or self.src[-1] != '\n': if self.src == '' or self.src[-1] != '\n':
@@ -106,13 +111,16 @@ class QAPISchema:
for elem in self.include_hist): for elem in self.include_hist):
raise QAPIExprError(expr_info, "Inclusion loop for %s" raise QAPIExprError(expr_info, "Inclusion loop for %s"
% include) % include)
# skip multiple include of the same file
if include_path in previously_included:
continue
try: try:
fobj = open(include_path, 'r') fobj = open(include_path, 'r')
except IOError as e: except IOError, e:
raise QAPIExprError(expr_info, raise QAPIExprError(expr_info,
'%s: %s' % (e.strerror, include)) '%s: %s' % (e.strerror, include))
exprs_include = QAPISchema(fobj, include, exprs_include = QAPISchema(fobj, include, self.include_hist,
self.include_hist, expr_info) previously_included, expr_info)
self.exprs.extend(exprs_include.exprs) self.exprs.extend(exprs_include.exprs)
else: else:
expr_elem = {'expr': expr, expr_elem = {'expr': expr,

View File

@@ -86,6 +86,7 @@ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
int s390_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, int s390_cpu_write_elf64_qemunote(WriteCoreDumpFunction f,
CPUState *cpu, void *opaque); CPUState *cpu, void *opaque);
hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);

View File

@@ -489,6 +489,18 @@ hwaddr s390_cpu_get_phys_page_debug(CPUState *cs, vaddr vaddr)
return raddr; return raddr;
} }
hwaddr s390_cpu_get_phys_addr_debug(CPUState *cs, vaddr vaddr)
{
hwaddr phys_addr;
target_ulong page;
page = vaddr & TARGET_PAGE_MASK;
phys_addr = cpu_get_phys_page_debug(cs, page);
phys_addr += (vaddr & ~TARGET_PAGE_MASK);
return phys_addr;
}
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr) void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
{ {
if (mask & PSW_MASK_WAIT) { if (mask & PSW_MASK_WAIT) {

View File

@@ -36,6 +36,7 @@
#include "sysemu/device_tree.h" #include "sysemu/device_tree.h"
#include "qapi/qmp/qjson.h" #include "qapi/qmp/qjson.h"
#include "monitor/monitor.h" #include "monitor/monitor.h"
#include "exec/gdbstub.h"
#include "trace.h" #include "trace.h"
/* #define DEBUG_KVM */ /* #define DEBUG_KVM */
@@ -86,6 +87,14 @@
#define ICPT_CPU_STOP 0x28 #define ICPT_CPU_STOP 0x28
#define ICPT_IO 0x40 #define ICPT_IO 0x40
static CPUWatchpoint hw_watchpoint;
/*
* We don't use a list because this structure is also used to transmit the
* hardware breakpoints to the kernel.
*/
static struct kvm_hw_breakpoint *hw_breakpoints;
static int nb_hw_breakpoints;
const KVMCapabilityInfo kvm_arch_required_capabilities[] = { const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
KVM_CAP_LAST_INFO KVM_CAP_LAST_INFO
}; };
@@ -320,12 +329,16 @@ static void *legacy_s390_alloc(size_t size)
return mem == MAP_FAILED ? NULL : mem; return mem == MAP_FAILED ? NULL : mem;
} }
/* DIAG 501 is used for sw breakpoints */
static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
{ {
static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)diag_501, 4, 1)) { sizeof(diag_501), 0) ||
cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)diag_501,
sizeof(diag_501), 1)) {
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
@@ -333,38 +346,140 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
{ {
uint8_t t[4]; uint8_t t[sizeof(diag_501)];
static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
if (cpu_memory_rw_debug(cs, bp->pc, t, 4, 0)) { if (cpu_memory_rw_debug(cs, bp->pc, t, sizeof(diag_501), 0)) {
return -EINVAL; return -EINVAL;
} else if (memcmp(t, diag_501, 4)) { } else if (memcmp(t, diag_501, sizeof(diag_501))) {
return -EINVAL; return -EINVAL;
} else if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) { } else if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
sizeof(diag_501), 1)) {
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
} }
static struct kvm_hw_breakpoint *find_hw_breakpoint(target_ulong addr,
int len, int type)
{
int n;
for (n = 0; n < nb_hw_breakpoints; n++) {
if (hw_breakpoints[n].addr == addr && hw_breakpoints[n].type == type &&
(hw_breakpoints[n].len == len || len == -1)) {
return &hw_breakpoints[n];
}
}
return NULL;
}
static int insert_hw_breakpoint(target_ulong addr, int len, int type)
{
int size;
if (find_hw_breakpoint(addr, len, type)) {
return -EEXIST;
}
size = (nb_hw_breakpoints + 1) * sizeof(struct kvm_hw_breakpoint);
if (!hw_breakpoints) {
nb_hw_breakpoints = 0;
hw_breakpoints = (struct kvm_hw_breakpoint *)g_try_malloc(size);
} else {
hw_breakpoints =
(struct kvm_hw_breakpoint *)g_try_realloc(hw_breakpoints, size);
}
if (!hw_breakpoints) {
nb_hw_breakpoints = 0;
return -ENOMEM;
}
hw_breakpoints[nb_hw_breakpoints].addr = addr;
hw_breakpoints[nb_hw_breakpoints].len = len;
hw_breakpoints[nb_hw_breakpoints].type = type;
nb_hw_breakpoints++;
return 0;
}
int kvm_arch_insert_hw_breakpoint(target_ulong addr, int kvm_arch_insert_hw_breakpoint(target_ulong addr,
target_ulong len, int type) target_ulong len, int type)
{ {
return -ENOSYS; switch (type) {
case GDB_BREAKPOINT_HW:
type = KVM_HW_BP;
break;
case GDB_WATCHPOINT_WRITE:
if (len < 1) {
return -EINVAL;
}
type = KVM_HW_WP_WRITE;
break;
default:
return -ENOSYS;
}
return insert_hw_breakpoint(addr, len, type);
} }
int kvm_arch_remove_hw_breakpoint(target_ulong addr, int kvm_arch_remove_hw_breakpoint(target_ulong addr,
target_ulong len, int type) target_ulong len, int type)
{ {
return -ENOSYS; int size;
struct kvm_hw_breakpoint *bp = find_hw_breakpoint(addr, len, type);
if (bp == NULL) {
return -ENOENT;
}
nb_hw_breakpoints--;
if (nb_hw_breakpoints > 0) {
/*
* In order to trim the array, move the last element to the position to
* be removed - if necessary.
*/
if (bp != &hw_breakpoints[nb_hw_breakpoints]) {
*bp = hw_breakpoints[nb_hw_breakpoints];
}
size = nb_hw_breakpoints * sizeof(struct kvm_hw_breakpoint);
hw_breakpoints =
(struct kvm_hw_breakpoint *)g_realloc(hw_breakpoints, size);
} else {
g_free(hw_breakpoints);
hw_breakpoints = NULL;
}
return 0;
} }
void kvm_arch_remove_all_hw_breakpoints(void) void kvm_arch_remove_all_hw_breakpoints(void)
{ {
nb_hw_breakpoints = 0;
g_free(hw_breakpoints);
hw_breakpoints = NULL;
} }
void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
{ {
int i;
if (nb_hw_breakpoints > 0) {
dbg->arch.nr_hw_bp = nb_hw_breakpoints;
dbg->arch.hw_bp = hw_breakpoints;
for (i = 0; i < nb_hw_breakpoints; ++i) {
hw_breakpoints[i].phys_addr = s390_cpu_get_phys_addr_debug(cpu,
hw_breakpoints[i].addr);
}
dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
} else {
dbg->arch.nr_hw_bp = 0;
dbg->arch.hw_bp = NULL;
}
} }
void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
@@ -579,6 +694,22 @@ static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run)
handle_diag_308(&cpu->env, r1, r3); handle_diag_308(&cpu->env, r1, r3);
} }
static int handle_sw_breakpoint(S390CPU *cpu, struct kvm_run *run)
{
CPUS390XState *env = &cpu->env;
unsigned long pc;
cpu_synchronize_state(CPU(cpu));
pc = env->psw.addr - 4;
if (kvm_find_sw_breakpoint(CPU(cpu), pc)) {
env->psw.addr = pc;
return EXCP_DEBUG;
}
return -ENOENT;
}
#define DIAG_KVM_CODE_MASK 0x000000000000ffff #define DIAG_KVM_CODE_MASK 0x000000000000ffff
static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb) static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
@@ -599,7 +730,7 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
r = handle_hypercall(cpu, run); r = handle_hypercall(cpu, run);
break; break;
case DIAG_KVM_BREAKPOINT: case DIAG_KVM_BREAKPOINT:
sleep(10); r = handle_sw_breakpoint(cpu, run);
break; break;
default: default:
DPRINTF("KVM: unknown DIAG: 0x%x\n", func_code); DPRINTF("KVM: unknown DIAG: 0x%x\n", func_code);
@@ -701,7 +832,7 @@ out:
return 0; return 0;
} }
static void handle_instruction(S390CPU *cpu, struct kvm_run *run) static int handle_instruction(S390CPU *cpu, struct kvm_run *run)
{ {
unsigned int ipa0 = (run->s390_sieic.ipa & 0xff00); unsigned int ipa0 = (run->s390_sieic.ipa & 0xff00);
uint8_t ipa1 = run->s390_sieic.ipa & 0x00ff; uint8_t ipa1 = run->s390_sieic.ipa & 0x00ff;
@@ -728,8 +859,11 @@ static void handle_instruction(S390CPU *cpu, struct kvm_run *run)
} }
if (r < 0) { if (r < 0) {
r = 0;
enter_pgmcheck(cpu, 0x0001); enter_pgmcheck(cpu, 0x0001);
} }
return r;
} }
static bool is_special_wait_psw(CPUState *cs) static bool is_special_wait_psw(CPUState *cs)
@@ -749,7 +883,7 @@ static int handle_intercept(S390CPU *cpu)
(long)cs->kvm_run->psw_addr); (long)cs->kvm_run->psw_addr);
switch (icpt_code) { switch (icpt_code) {
case ICPT_INSTRUCTION: case ICPT_INSTRUCTION:
handle_instruction(cpu, run); r = handle_instruction(cpu, run);
break; break;
case ICPT_WAITPSW: case ICPT_WAITPSW:
/* disabled wait, since enabled wait is handled in kernel */ /* disabled wait, since enabled wait is handled in kernel */
@@ -830,7 +964,36 @@ static int handle_tsch(S390CPU *cpu)
static int kvm_arch_handle_debug_exit(S390CPU *cpu) static int kvm_arch_handle_debug_exit(S390CPU *cpu)
{ {
return -ENOSYS; CPUState *cs = CPU(cpu);
struct kvm_run *run = cs->kvm_run;
int ret = 0;
struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
switch (arch_info->type) {
case KVM_HW_WP_WRITE:
if (find_hw_breakpoint(arch_info->addr, -1, arch_info->type)) {
cs->watchpoint_hit = &hw_watchpoint;
hw_watchpoint.vaddr = arch_info->addr;
hw_watchpoint.flags = BP_MEM_WRITE;
ret = EXCP_DEBUG;
}
break;
case KVM_HW_BP:
if (find_hw_breakpoint(arch_info->addr, -1, arch_info->type)) {
ret = EXCP_DEBUG;
}
break;
case KVM_SINGLESTEP:
if (cs->singlestep_enabled) {
ret = EXCP_DEBUG;
}
break;
default:
ret = -ENOSYS;
}
return ret;
} }
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
@@ -911,6 +1074,16 @@ void kvm_s390_enable_css_support(S390CPU *cpu)
void kvm_arch_init_irq_routing(KVMState *s) void kvm_arch_init_irq_routing(KVMState *s)
{ {
/*
* Note that while irqchip capabilities generally imply that cpustates
* are handled in-kernel, it is not true for s390 (yet); therefore, we
* have to override the common code kvm_halt_in_kernel_allowed setting.
*/
if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
kvm_irqfds_allowed = true;
kvm_gsi_routing_allowed = true;
kvm_halt_in_kernel_allowed = false;
}
} }
int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,

View File

@@ -193,7 +193,8 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
flat-union-string-discriminator.json \ flat-union-string-discriminator.json \
include-simple.json include-relpath.json include-format-err.json \ include-simple.json include-relpath.json include-format-err.json \
include-non-file.json include-no-file.json include-before-err.json \ include-non-file.json include-no-file.json include-before-err.json \
include-nested-err.json include-self-cycle.json include-cycle.json) include-nested-err.json include-self-cycle.json include-cycle.json \
include-repetition.json)
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h

View File

@@ -444,6 +444,92 @@ static void qdict_array_split_test(void)
QDECREF(test_dict); QDECREF(test_dict);
} }
static void qdict_join_test(void)
{
QDict *dict1, *dict2;
bool overwrite = false;
int i;
dict1 = qdict_new();
dict2 = qdict_new();
/* Test everything once without overwrite and once with */
do
{
/* Test empty dicts */
qdict_join(dict1, dict2, overwrite);
g_assert(qdict_size(dict1) == 0);
g_assert(qdict_size(dict2) == 0);
/* First iteration: Test movement */
/* Second iteration: Test empty source and non-empty destination */
qdict_put(dict2, "foo", qint_from_int(42));
for (i = 0; i < 2; i++) {
qdict_join(dict1, dict2, overwrite);
g_assert(qdict_size(dict1) == 1);
g_assert(qdict_size(dict2) == 0);
g_assert(qdict_get_int(dict1, "foo") == 42);
}
/* Test non-empty source and destination without conflict */
qdict_put(dict2, "bar", qint_from_int(23));
qdict_join(dict1, dict2, overwrite);
g_assert(qdict_size(dict1) == 2);
g_assert(qdict_size(dict2) == 0);
g_assert(qdict_get_int(dict1, "foo") == 42);
g_assert(qdict_get_int(dict1, "bar") == 23);
/* Test conflict */
qdict_put(dict2, "foo", qint_from_int(84));
qdict_join(dict1, dict2, overwrite);
g_assert(qdict_size(dict1) == 2);
g_assert(qdict_size(dict2) == !overwrite);
g_assert(qdict_get_int(dict1, "foo") == overwrite ? 84 : 42);
g_assert(qdict_get_int(dict1, "bar") == 23);
if (!overwrite) {
g_assert(qdict_get_int(dict2, "foo") == 84);
}
/* Check the references */
g_assert(qdict_get(dict1, "foo")->refcnt == 1);
g_assert(qdict_get(dict1, "bar")->refcnt == 1);
if (!overwrite) {
g_assert(qdict_get(dict2, "foo")->refcnt == 1);
}
/* Clean up */
qdict_del(dict1, "foo");
qdict_del(dict1, "bar");
if (!overwrite) {
qdict_del(dict2, "foo");
}
}
while (overwrite ^= true);
QDECREF(dict1);
QDECREF(dict2);
}
/* /*
* Errors test-cases * Errors test-cases
*/ */
@@ -584,6 +670,7 @@ int main(int argc, char **argv)
g_test_add_func("/public/iterapi", qdict_iterapi_test); g_test_add_func("/public/iterapi", qdict_iterapi_test);
g_test_add_func("/public/flatten", qdict_flatten_test); g_test_add_func("/public/flatten", qdict_flatten_test);
g_test_add_func("/public/array_split", qdict_array_split_test); g_test_add_func("/public/array_split", qdict_array_split_test);
g_test_add_func("/public/join", qdict_join_test);
g_test_add_func("/errors/put_exists", qdict_put_exists_test); g_test_add_func("/errors/put_exists", qdict_put_exists_test);
g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test); g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test);

View File

@@ -0,0 +1,2 @@
{ 'include': 'comments.json' }
{ 'include': 'comments.json' }

View File

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1,3 @@
{ 'include': 'comments.json' }
{ 'include': 'include-repetition-sub.json' }
{ 'include': 'comments.json' }

View File

@@ -0,0 +1,3 @@
[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}]
[]

View File

@@ -35,7 +35,7 @@ class TestSingleDrive(iotests.QMPTestCase):
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
qemu_io('-c', 'write -P 0x1 0 512', backing_img) qemu_io('-c', 'write -P 0x1 0 512', backing_img)
self.vm = iotests.VM().add_drive(test_img) self.vm = iotests.VM().add_drive("blkdebug::" + test_img)
self.vm.launch() self.vm.launch()
def tearDown(self): def tearDown(self):

View File

@@ -47,6 +47,11 @@ _supported_os Linux
_default_cache_mode "writethrough" _default_cache_mode "writethrough"
_supported_cache_modes "writethrough" _supported_cache_modes "writethrough"
_no_dump_exec()
{
(ulimit -c 0; exec "$@")
}
size=128M size=128M
echo echo
@@ -67,10 +72,7 @@ echo "== Creating a dirty image file =="
IMGOPTS="compat=1.1,lazy_refcounts=on" IMGOPTS="compat=1.1,lazy_refcounts=on"
_make_test_img $size _make_test_img $size
old_ulimit=$(ulimit -c) _no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
ulimit -c 0 # do not produce a core dump on abort(3)
$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
ulimit -c "$old_ulimit"
# The dirty bit must be set # The dirty bit must be set
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features ./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
@@ -103,10 +105,7 @@ echo "== Opening a dirty image read/write should repair it =="
IMGOPTS="compat=1.1,lazy_refcounts=on" IMGOPTS="compat=1.1,lazy_refcounts=on"
_make_test_img $size _make_test_img $size
old_ulimit=$(ulimit -c) _no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
ulimit -c 0 # do not produce a core dump on abort(3)
$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
ulimit -c "$old_ulimit"
# The dirty bit must be set # The dirty bit must be set
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features ./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
@@ -122,10 +121,7 @@ echo "== Creating an image file with lazy_refcounts=off =="
IMGOPTS="compat=1.1,lazy_refcounts=off" IMGOPTS="compat=1.1,lazy_refcounts=off"
_make_test_img $size _make_test_img $size
old_ulimit=$(ulimit -c) _no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
ulimit -c 0 # do not produce a core dump on abort(3)
$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
ulimit -c "$old_ulimit"
# The dirty bit must not be set since lazy_refcounts=off # The dirty bit must not be set since lazy_refcounts=off
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features ./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features

View File

@@ -11,6 +11,7 @@ No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./039: Aborted ( ulimit -c 0; exec "$@" )
incompatible_features 0x1 incompatible_features 0x1
ERROR cluster 5 refcount=0 reference=1 ERROR cluster 5 refcount=0 reference=1
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0 ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
@@ -42,6 +43,7 @@ read 512/512 bytes at offset 0
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./039: Aborted ( ulimit -c 0; exec "$@" )
incompatible_features 0x1 incompatible_features 0x1
Repairing cluster 5 refcount=0 reference=1 Repairing cluster 5 refcount=0 reference=1
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
@@ -52,6 +54,7 @@ incompatible_features 0x0
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./039: Aborted ( ulimit -c 0; exec "$@" )
incompatible_features 0x0 incompatible_features 0x0
No errors were found on the image. No errors were found on the image.

View File

@@ -6,7 +6,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virtio-blk-pci,drive=disk,id=virtio0 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virtio-blk-pci,drive=disk,id=virtio0
QMP_VERSION QMP_VERSION
{"return": {}} {"return": {}}
{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]} {"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
@@ -24,7 +24,7 @@ QMP_VERSION
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
QMP_VERSION QMP_VERSION
{"return": {}} {"return": {}}
{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]} {"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
@@ -44,7 +44,7 @@ Testing:
QMP_VERSION QMP_VERSION
{"return": {}} {"return": {}}
{"return": "OK\r\n"} {"return": "OK\r\n"}
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]} {"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
@@ -64,14 +64,14 @@ Testing:
QMP_VERSION QMP_VERSION
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]} {"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "RESET"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "RESET"}
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]} {"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
{"return": {}} {"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}

View File

@@ -72,6 +72,13 @@ echo "=== Verify open image read-only succeeds after log replay ==="
$QEMU_IO -r -c "read -pP 0xa5 0 18M" "$TEST_IMG" 2>&1 | _filter_testdir \ $QEMU_IO -r -c "read -pP 0xa5 0 18M" "$TEST_IMG" 2>&1 | _filter_testdir \
| _filter_qemu_io | _filter_qemu_io
_cleanup_test_img
_use_sample_img test-disk2vhd.vhdx.bz2
echo
echo "=== Verify image created by Disk2VHD can be opened ==="
$QEMU_IMG info "$TEST_IMG" 2>&1 | _filter_testdir | _filter_qemu
# success, all done # success, all done
echo "*** done" echo "*** done"
rm -f $seq.full rm -f $seq.full

View File

@@ -18,4 +18,11 @@ No errors were found on the image.
=== Verify open image read-only succeeds after log replay === === Verify open image read-only succeeds after log replay ===
read 18874368/18874368 bytes at offset 0 read 18874368/18874368 bytes at offset 0
18 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 18 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Verify image created by Disk2VHD can be opened ===
image: TEST_DIR/test-disk2vhd.vhdx
file format: vhdx
virtual size: 256M (268435456 bytes)
disk size: 260M
cluster_size: 2097152
*** done *** done

130
tests/qemu-iotests/089 Executable file
View File

@@ -0,0 +1,130 @@
#!/bin/bash
#
# Test case for support of JSON filenames
#
# Copyright (C) 2014 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# creator
owner=mreitz@redhat.com
seq="$(basename $0)"
echo "QA output created by $seq"
here="$PWD"
tmp=/tmp/$$
status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
# get standard environment, filters and checks
. ./common.rc
. ./common.filter
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
# Using an image filename containing quotation marks will render the JSON data
# below invalid. In that case, we have little choice but simply not to run this
# test.
case $TEST_IMG in
*'"'*)
_notrun "image filename may not contain quotation marks"
;;
esac
IMG_SIZE=64M
# Taken from test 072
echo
echo "=== Testing nested image formats ==="
echo
TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE
$QEMU_IO -c 'write -P 42 0 512' -c 'write -P 23 512 512' \
-c 'write -P 66 1024 512' "$TEST_IMG.base" | _filter_qemu_io
$QEMU_IMG convert -f raw -O $IMGFMT "$TEST_IMG.base" "$TEST_IMG"
$QEMU_IO -c 'read -P 42 0 512' -c 'read -P 23 512 512' \
-c 'read -P 66 1024 512' "json:{
\"driver\": \"$IMGFMT\",
\"file\": {
\"driver\": \"$IMGFMT\",
\"file\": {
\"filename\": \"$TEST_IMG\"
}
}
}" | _filter_qemu_io
# This should fail (see test 072)
$QEMU_IO -c 'read -P 42 0 512' "$TEST_IMG" | _filter_qemu_io
# Taken from test 071
echo
echo "=== Testing blkdebug ==="
echo
_make_test_img $IMG_SIZE
$QEMU_IO -c 'write -P 42 0x38000 512' "$TEST_IMG" | _filter_qemu_io
# The "image.filename" part tests whether "a": { "b": "c" } and "a.b": "c" do
# the same (which they should).
$QEMU_IO -c 'read -P 42 0x38000 512' "json:{
\"driver\": \"$IMGFMT\",
\"file\": {
\"driver\": \"blkdebug\",
\"inject-error\": [{
\"event\": \"l2_load\"
}],
\"image.filename\": \"$TEST_IMG\"
}
}" | _filter_qemu_io
echo
echo "=== Testing qemu-img info output ==="
echo
$QEMU_IMG info "json:{\"driver\":\"qcow2\",\"file.filename\":\"$TEST_IMG\"}" \
| _filter_testdir | _filter_imgfmt
echo
echo "=== Testing option merging ==="
echo
# Both options given directly and those given in the filename should be used
$QEMU_IO -c "open -o driver=qcow2 json:{\"file.filename\":\"$TEST_IMG\"}" \
-c "info" 2>&1 | _filter_testdir | _filter_imgfmt
# Options given directly should be prioritized over those given in the filename
$QEMU_IO -c "open -o driver=qcow2 json:{\"driver\":\"raw\",\"file.filename\":\"$TEST_IMG\"}" \
-c "info" 2>&1 | _filter_testdir | _filter_imgfmt
# success, all done
echo "*** done"
rm -f $seq.full
status=0

View File

@@ -0,0 +1,54 @@
QA output created by 089
=== Testing nested image formats ===
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 512/512 bytes at offset 512
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 512/512 bytes at offset 1024
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 512/512 bytes at offset 512
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 512/512 bytes at offset 1024
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Pattern verification failed at offset 0, 512 bytes
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Testing blkdebug ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
wrote 512/512 bytes at offset 229376
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read failed: Input/output error
=== Testing qemu-img info output ===
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 64M (67108864 bytes)
disk size: 324K
cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
=== Testing option merging ===
format name: IMGFMT
cluster size: 64 KiB
vm state offset: 512 MiB
Format specific information:
compat: 1.1
lazy refcounts: false
format name: IMGFMT
cluster size: 64 KiB
vm state offset: 512 MiB
Format specific information:
compat: 1.1
lazy refcounts: false
*** done

98
tests/qemu-iotests/092 Executable file
View File

@@ -0,0 +1,98 @@
#!/bin/bash
#
# qcow1 format input validation tests
#
# Copyright (C) 2014 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# creator
owner=kwolf@redhat.com
seq=`basename $0`
echo "QA output created by $seq"
here=`pwd`
tmp=/tmp/$$
status=1 # failure is the default!
_cleanup()
{
rm -f $TEST_IMG.snap
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
# get standard environment, filters and checks
. ./common.rc
. ./common.filter
_supported_fmt qcow
_supported_proto generic
_supported_os Linux
offset_backing_file_offset=8
offset_backing_file_size=16
offset_size=24
offset_cluster_bits=32
offset_l2_bits=33
echo
echo "== Invalid cluster size =="
_make_test_img 64M
poke_file "$TEST_IMG" "$offset_cluster_bits" "\xff"
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
poke_file "$TEST_IMG" "$offset_cluster_bits" "\x1f"
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
poke_file "$TEST_IMG" "$offset_cluster_bits" "\x08"
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
poke_file "$TEST_IMG" "$offset_cluster_bits" "\x11"
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
echo
echo "== Invalid L2 table size =="
_make_test_img 64M
poke_file "$TEST_IMG" "$offset_l2_bits" "\xff"
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
poke_file "$TEST_IMG" "$offset_l2_bits" "\x05"
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
poke_file "$TEST_IMG" "$offset_l2_bits" "\x0e"
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
# 1 << 0x1b = 2^31 / L2_CACHE_SIZE
poke_file "$TEST_IMG" "$offset_l2_bits" "\x1b"
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
echo
echo "== Invalid size =="
_make_test_img 64M
poke_file "$TEST_IMG" "$offset_size" "\xee\xee\xee\xee\xee\xee\xee\xee"
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
poke_file "$TEST_IMG" "$offset_size" "\x7f\xff\xff\xff\xff\xff\xff\xff"
{ $QEMU_IO -c "write 0 64M" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
echo
echo "== Invalid backing file length =="
_make_test_img 64M
poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\xff"
poke_file "$TEST_IMG" "$offset_backing_file_size" "\xff\xff\xff\xff"
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
poke_file "$TEST_IMG" "$offset_backing_file_size" "\x7f\xff\xff\xff"
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
# success, all done
echo "*** done"
rm -f $seq.full
status=0

View File

@@ -0,0 +1,38 @@
QA output created by 092
== Invalid cluster size ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
no file open, try 'help open'
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
no file open, try 'help open'
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
no file open, try 'help open'
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
no file open, try 'help open'
== Invalid L2 table size ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
no file open, try 'help open'
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
no file open, try 'help open'
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
no file open, try 'help open'
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
no file open, try 'help open'
== Invalid size ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
qemu-io: can't open device TEST_DIR/t.qcow: Image too large
no file open, try 'help open'
qemu-io: can't open device TEST_DIR/t.qcow: Image too large
no file open, try 'help open'
== Invalid backing file length ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long
no file open, try 'help open'
qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long
no file open, try 'help open'
*** done

View File

@@ -150,6 +150,7 @@ _filter_win32()
_filter_qemu_io() _filter_qemu_io()
{ {
_filter_win32 | sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \ _filter_win32 | sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \
-e "s/: line [0-9][0-9]*: *[0-9][0-9]*\( Aborted\)/:\1/" \
-e "s/qemu-io> //g" -e "s/qemu-io> //g"
} }

View File

@@ -95,5 +95,7 @@
086 rw auto quick 086 rw auto quick
087 rw auto 087 rw auto
088 rw auto 088 rw auto
089 rw auto quick
090 rw auto quick 090 rw auto quick
091 rw auto 091 rw auto
092 rw auto quick

View File

@@ -72,14 +72,30 @@ typedef struct TestStruct
static void visit_type_TestStruct(Visitor *v, TestStruct **obj, static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
const char *name, Error **errp) const char *name, Error **errp)
{ {
Error *err = NULL;
visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
errp); &err);
if (err) {
goto out;
}
visit_type_int(v, &(*obj)->integer, "integer", errp); visit_type_int(v, &(*obj)->integer, "integer", &err);
visit_type_bool(v, &(*obj)->boolean, "boolean", errp); if (err) {
visit_type_str(v, &(*obj)->string, "string", errp); goto out_end;
}
visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
if (err) {
goto out_end;
}
visit_type_str(v, &(*obj)->string, "string", &err);
visit_end_struct(v, errp); out_end:
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
out:
error_propagate(errp, err);
} }
static void test_validate_struct(TestInputVisitorData *data, static void test_validate_struct(TestInputVisitorData *data,

View File

@@ -199,16 +199,24 @@ static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
&err); &err);
if (!err) { if (err) {
visit_type_int(v, &(*obj)->integer, "integer", &err); goto out;
visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
visit_type_str(v, &(*obj)->string, "string", &err);
/* Always call end_struct if start_struct succeeded. */
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
} }
visit_type_int(v, &(*obj)->integer, "integer", &err);
if (err) {
goto out_end;
}
visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
if (err) {
goto out_end;
}
visit_type_str(v, &(*obj)->string, "string", &err);
out_end:
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
out:
error_propagate(errp, err); error_propagate(errp, err);
} }

View File

@@ -176,14 +176,30 @@ typedef struct TestStruct
static void visit_type_TestStruct(Visitor *v, TestStruct **obj, static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
const char *name, Error **errp) const char *name, Error **errp)
{ {
Error *err = NULL;
visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
errp); &err);
if (err) {
goto out;
}
visit_type_int(v, &(*obj)->integer, "integer", errp); visit_type_int(v, &(*obj)->integer, "integer", &err);
visit_type_bool(v, &(*obj)->boolean, "boolean", errp); if (err) {
visit_type_str(v, &(*obj)->string, "string", errp); goto out_end;
}
visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
if (err) {
goto out_end;
}
visit_type_str(v, &(*obj)->string, "string", &err);
visit_end_struct(v, errp); out_end:
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
out:
error_propagate(errp, err);
} }
static void test_visitor_out_struct(TestOutputVisitorData *data, static void test_visitor_out_struct(TestOutputVisitorData *data,

View File

@@ -195,13 +195,29 @@ typedef struct TestStruct
static void visit_type_TestStruct(Visitor *v, TestStruct **obj, static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
const char *name, Error **errp) const char *name, Error **errp)
{ {
visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), errp); Error *err = NULL;
visit_type_int(v, &(*obj)->integer, "integer", errp); visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), &err);
visit_type_bool(v, &(*obj)->boolean, "boolean", errp); if (err) {
visit_type_str(v, &(*obj)->string, "string", errp); goto out;
}
visit_end_struct(v, errp); visit_type_int(v, &(*obj)->integer, "integer", &err);
if (err) {
goto out_end;
}
visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
if (err) {
goto out_end;
}
visit_type_str(v, &(*obj)->string, "string", &err);
out_end:
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
out:
error_propagate(errp, err);
} }
static TestStruct *struct_create(void) static TestStruct *struct_create(void)

View File

@@ -688,17 +688,21 @@ megasas_dcmd_ld_get_list(int cmd, int num, int max) "scmd %d: DCMD LD get list:
megasas_dcmd_ld_get_info(int cmd, int ld_id) "scmd %d: DCMD LD get info for dev %d" megasas_dcmd_ld_get_info(int cmd, int ld_id) "scmd %d: DCMD LD get info for dev %d"
megasas_dcmd_pd_get_info(int cmd, int pd_id) "scmd %d: DCMD PD get info for dev %d" megasas_dcmd_pd_get_info(int cmd, int pd_id) "scmd %d: DCMD PD get info for dev %d"
megasas_dcmd_pd_list_query(int cmd, int flags) "scmd %d: DCMD PD list query flags %x" megasas_dcmd_pd_list_query(int cmd, int flags) "scmd %d: DCMD PD list query flags %x"
megasas_dcmd_ld_list_query(int cmd, int flags) "scmd %d: DCMD LD list query flags %x"
megasas_dcmd_unsupported(int cmd, unsigned long size) "scmd %d: set properties len %ld" megasas_dcmd_unsupported(int cmd, unsigned long size) "scmd %d: set properties len %ld"
megasas_abort_frame(int cmd, int abort_cmd) "scmd %d: aborting frame %x" megasas_abort_frame(int cmd, int abort_cmd) "scmd %d: aborting frame %x"
megasas_abort_no_cmd(int cmd, uint64_t context) "scmd %d: no active command for frame context %" PRIx64 "" megasas_abort_no_cmd(int cmd, uint64_t context) "scmd %d: no active command for frame context %" PRIx64 ""
megasas_abort_invalid_context(int cmd, uint64_t context, int abort_cmd) "scmd %d: invalid frame context %" PRIx64 " for abort frame %x" megasas_abort_invalid_context(int cmd, uint64_t context, int abort_cmd) "scmd %d: invalid frame context %" PRIx64 " for abort frame %x"
megasas_reset(void) "Reset" megasas_reset(void) "Reset"
megasas_init(int sges, int cmds, const char *intr, const char *mode) "Using %d sges, %d cmds, %s, %s mode" megasas_init(int sges, int cmds, const char *mode) "Using %d sges, %d cmds, %s mode"
megasas_msix_raise(int vector) "vector %d" megasas_msix_raise(int vector) "vector %d"
megasas_msi_raise(int vector) "vector %d"
megasas_irq_lower(void) "INTx" megasas_irq_lower(void) "INTx"
megasas_irq_raise(void) "INTx" megasas_irq_raise(void) "INTx"
megasas_intr_enabled(void) "Interrupts enabled" megasas_intr_enabled(void) "Interrupts enabled"
megasas_intr_disabled(void) "Interrupts disabled" megasas_intr_disabled(void) "Interrupts disabled"
megasas_msix_enabled(int vector) "vector %d"
megasas_msi_enabled(int vector) "vector %d"
megasas_mmio_readl(unsigned long addr, uint32_t val) "addr 0x%lx: 0x%x" megasas_mmio_readl(unsigned long addr, uint32_t val) "addr 0x%lx: 0x%x"
megasas_mmio_invalid_readl(unsigned long addr) "addr 0x%lx" megasas_mmio_invalid_readl(unsigned long addr) "addr 0x%lx"
megasas_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x" megasas_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x"
@@ -1046,7 +1050,7 @@ gd_update(int x, int y, int w, int h) "x=%d, y=%d, w=%d, h=%d"
gd_key_event(int gdk_keycode, int qemu_keycode, const char *action) "translated GDK keycode %d to QEMU keycode %d (%s)" gd_key_event(int gdk_keycode, int qemu_keycode, const char *action) "translated GDK keycode %d to QEMU keycode %d (%s)"
# ui/input.c # ui/input.c
input_event_key_number(int conidx, int number, bool down) "con %d, key number 0x%x, down %d" input_event_key_number(int conidx, int number, const char *qcode, bool down) "con %d, key number 0x%x [%s], down %d"
input_event_key_qcode(int conidx, const char *qcode, bool down) "con %d, key qcode %s, down %d" input_event_key_qcode(int conidx, const char *qcode, bool down) "con %d, key qcode %s, down %d"
input_event_btn(int conidx, const char *btn, bool down) "con %d, button %s, down %d" input_event_btn(int conidx, const char *btn, bool down) "con %d, button %s, down %d"
input_event_rel(int conidx, const char *axis, int value) "con %d, axis %s, value %d" input_event_rel(int conidx, const char *axis, int value) "con %d, axis %s, value %d"

View File

@@ -288,8 +288,8 @@ static void curses_refresh(DisplayChangeListener *dcl)
qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true); qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true);
} }
qemu_input_event_send_key_number(NULL, keycode, true); qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, true);
qemu_input_event_send_key_number(NULL, keycode, false); qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, false);
if (keycode & ALTGR) { if (keycode & ALTGR) {
qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false); qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false);

View File

@@ -13,6 +13,8 @@ static const int qcode_to_number[] = {
[Q_KEY_CODE_CTRL] = 0x1d, [Q_KEY_CODE_CTRL] = 0x1d,
[Q_KEY_CODE_CTRL_R] = 0x9d, [Q_KEY_CODE_CTRL_R] = 0x9d,
[Q_KEY_CODE_META_L] = 0xdb,
[Q_KEY_CODE_META_R] = 0xdc,
[Q_KEY_CODE_MENU] = 0xdd, [Q_KEY_CODE_MENU] = 0xdd,
[Q_KEY_CODE_ESC] = 0x01, [Q_KEY_CODE_ESC] = 0x01,
@@ -129,7 +131,7 @@ static const int qcode_to_number[] = {
[Q_KEY_CODE_MAX] = 0, [Q_KEY_CODE_MAX] = 0,
}; };
static int number_to_qcode[0xff]; static int number_to_qcode[0x100];
int qemu_input_key_value_to_number(const KeyValue *value) int qemu_input_key_value_to_number(const KeyValue *value)
{ {
@@ -141,7 +143,7 @@ int qemu_input_key_value_to_number(const KeyValue *value)
} }
} }
int qemu_input_key_value_to_qcode(const KeyValue *value) int qemu_input_key_number_to_qcode(uint8_t nr)
{ {
static int first = true; static int first = true;
@@ -155,11 +157,16 @@ int qemu_input_key_value_to_qcode(const KeyValue *value)
} }
} }
return number_to_qcode[nr];
}
int qemu_input_key_value_to_qcode(const KeyValue *value)
{
if (value->kind == KEY_VALUE_KIND_QCODE) { if (value->kind == KEY_VALUE_KIND_QCODE) {
return value->qcode; return value->qcode;
} else { } else {
assert(value->kind == KEY_VALUE_KIND_NUMBER); assert(value->kind == KEY_VALUE_KIND_NUMBER);
return number_to_qcode[value->number]; return qemu_input_key_number_to_qcode(value->number);
} }
} }

View File

@@ -1,3 +1,4 @@
#include "hw/qdev.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "qapi-types.h" #include "qapi-types.h"
#include "qmp-commands.h" #include "qmp-commands.h"
@@ -10,6 +11,7 @@ struct QemuInputHandlerState {
QemuInputHandler *handler; QemuInputHandler *handler;
int id; int id;
int events; int events;
QemuConsole *con;
QTAILQ_ENTRY(QemuInputHandlerState) node; QTAILQ_ENTRY(QemuInputHandlerState) node;
}; };
static QTAILQ_HEAD(, QemuInputHandlerState) handlers = static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
@@ -53,12 +55,46 @@ void qemu_input_handler_unregister(QemuInputHandlerState *s)
qemu_input_check_mode_change(); qemu_input_check_mode_change();
} }
void qemu_input_handler_bind(QemuInputHandlerState *s,
const char *device_id, int head,
Error **errp)
{
DeviceState *dev;
QemuConsole *con;
dev = qdev_find_recursive(sysbus_get_default(), device_id);
if (dev == NULL) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device_id);
return;
}
con = qemu_console_lookup_by_device(dev, head);
if (con == NULL) {
error_setg(errp, "Device %s is not bound to a QemuConsole", device_id);
return;
}
s->con = con;
}
static QemuInputHandlerState* static QemuInputHandlerState*
qemu_input_find_handler(uint32_t mask) qemu_input_find_handler(uint32_t mask, QemuConsole *con)
{ {
QemuInputHandlerState *s; QemuInputHandlerState *s;
QTAILQ_FOREACH(s, &handlers, node) { QTAILQ_FOREACH(s, &handlers, node) {
if (s->con == NULL || s->con != con) {
continue;
}
if (mask & s->handler->mask) {
return s;
}
}
QTAILQ_FOREACH(s, &handlers, node) {
if (s->con != NULL) {
continue;
}
if (mask & s->handler->mask) { if (mask & s->handler->mask) {
return s; return s;
} }
@@ -94,7 +130,7 @@ static void qemu_input_transform_abs_rotate(InputEvent *evt)
static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt) static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
{ {
const char *name; const char *name;
int idx = -1; int qcode, idx = -1;
if (src) { if (src) {
idx = qemu_console_get_index(src); idx = qemu_console_get_index(src);
@@ -103,8 +139,10 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
case INPUT_EVENT_KIND_KEY: case INPUT_EVENT_KIND_KEY:
switch (evt->key->key->kind) { switch (evt->key->key->kind) {
case KEY_VALUE_KIND_NUMBER: case KEY_VALUE_KIND_NUMBER:
qcode = qemu_input_key_number_to_qcode(evt->key->key->number);
name = QKeyCode_lookup[qcode];
trace_input_event_key_number(idx, evt->key->key->number, trace_input_event_key_number(idx, evt->key->key->number,
evt->key->down); name, evt->key->down);
break; break;
case KEY_VALUE_KIND_QCODE: case KEY_VALUE_KIND_QCODE:
name = QKeyCode_lookup[evt->key->key->qcode]; name = QKeyCode_lookup[evt->key->key->qcode];
@@ -149,7 +187,7 @@ void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
} }
/* send event */ /* send event */
s = qemu_input_find_handler(1 << evt->kind); s = qemu_input_find_handler(1 << evt->kind, src);
if (!s) { if (!s) {
return; return;
} }
@@ -250,7 +288,8 @@ bool qemu_input_is_absolute(void)
{ {
QemuInputHandlerState *s; QemuInputHandlerState *s;
s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS); s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS,
NULL);
return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS); return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
} }

View File

@@ -190,30 +190,33 @@ static void sdl_switch(DisplayChangeListener *dcl,
} }
} }
static void reset_keys(void) static void reset_keys(struct sdl2_state *scon)
{ {
QemuConsole *con = scon ? scon->dcl.con : NULL;
int i; int i;
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
if (modifiers_state[i]) { if (modifiers_state[i]) {
int qcode = sdl2_scancode_to_qcode[i]; int qcode = sdl2_scancode_to_qcode[i];
qemu_input_event_send_key_qcode(NULL, qcode, false); qemu_input_event_send_key_qcode(con, qcode, false);
modifiers_state[i] = 0; modifiers_state[i] = 0;
} }
} }
} }
static void sdl_process_key(SDL_KeyboardEvent *ev) static void sdl_process_key(struct sdl2_state *scon,
SDL_KeyboardEvent *ev)
{ {
int qcode = sdl2_scancode_to_qcode[ev->keysym.scancode]; int qcode = sdl2_scancode_to_qcode[ev->keysym.scancode];
QemuConsole *con = scon ? scon->dcl.con : NULL;
switch (ev->keysym.scancode) { switch (ev->keysym.scancode) {
#if 0 #if 0
case SDL_SCANCODE_NUMLOCKCLEAR: case SDL_SCANCODE_NUMLOCKCLEAR:
case SDL_SCANCODE_CAPSLOCK: case SDL_SCANCODE_CAPSLOCK:
/* SDL does not send the key up event, so we generate it */ /* SDL does not send the key up event, so we generate it */
qemu_input_event_send_key_qcode(NULL, qcode, true); qemu_input_event_send_key_qcode(con, qcode, true);
qemu_input_event_send_key_qcode(NULL, qcode, false); qemu_input_event_send_key_qcode(con, qcode, false);
return; return;
#endif #endif
case SDL_SCANCODE_LCTRL: case SDL_SCANCODE_LCTRL:
@@ -231,7 +234,7 @@ static void sdl_process_key(SDL_KeyboardEvent *ev)
} }
/* fall though */ /* fall though */
default: default:
qemu_input_event_send_key_qcode(NULL, qcode, qemu_input_event_send_key_qcode(con, qcode,
ev->type == SDL_KEYDOWN); ev->type == SDL_KEYDOWN);
} }
} }
@@ -506,7 +509,7 @@ static void handle_keydown(SDL_Event *ev)
} }
} }
if (!gui_keysym) { if (!gui_keysym) {
sdl_process_key(&ev->key); sdl_process_key(scon, &ev->key);
} }
} }
@@ -531,13 +534,13 @@ static void handle_keyup(SDL_Event *ev)
} }
/* SDL does not send back all the modifiers key, so we must /* SDL does not send back all the modifiers key, so we must
* correct it. */ * correct it. */
reset_keys(); reset_keys(scon);
return; return;
} }
gui_keysym = 0; gui_keysym = 0;
} }
if (!gui_keysym) { if (!gui_keysym) {
sdl_process_key(&ev->key); sdl_process_key(scon, &ev->key);
} }
} }

View File

@@ -142,11 +142,6 @@ Error *error_copy(const Error *err)
return err_new; return err_new;
} }
bool error_is_set(Error **errp)
{
return (errp && *errp);
}
ErrorClass error_get_class(const Error *err) ErrorClass error_get_class(const Error *err)
{ {
return err->err_class; return err->err_class;

View File

@@ -335,6 +335,27 @@ void qemu_iovec_concat(QEMUIOVector *dst,
qemu_iovec_concat_iov(dst, src->iov, src->niov, soffset, sbytes); qemu_iovec_concat_iov(dst, src->iov, src->niov, soffset, sbytes);
} }
/*
* Check if the contents of the iovecs are all zero
*/
bool qemu_iovec_is_zero(QEMUIOVector *qiov)
{
int i;
for (i = 0; i < qiov->niov; i++) {
size_t offs = QEMU_ALIGN_DOWN(qiov->iov[i].iov_len, 4 * sizeof(long));
uint8_t *ptr = qiov->iov[i].iov_base;
if (offs && !buffer_is_zero(qiov->iov[i].iov_base, offs)) {
return false;
}
for (; offs < qiov->iov[i].iov_len; offs++) {
if (ptr[offs]) {
return false;
}
}
}
return true;
}
void qemu_iovec_destroy(QEMUIOVector *qiov) void qemu_iovec_destroy(QEMUIOVector *qiov)
{ {
assert(qiov->nalloc != -1); assert(qiov->nalloc != -1);

View File

@@ -354,6 +354,7 @@ static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp)
int inet_connect_opts(QemuOpts *opts, Error **errp, int inet_connect_opts(QemuOpts *opts, Error **errp,
NonBlockingConnectHandler *callback, void *opaque) NonBlockingConnectHandler *callback, void *opaque)
{ {
Error *local_err = NULL;
struct addrinfo *res, *e; struct addrinfo *res, *e;
int sock = -1; int sock = -1;
bool in_progress; bool in_progress;
@@ -372,24 +373,27 @@ int inet_connect_opts(QemuOpts *opts, Error **errp,
} }
for (e = res; e != NULL; e = e->ai_next) { for (e = res; e != NULL; e = e->ai_next) {
if (error_is_set(errp)) { error_free(local_err);
error_free(*errp); local_err = NULL;
*errp = NULL;
}
if (connect_state != NULL) { if (connect_state != NULL) {
connect_state->current_addr = e; connect_state->current_addr = e;
} }
sock = inet_connect_addr(e, &in_progress, connect_state, errp); sock = inet_connect_addr(e, &in_progress, connect_state, &local_err);
if (in_progress) { if (sock >= 0) {
return sock;
} else if (sock >= 0) {
/* non blocking socket immediate success, call callback */
if (callback != NULL) {
callback(sock, opaque);
}
break; break;
} }
} }
if (sock < 0) {
error_propagate(errp, local_err);
} else if (in_progress) {
/* wait_for_connect() will do the rest */
return sock;
} else {
if (callback) {
callback(sock, opaque);
}
}
g_free(connect_state); g_free(connect_state);
freeaddrinfo(res); freeaddrinfo(res);
return sock; return sock;