Compare commits

..

58 Commits

Author SHA1 Message Date
Michael Roth
57105f7480 update VERSION for 1.4.1
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-15 14:18:25 -05:00
Daniel P. Berrange
6e8865313f Add -f FMT / --format FMT arg to qemu-nbd
Currently the qemu-nbd program will auto-detect the format of
any disk it is given. This behaviour is known to be insecure.
For example, if qemu-nbd initially exposes a 'raw' file to an
unprivileged app, and that app runs

   'qemu-img create -f qcow2 -o backing_file=/etc/shadow /dev/nbd0'

then the next time the app is started, the qemu-nbd will now
detect it as a 'qcow2' file and expose /etc/shadow to the
unprivileged app.

The only way to avoid this is to explicitly tell qemu-nbd what
disk format to use on the command line, completely disabling
auto-detection. This patch adds a '-f' / '--format' arg for
this purpose, mirroring what is already available via qemu-img
and qemu commands.

  qemu-nbd --format raw -p 9000 evil.img

will now always use raw, regardless of what format 'evil.img'
looks like it contains

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
[Use errx, not err. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>

*fixed conflict due to bdrv_open() not supporting "options" param
in v1.4.1

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-09 10:00:20 -05:00
Richard Sandiford
6d0b135a98 target-mips: Fix accumulator selection for MIPS16 and microMIPS
Add accumulator arguments to gen_HILO and gen_muldiv, rather than
extracting the accumulator directly from ctx->opcode.  The extraction
was only right for the standard encoding: MIPS16 doesn't have access
to the DSP registers, while microMIPS encodes the accumulator register
in a different field (bits 14 and 15).

Passing the accumulator register is probably an over-generalisation
for division and 64-bit multiplication, which never access anything
other than HI and LO, and which always pass 0 as the new argument.
Separating them felt a bit fussy though.

Signed-off-by: Richard Sandiford <rdsandiford@googlemail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 26135ead80)

Conflicts:
	target-mips/translate.c

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-09 09:59:17 -05:00
Brad Smith
d89f9ba43b Allow clock_gettime() monotonic clock to be utilized on more OS's
Allow the clock_gettime() code using monotonic clock to be utilized on
more POSIX compliannt OS's. This started as a fix for OpenBSD which was
listed in one function as part of the previous hard coded list of OS's
for the functions to support but not in the other.

Signed-off-by: Brad Smith <brad@comstyle.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 20130405003748.GH884@rox.home.comstyle.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit d05ef16045)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-06 16:38:15 -05:00
Eduardo Habkost
46f9071a23 target-i386: Check for host features before filter_features_for_kvm()
commit 5ec01c2e96 broke "-cpu ..,enforce",
as it has moved kvm_check_features_against_host() after the
filter_features_for_kvm() call. filter_features_for_kvm() removes all
features not supported by the host, so this effectively made
kvm_check_features_against_host() impossible to fail.

This patch changes the call so we check for host feature support before
filtering the feature bits.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Message-id: 1364935692-24004-1-git-send-email-ehabkost@redhat.com
Cc: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit a509d632c8)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-05 14:01:33 -05:00
Jason Wang
f85e082a36 help: add docs for missing 'queues' option of tap
Cc: Markus Armbruster <armbru@redhat.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Jason Wang <jasowang@redhat.com>
Message-id: 1361545072-30426-1-git-send-email-jasowang@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit ec3960148f)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-05 13:57:17 -05:00
Paolo Bonzini
da78a1bc7a compiler: fix warning with GCC 4.8.0
GCC 4.8.0 introduces a new warning:

    block/qcow2-snapshot.c: In function 'qcow2_write_snapshots’:
    block/qcow2-snapshot.c:252:18: error: typedef 'qemu_build_bug_on__253'
              locally defined but not used [-Werror=unused-local-typedefs]
         QEMU_BUILD_BUG_ON(offsetof(QCowHeader, snapshots_offset) !=
                  ^
    cc1: all warnings being treated as errors

(Caret diagnostics aren't perfect yet with macros... :)) Work around it
with __attribute__((unused)).

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1364391272-1128-1-git-send-email-pbonzini@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 99835e0084)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 19:53:21 -05:00
Peter Lieven
2b92aa36d1 block: complete all IOs before resizing a device
this patch ensures that all pending IOs are completed
before a device is resized. this is especially important
if a device is shrinked as it the bdrv_check_request()
result is invalidated.

Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 92b7a08d64)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 17:36:43 -05:00
Peter Lieven
e4cce2d3e9 Revert "block: complete all IOs before .bdrv_truncate"
brdv_truncate() is also called from readv/writev commands on self-
growing file based storage. this will result in requests waiting
for theirselves to complete.

This reverts commit 9a665b2b86.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 5c916681ae)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 17:35:43 -05:00
Gerd Hoffmann
d15b1aa30c qxl: better vga init in enter_vga_mode
Ask the vga core to update the display.  Will trigger dpy_gfx_resize
if needed.  More complete than just calling dpy_gfx_resize.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit c099e7aa02)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 17:33:55 -05:00
Markus Armbruster
65fe29ec00 doc: Fix texinfo @table markup in qemu-options.hx
End tables before headings, start new ones afterwards.  Fixes
incorrect indentation of headings "File system options" and "Virtual
File system pass-through options" in manual page and qemu-doc.

Normalize markup some to increase chances it survives future edits.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: 1360781383-28635-5-git-send-email-armbru@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit c70a01e449)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 17:29:28 -05:00
Bruce Rogers
888e036eb4 acpi: initialize s4_val used in s4 shutdown
While investigating why a 32 bit Windows 2003 guest wasn't able to
successfully perform a shutdown /h, it was discovered that commit
afafe4bbe0 inadvertently dropped the
initialization of the s4_val used to handle s4 shutdown.
Initialize the value as before.

Signed-off-by: Bruce Rogers <brogers@suse.com>
Message-id: 1364928100-487-1-git-send-email-brogers@suse.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 560e639652)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 17:24:55 -05:00
Petar Jovanovic
d019dd928c target-mips: fix rndrashift_short_acc and code for EXTR_ instructions
Fix for rndrashift_short_acc to set correct value to higher 64 bits.
This change also corrects conditions when bit 23 of the DSPControl register
is set.

The existing test files have been extended with several examples that
trigger the issues. One bug/example in the test file for EXTR_RS_W has been
found and reported by Klaus Peichl.

Signed-off-by: Petar Jovanovic <petar.jovanovic@imgtec.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 8b758d0568)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 16:58:41 -05:00
Petar Jovanovic
dac077f0e6 target-mips: fix DSP overflow macro and affected routines
The previous implementation incorrectly used same macro to detect overflow
for addition and subtraction. This patch makes distinction between these
two, and creates separate macros. The affected routines are changed
accordingly.

This change also includes additions to the existing tests for SUBQ_S_PH and
SUBQ_S_W that would trigger the fixed issue, and it removes dead code from
the test file. The last test case in subq_s_w.c is a bug found/reported/
isolated by Klaus Peichl from Dolby.

Signed-off-by: Petar Jovanovic <petar.jovanovic@imgtec.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 20c334a797)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 16:32:39 -05:00
Petar Jovanovic
b09a673164 target-mips: fix for sign-issue in MULQ_W helper
Correct sign-propagation before multiplication in MULQ_W helper.
The change also fixes previously incorrect expected values in the
tests for MULQ_RS.W and MULQ_S.W.

Signed-off-by: Petar Jovanovic <petarj@mips.com>
Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit a345481baa)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 16:31:57 -05:00
Petar Jovanovic
79a4dd4085 target-mips: fix for incorrect multiplication with MULQ_S.PH
The change corrects sign-related issue with MULQ_S.PH. It also includes
extension to the already existing test which will trigger the issue.

Signed-off-by: Petar Jovanovic <petarj@mips.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 9c19eb1e20)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 16:31:23 -05:00
Hans de Goede
57e929c19c usb-tablet: Don't claim wakeup capability for USB-2 version
Our ehci code does not implement wakeup support, so claiming support for
it with usb-tablet in USB-2 mode causes all tablet events to get lost.

http://bugzilla.redhat.com/show_bug.cgi?id=929068

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit aa1c9e971e)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 15:33:52 -05:00
Stefan Hajnoczi
27c71355fb chardev: clear O_NONBLOCK on SCM_RIGHTS file descriptors
When we receive a file descriptor over a UNIX domain socket the
O_NONBLOCK flag is preserved.  Clear the O_NONBLOCK flag and rely on
QEMU file descriptor users like migration, SPICE, VNC, block layer, and
others to set non-blocking only when necessary.

This change ensures we don't accidentally expose O_NONBLOCK in the QMP
API.  QMP clients should not need to get the non-blocking state
"correct".

A recent real-world example was when libvirt passed a non-blocking TCP
socket for migration where we expected a blocking socket.  The source
QEMU produced a corrupted migration stream since its code did not cope
with non-blocking sockets.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit e374f7f816171f9783c1d9d00a041f26379f1ac6)

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 15:17:32 -05:00
Stefan Hajnoczi
283b7de6a5 qemu-socket: set passed fd non-blocking in socket_connect()
socket_connect() sets non-blocking on TCP or UNIX domain sockets if a
callback function is passed.  Do the same for file descriptor passing,
otherwise we could unexpectedly be using a blocking file descriptor.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 35fb94fa292173a3e1df0768433e06912a2a88e4)

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 15:17:32 -05:00
Stefan Hajnoczi
a1cb89f3fe net: ensure "socket" backend uses non-blocking fds
There are several code paths in net_init_socket() depending on how the
socket is created: file descriptor passing, UDP multicast, TCP, or UDP.
Some of these support both listen and connect.

Not all code paths set the socket to non-blocking.  This patch addresses
the file descriptor passing and UDP cases which were missing
socket_set_nonblock(fd) calls.

I considered moving socket_set_nonblock(fd) to a central location but it
turns out the code paths are different enough to require non-blocking at
different places.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit f05b707279dc7c29ab10d9d13dbf413df6ec22f1)

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 15:17:32 -05:00
Stefan Hajnoczi
68f9df5990 oslib-posix: rename socket_set_nonblock() to qemu_set_nonblock()
The fcntl(fd, F_SETFL, O_NONBLOCK) flag is not specific to sockets.
Rename to qemu_set_nonblock() just like qemu_set_cloexec().

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 399f1c8f8af1f6f8b18ef4e37169c6301264e467)

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>

Conflicts:
	block/sheepdog.c

socket_set_block()/socket_set_nonblock() calls in different locations

	include/qemu/sockets.h

socket_set_nodelay() does not exist in v1.4.0, messes up diff context

	qemu-char.c

glib G_IO_IN events are not used in v1.4.0, messes up diff context

	savevm.c

qemu_fopen_socket() only has read mode in v1.4.0, qemu_set_block() not
necessary.

	slirp/misc.c

unportable setsockopt() calls in v1.4.0 mess up diff context

	slirp/tcp_subr.c

file was reformatted, diff context is messed up

	ui/vnc.c

old dcl->idle instead of vd->dcl.idle messes up diff context

Added:
	migration-tcp.c, migration-unix.c

qemu_fopen_socket() write mode does not exist yet, qemu_set_block() call
is needed here.
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-04 15:17:32 -05:00
Gerd Hoffmann
0135796271 update seabios to 1.7.2.1
Alex Williamson (3):
      seabios q35: Enable all PIRQn IRQs at startup
      seabios q35: Add new PCI slot to irq routing function
      seabios: Add a dummy PCI slot to irq mapping function

Avik Sil (1):
      USB-EHCI: Fix null pointer assignment

Kevin O'Connor (4):
      Update tools/acpi_extract.py to handle iasl 20130117 release.
      Fix Makefile - don't reference "out/" directly, instead use "$(OUT)".
      build: Don't require $(OUT) to be a sub-directory of the main
directory.
      Verify CC is valid during build tests.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 5c75fb1002)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 16:34:06 -05:00
Peter Maydell
799a34a48b linux-user/syscall.c: Don't warn about unimplemented get_robust_list
The nature of the kernel ABI for the get_robust_list and set_robust_list
syscalls means we cannot implement them in QEMU. Make get_robust_list
silently return ENOSYS rather than using the default "print message and
then fail ENOSYS" code path, in the same way we already do for
set_robust_list, and add a comment documenting why we do this.

This silences warnings which were being produced for emulating
even trivial programs like 'ls' in x86-64-on-x86-64.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
(cherry picked from commit e9a970a831)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 16:28:53 -05:00
Peter Maydell
8378910554 linux-user: make bogus negative iovec lengths fail EINVAL
If the guest passes us a bogus negative length for an iovec, fail
EINVAL rather than proceeding blindly forward. This fixes some of
the error cases tests for readv and writev in the LTP.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
(cherry picked from commit dfae8e00f8)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 16:23:52 -05:00
John Rigby
7a238b9fbd linux-user: fix futex strace of FUTEX_CLOCK_REALTIME
Handle same as existing FUTEX_PRIVATE_FLAG.

Signed-off-by: John Rigby <john.rigby@linaro.org>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
(cherry picked from commit bfb669f39f)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 15:49:19 -05:00
John Rigby
02493ee490 linux-user/syscall.c: handle FUTEX_WAIT_BITSET in do_futex
Upstream libc has recently changed to start using
FUTEX_WAIT_BITSET instead of FUTEX_WAIT and this
is causing do_futex to return -TARGET_ENOSYS.

Pass bitset in val3 to sys_futex which will be
ignored by kernel for the FUTEX_WAIT case.

Signed-off-by: John Rigby <john.rigby@linaro.org>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
(cherry picked from commit cce246e0a2)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 15:48:35 -05:00
Stefan Hajnoczi
7d47b243d6 qcow2: flush refcount cache correctly in qcow2_write_snapshots()
Since qcow2 metadata is cached we need to flush the caches, not just the
underlying file.  Use bdrv_flush(bs) instead of bdrv_flush(bs->file).

Also add the error return path when bdrv_flush() fails and move the
flush after checking for qcow2_alloc_clusters() failure so that the
qcow2_alloc_clusters() error return value takes precedence.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit f6977f1556)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 15:47:09 -05:00
Stefan Hajnoczi
02ea844746 qcow2: flush refcount cache correctly in alloc_refcount_block()
update_refcount() affects the refcount cache, it does not write to disk.
Therefore bdrv_flush(bs->file) does nothing.  We need to flush the
refcount cache in order to write out the refcount updates!

While we're here also add error returns when qcow2_cache_flush() fails.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 9991923b26)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 15:45:40 -05:00
Peter Lieven
0fcf00b55c page_cache: fix memory leak
XBZRLE encoded migration introduced a MRU page cache
meachnism. Unfortunately, cached items where never freed in
case of a collision in the page cache on cache_insert().

This lead to out of memory conditions during XBZRLE migration
if the page cache was small and there where a lot of collisions
in the cache.

Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Juan Quintela <quintela@redhat.com>
(cherry picked from commit 32a1c08b60)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 15:44:43 -05:00
Orit Wasserman
5610ef5863 Fix page_cache leak in cache_resize
Signed-off-by: Orit Wasserman <owasserm@redhat.com>

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Juan Quintela <quintela@redhat.com>
(cherry picked from commit 0db65d624e)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 15:44:02 -05:00
Christian Borntraeger
7a687aed28 virtio-blk: fix unplug + virsh reboot
virtio-blk registers a vmstate change handler. Unfortunately this
handler is not unregistered on unplug, leading to some random
crashes if the system is restarted, e.g. via virsh reboot.
Lets unregister the vmstate change handler if the device is removed.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 69b302b204)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 15:41:50 -05:00
Mark Cave-Ayland
b91aee5810 ide/macio: Fix macio DMA initialisation.
Commit 07a7484e5d accidentally introduced a bug
in the initialisation of the second macio DMA device which could cause some
DMA operations to segfault QEMU.

CC: Andreas Färber <afaerber@suse.de>
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Acked-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 02d583c723)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 15:39:59 -05:00
Andreas Färber
e09b99b54f target-ppc: Fix CPU_POWERPC_MPC8547E
It was defined to ..._MPC8545E_v21 rather than ..._MPC8547E_v21.
Due to both resolving to CPU_POWERPC_e500v2_v21 this did not show.

Fixing this nontheless helps with QOM'ifying CPU aliases.

Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
(cherry picked from commit 0136d715ad)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 11:53:18 -05:00
David Gibson
611c7f2c3a pseries: Add cleanup hook for PAPR virtual LAN device
Currently the spapr-vlan device does not supply a cleanup call for its
NetClientInfo structure.  With current qemu versions, that leads to a SEGV
on exit, when net_cleanup() attempts to call the cleanup handlers on all
net clients.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
(cherry picked from commit 156dfaded8)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 11:51:39 -05:00
Michal Privoznik
4e4566ce78 configure: Require at least spice-protocol-0.12.3
As of 5a49d3e9 we assume SPICE_PORT_EVENT_BREAK to be defined.
However, it is defined not in 0.12.2 what we require now, but in
0.12.3.  Therefore in order to prevent build failure we must
adjust our minimal requirements.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 358689fe29)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 11:48:51 -05:00
Paolo Bonzini
43e00611bc qemu-bridge-helper: force usage of a very high MAC address for the bridge
Linux uses the lowest enslaved MAC address as the MAC address of
the bridge.  Set MAC address to a high value so that it does not
affect the MAC address of the bridge.

Changing the MAC address of the bridge could cause a few seconds
of network downtime.

Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1363971468-21154-1-git-send-email-pbonzini@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 226ecabfbd)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 11:31:58 -05:00
Cornelia Huck
3c3de7c6b4 virtio-ccw: Queue sanity check for notify hypercall.
Verify that the virtio-ccw notify hypercall passed a reasonable
value for queue.

Cc: qemu-stable@nongnu.org
Reported-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
(cherry picked from commit b57ed9bf07)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 11:30:51 -05:00
Yeongkyoon Lee
b0da310a69 tcg: Fix occasional TCG broken problem when ldst optimization enabled
is_tcg_gen_code() checks the upper limit of TCG generated code range wrong, so
that TCG could get broken occasionally only when CONFIG_QEMU_LDST_OPTIMIZATION
enabled. The reason is code_gen_buffer_max_size does not cover the upper range
up to (TCG_MAX_OP_SIZE * OPC_BUF_SIZE), thus code_gen_buffer_max_size should be
modified to code_gen_buffer_size.

CC: qemu-stable@nongnu.org
Signed-off-by: Yeongkyoon Lee <yeongkyoon.lee@samsung.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 52ae646d4a)

Conflicts:

	translate-all.c

*modified to use non-tcg-ctx version of code_gen_* variables

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 11:28:39 -05:00
Peter Crosthwaite
d26efd2d39 qga/main.c: Don't use g_key_file_get/set_int64
These functions don't exist until glib version 2.26. QEMU is currently only
mandating glib 2.12.

This patch replaces the functions with g_key_file_get/set_integer.

Unbreaks the build on Ubuntu 10.04 and RHEL 5.6.

Regression was introduced by 39097daf15

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: 1363323879-682-1-git-send-email-peter.crosthwaite@xilinx.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 4f30649618)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 11:18:47 -05:00
Michael Roth
f305d504ab qemu-ga: use key-value store to avoid recycling fd handles after restart
Hosts hold on to handles provided by guest-file-open for periods that can
span beyond the life of the qemu-ga process that issued them. Since these
are issued starting from 0 on every restart, we run the risk of issuing
duplicate handles after restarts/reboots.

As a result, users with a stale copy of these handles may end up
reading/writing corrupted data due to their existing handles effectively
being re-assigned to an unexpected file or offset.

We unfortunately do not issue handles as strings, but as integers, so a
solution such as using UUIDs can't be implemented without introducing a
new interface.

As a workaround, we fix this by implementing a persistent key-value store
that will be used to track the value of the last handle that was issued
across restarts/reboots to avoid issuing duplicates.

The store is automatically written to the same directory we currently
set via --statedir to track fsfreeze state, and so should be applicable
for stable releases where this flag is supported.

A follow-up can use this same store for handling fsfreeze state, but
that change is cosmetic and left out for now.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Cc: qemu-stable@nongnu.org

* fixed guest_file_handle_add() return value from uint64_t to int64_t
(cherry picked from commit 39097daf15)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 11:16:31 -05:00
Paolo Bonzini
d3652a1b28 qcow2: make is_allocated return true for zero clusters
Otherwise, live migration of the top layer will miss zero clusters and
let the backing file show through.  This also matches what is done in qed.

QCOW2_CLUSTER_ZERO clusters are invalid in v2 image files.  Check this
directly in qcow2_get_cluster_offset instead of replicating the test
everywhere.

Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 381b487d54)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 11:00:19 -05:00
David Gibson
51943504d5 pseries: Add compatible property to root of device tree
Currently, for the pseries machine the device tree supplied by qemu to SLOF
and from there to the guest does not include a 'compatible property' at the
root level.  Usually that works fine, since in this case the compatible
property doesn't really give any information not already found in the
'device_type' or 'model' properties.

However, the lack of 'compatible' confuses the bootloader install in the
SLES11 SP2 and SLES11 SP3 installers.  This patch therefore adds a token
'compatible' property to work around that.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Cc: qemu-stable@nongnu.org
Signed-off-by: Alexander Graf <agraf@suse.de>
(cherry picked from commit d63919c93e)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:59:03 -05:00
Christian Borntraeger
4d1cdb9efd Allow virtio-net features for legacy s390 virtio bus
Enable all virtio-net features for the legacy s390 virtio bus. This also fixes
kernel BUG at /usr/src/packages/BUILD/kernel-default-3.0.58/linux-3.0/drivers/s390/kvm/kvm_virtio.c:121!

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Alexander Graf <agraf@suse.de>
(cherry picked from commit 35569cea79)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:57:53 -05:00
Cole Robinson
c3b81e01b8 rtc-test: Fix test failures with recent glib
As of glib 2.35.4, glib changed its logic for ordering test cases:

https://bugzilla.gnome.org/show_bug.cgi?id=694487

This was causing failures in rtc-test. Group the reordered test
cases into their own suite, which maintains the original ordering.

CC: qemu-stable@nongnu.org
Signed-off-by: Cole Robinson <crobinso@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit eeb29fb9aa)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:56:19 -05:00
Paolo Bonzini
99b1f39bd2 scsi-disk: do not complete canceled UNMAP requests
Canceled requests should never be completed, and doing that could cause
accesses to a NULL hba_private field.

Cc: qemu-stable@nongnu.org
Reported-by: Stefan Priebe <s.priebe@profihost.ag>
Tested-by: Stefan Priebe <s.priebe@profihost.ag>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit d0242eadc5)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:54:35 -05:00
Paolo Bonzini
f23ab037c7 scsi: do not call scsi_read_data/scsi_write_data for a canceled request
Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 6f6710aa99)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:53:33 -05:00
Paolo Bonzini
0c918dd600 iscsi: look for pkg-config file too
Due to library conflicts, Fedora will have to put libiscsi in
/usr/lib/iscsi.  Simplify configuration by using a pkg-config
file.  The Fedora package will distribute one, and the patch
to add it has been sent to upstream libiscsi as well.

Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 3c33ea9640)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:52:33 -05:00
Paolo Bonzini
a8b090ef08 scsi-disk: handle io_canceled uniformly and correctly
Always check it immediately after calling bdrv_acct_done, and
always do a "goto done" in case the "done" label has to free
some memory---as is the case for scsi_unmap_complete in the
previous patch.

This patch could fix problems that happen when a request is
split into multiple parts, and one of them is canceled.  Then
the next part is fired, but the HBA's cancellation callbacks have
fired already.  Whether this happens or not, depends on how the
block/ driver implements AIO cancellation.  It it does a simple
bdrv_drain_all() or similar, then it will not have a problem.
If it only cancels the given AIOCB, this scenario could happen.

Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 0c92e0e6b6)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:50:28 -05:00
Michael Roth
4a38944326 qemu-ga: make guest-sync-delimited available during fsfreeze
We currently maintain a whitelist of commands that are safe during
fsfreeze. During fsfreeze, we disable all commands that aren't part of
that whitelist.

guest-sync-delimited meets the criteria for being whitelisted, and is
also required for qemu-ga clients that rely on guest-sync-delimited for
re-syncing the channel after a timeout.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Cc: qemu-stable@nongnu.org
Reviewed-by: Eric Blake <eblake@redhat.com>
(cherry picked from commit c5dcb6ae23)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:49:47 -05:00
Markus Armbruster
b7ff1a7a00 qmp: netdev_add is like -netdev, not -net, fix documentation
Cc: qemu-stable@nongnu.org
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit af347aa5a5)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:43:46 -05:00
Gerd Hoffmann
d49fed4c55 vga: fix byteswapping.
In case host and guest endianness differ the vga code first creates
a shared surface (using qemu_create_displaysurface_from), then goes
patch the surface format to indicate that the bytes must be swapped.

The switch to pixman broke that hack as the format patching isn't
propagated into the pixman image, so ui code using the pixman image
directly (such as vnc) uses the wrong format.

Fix that by adding a byteswap parameter to
qemu_create_displaysurface_from, so we'll use the correct format
when creating the surface (and the pixman image) and don't have
to patch the format afterwards.

[ v2: unbreak xen build ]

Cc: qemu-stable@nongnu.org
Cc: mark.cave-ayland@ilande.co.uk
Cc: agraf@suse.de
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 1361349432-23884-1-git-send-email-kraxel@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit b1424e0381)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:34:41 -05:00
Jason Wang
cebb8ebe41 help: add docs for multiqueue tap options
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Jason Wang <jasowang@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Message-id: 1361354641-51969-1-git-send-email-jasowang@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 2ca81baa0b)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:32:37 -05:00
Jason Wang
3b39a11cde net: reduce the unnecessary memory allocation of multiqueue
Edivaldo reports a problem that the array of NetClientState in NICState is too
large - MAX_QUEUE_NUM(1024) which will wastes memory even if multiqueue is not
used.

Instead of static arrays, solving this issue by allocating the queues on demand
for both the NetClientState array in NICState and VirtIONetQueue array in
VirtIONet.

Tested by myself, with single virtio-net-pci device. The memory allocation is
almost the same as when multiqueue is not merged.

Cc: Edivaldo de Araujo Pereira <edivaldoapereira@yahoo.com.br>
Cc: qemu-stable@nongnu.org
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit f6b26cf257)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:28:29 -05:00
Igor Mitsyanko
ec9f828341 qemu-char.c: fix waiting for telnet connection message
Current colon position in "waiting for telnet connection" message template
produces messages like:
QEMU waiting for connection on: telnet::127.0.0.16666,server

After moving a colon to the right, we will get a correct messages like:
QEMU waiting for connection on: telnet:127.0.0.1:6666,server

Signed-off-by: Igor Mitsyanko <i.mitsyanko@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit e5545854dd)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:25:05 -05:00
Jason Wang
332e93417a tap: forbid creating multiqueue tap when hub is used
Obviously, hub does not support multiqueue tap. So this patch forbids creating
multiple queue tap when hub is used to prevent the crash when command line such
as "-net tap,queues=2" is used.

Cc: qemu-stable@nongnu.org
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit ce675a7579)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:07:24 -05:00
Peter Lieven
e6b795f34e block: complete all IOs before .bdrv_truncate
bdrv_truncate() invalidates the bdrv_check_request() result for
in-flight requests, so there should better be none.

Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Lieven <pl@kamp.de>
Reported-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 9a665b2b86)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:05:31 -05:00
Paolo Bonzini
51968b8503 coroutine: trim down nesting level in perf_nesting test
20000 nested coroutines require 20 GB of virtual address space.
Only nest 1000 of them so that the test (only enabled with
"-m perf" on the command line) runs on 32-bit machines too.

Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 027003152f)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 10:04:32 -05:00
Andreas Färber
80d8b5da48 target-ppc: Fix "G2leGP3" PVR
Unlike derived PVR constants mapped to CPU_POWERPC_G2LEgp3, the
"G2leGP3" model definition itself used the CPU_POWERPC_G2LEgp1 PVR.

Fixing this will allow to alias CPU_POWERPC_G2LEgp3-using types to
"G2leGP3".

Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
(cherry picked from commit bfe6d5b0da)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2013-04-02 09:52:13 -05:00
1438 changed files with 28281 additions and 73616 deletions

12
.gitignore vendored
View File

@@ -6,9 +6,7 @@ config-target.*
trace/generated-tracers.h
trace/generated-tracers.c
trace/generated-tracers-dtrace.h
trace/generated-tracers.dtrace
trace/generated-events.h
trace/generated-events.c
trace/generated-tracers-dtrace.dtrace
libcacard/trace/generated-tracers.c
*-timestamp
*-softmmu
@@ -82,26 +80,18 @@ fsdev/virtfs-proxy-helper.pod
*.swp
*.orig
.pc
*.patch
*.gcda
*.gcno
patches
pc-bios/bios-pq/status
pc-bios/vgabios-pq/status
pc-bios/optionrom/linuxboot.asm
pc-bios/optionrom/linuxboot.bin
pc-bios/optionrom/linuxboot.raw
pc-bios/optionrom/linuxboot.img
pc-bios/optionrom/multiboot.asm
pc-bios/optionrom/multiboot.bin
pc-bios/optionrom/multiboot.raw
pc-bios/optionrom/multiboot.img
pc-bios/optionrom/kvmvapic.asm
pc-bios/optionrom/kvmvapic.bin
pc-bios/optionrom/kvmvapic.raw
pc-bios/optionrom/kvmvapic.img
pc-bios/s390-ccw/s390-ccw.elf
pc-bios/s390-ccw/s390-ccw.img
.stgit-*
cscope.*
tags

3
.gitmodules vendored
View File

@@ -22,6 +22,3 @@
[submodule "pixman"]
path = pixman
url = git://anongit.freedesktop.org/pixman
[submodule "dtc"]
path = dtc
url = git://git.qemu.org/dtc.git

View File

@@ -78,15 +78,16 @@ avoided.
Use of the malloc/free/realloc/calloc/valloc/memalign/posix_memalign
APIs is not allowed in the QEMU codebase. Instead of these routines,
use the GLib memory allocation routines g_malloc/g_malloc0/g_new/
g_new0/g_realloc/g_free or QEMU's qemu_memalign/qemu_blockalign/qemu_vfree
g_new0/g_realloc/g_free or QEMU's qemu_vmalloc/qemu_memalign/qemu_vfree
APIs.
Please note that g_malloc will exit on allocation failure, so there
is no need to test for failure (as you would have to with malloc).
Calling g_malloc with a zero size is valid and will return NULL.
Memory allocated by qemu_memalign or qemu_blockalign must be freed with
qemu_vfree, since breaking this will cause problems on Win32.
Memory allocated by qemu_vmalloc or qemu_memalign must be freed with
qemu_vfree, since breaking this will cause problems on Win32 and user
emulators.
4. String manipulation

View File

@@ -59,96 +59,75 @@ Alpha
M: Richard Henderson <rth@twiddle.net>
S: Maintained
F: target-alpha/
F: hw/alpha/
ARM
M: Paul Brook <paul@codesourcery.com>
M: Peter Maydell <peter.maydell@linaro.org>
S: Maintained
F: target-arm/
F: hw/arm/
F: hw/cpu/a*mpcore.c
CRIS
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained
F: target-cris/
F: hw/cris/
LM32
M: Michael Walle <michael@walle.cc>
S: Maintained
F: target-lm32/
F: hw/lm32/
M68K
M: Paul Brook <paul@codesourcery.com>
S: Odd Fixes
F: target-m68k/
F: hw/m68k/
MicroBlaze
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained
F: target-microblaze/
F: hw/microblaze/
MIPS
M: Aurelien Jarno <aurelien@aurel32.net>
S: Odd Fixes
F: target-mips/
F: hw/mips/
Moxie
M: Anthony Green <green@moxielogic.com>
S: Maintained
F: target-moxie/
PowerPC
M: Alexander Graf <agraf@suse.de>
L: qemu-ppc@nongnu.org
S: Maintained
F: target-ppc/
F: hw/ppc/
S390
M: Richard Henderson <rth@twiddle.net>
M: Alexander Graf <agraf@suse.de>
S: Maintained
F: target-s390x/
F: hw/s390x/
SH4
M: Aurelien Jarno <aurelien@aurel32.net>
S: Odd Fixes
F: target-sh4/
F: hw/sh4/
SPARC
M: Blue Swirl <blauwirbel@gmail.com>
S: Maintained
F: target-sparc/
F: hw/sparc/
F: hw/sparc64/
UniCore32
M: Guan Xuetao <gxt@mprc.pku.edu.cn>
S: Maintained
F: target-unicore32/
F: hw/unicore32/
X86
M: qemu-devel@nongnu.org
S: Odd Fixes
F: target-i386/
F: hw/i386/
Xtensa
M: Max Filippov <jcmvbkbc@gmail.com>
W: http://wiki.osll.spb.ru/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa
S: Maintained
F: target-xtensa/
F: hw/xtensa/
Guest CPU Cores (KVM):
----------------------
@@ -161,11 +140,6 @@ S: Supported
F: kvm-*
F: */kvm.*
ARM
M: Peter Maydell <peter.maydell@linaro.org>
S: Maintained
F: target-arm/kvm.c
PPC
M: Alexander Graf <agraf@suse.de>
S: Maintained
@@ -221,156 +195,156 @@ M: Maksim Kozlov <m.kozlov@samsung.com>
M: Igor Mitsyanko <i.mitsyanko@samsung.com>
M: Dmitry Solodkiy <d.solodkiy@samsung.com>
S: Maintained
F: hw/*/exynos*
F: hw/exynos*
Calxeda Highbank
M: Mark Langsdorf <mark.langsdorf@calxeda.com>
S: Supported
F: hw/arm/highbank.c
F: hw/net/xgmac.c
F: hw/highbank.c
F: hw/xgmac.c
Gumstix
M: qemu-devel@nongnu.org
S: Orphan
F: hw/arm/gumstix.c
F: hw/gumstix.c
i.MX31
M: Peter Chubb <peter.chubb@nicta.com.au>
S: Odd fixes
F: hw/*/imx*
F: hw/arm/kzm.c
F: hw/imx*
F: hw/kzm.c
Integrator CP
M: Paul Brook <paul@codesourcery.com>
M: Peter Maydell <peter.maydell@linaro.org>
S: Maintained
F: hw/arm/integratorcp.c
F: hw/integratorcp.c
Mainstone
M: qemu-devel@nongnu.org
S: Orphan
F: hw/arm/mainstone.c
F: hw/mainstone.c
Musicpal
M: Jan Kiszka <jan.kiszka@web.de>
S: Maintained
F: hw/arm/musicpal.c
F: hw/musicpal.c
nSeries
M: Andrzej Zaborowski <balrogg@gmail.com>
S: Maintained
F: hw/arm/nseries.c
F: hw/nseries.c
Palm
M: Andrzej Zaborowski <balrogg@gmail.com>
S: Maintained
F: hw/arm/palm.c
F: hw/palm.c
Real View
M: Paul Brook <paul@codesourcery.com>
M: Peter Maydell <peter.maydell@linaro.org>
S: Maintained
F: hw/arm/realview*
F: hw/realview*
Spitz
M: Andrzej Zaborowski <balrogg@gmail.com>
S: Maintained
F: hw/arm/spitz.c
F: hw/spitz.c
Stellaris
M: Paul Brook <paul@codesourcery.com>
M: Peter Maydell <peter.maydell@linaro.org>
S: Maintained
F: hw/*/stellaris*
F: hw/stellaris.c
Versatile PB
M: Paul Brook <paul@codesourcery.com>
M: Peter Maydell <peter.maydell@linaro.org>
S: Maintained
F: hw/*/versatile*
F: hw/versatilepb.c
Xilinx Zynq
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
S: Maintained
F: hw/arm/xilinx_zynq.c
F: hw/misc/zynq_slcr.c
F: hw/*/cadence_*
F: hw/ssi/xilinx_spips.c
F: hw/xilinx_zynq.c
F: hw/zynq_slcr.c
F: hw/cadence_*
F: hw/xilinx_spips.c
CRIS Machines
-------------
Axis Dev88
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained
F: hw/cris/axis_dev88.c
F: hw/axis_dev88.c
etraxfs
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained
F: hw/cris/etraxfs.c
F: hw/etraxfs.c
LM32 Machines
-------------
EVR32 and uclinux BSP
M: Michael Walle <michael@walle.cc>
S: Maintained
F: hw/lm32/lm32_boards.c
F: hw/lm32_boards.c
milkymist
M: Michael Walle <michael@walle.cc>
S: Maintained
F: hw/lm32/milkymist.c
F: hw/milkymist.c
M68K Machines
-------------
an5206
M: Paul Brook <paul@codesourcery.com>
S: Maintained
F: hw/m68k/an5206.c
F: hw/an5206.c
dummy_m68k
M: Paul Brook <paul@codesourcery.com>
S: Maintained
F: hw/m68k/dummy_m68k.c
F: hw/dummy_m68k.c
mcf5208
M: Paul Brook <paul@codesourcery.com>
S: Maintained
F: hw/m68k/mcf5208.c
F: hw/mcf5208.c
MicroBlaze Machines
-------------------
petalogix_s3adsp1800
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained
F: hw/microblaze/petalogix_s3adsp1800.c
F: hw/petalogix_s3adsp1800.c
petalogix_ml605
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
S: Maintained
F: hw/microblaze/petalogix_ml605_mmu.c
F: hw/petalogix_ml605_mmu.c
MIPS Machines
-------------
Jazz
M: Hervé Poussineau <hpoussin@reactos.org>
S: Maintained
F: hw/mips/mips_jazz.c
F: hw/mips_jazz.c
Malta
M: Aurelien Jarno <aurelien@aurel32.net>
S: Maintained
F: hw/mips/mips_malta.c
F: hw/mips_malta.c
Mipssim
M: qemu-devel@nongnu.org
S: Orphan
F: hw/mips/mips_mipssim.c
F: hw/mips_mipssim.c
R4000
M: Aurelien Jarno <aurelien@aurel32.net>
S: Maintained
F: hw/mips/mips_r4k.c
F: hw/mips_r4k.c
PowerPC Machines
----------------
@@ -378,13 +352,13 @@ PowerPC Machines
M: Alexander Graf <agraf@suse.de>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc/ppc405_boards.c
F: hw/ppc405_boards.c
Bamboo
M: Alexander Graf <agraf@suse.de>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc/ppc440_bamboo.c
F: hw/ppc440_bamboo.c
e500
M: Alexander Graf <agraf@suse.de>
@@ -400,97 +374,87 @@ M: Scott Wood <scottwood@freescale.com>
L: qemu-ppc@nongnu.org
S: Supported
F: hw/ppc/mpc8544ds.c
F: hw/ppc/mpc8544_guts.c
F: hw/mpc8544_guts.c
New World
M: Alexander Graf <agraf@suse.de>
L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc/mac_newworld.c
F: hw/pci/devices/host-uninorth.c
F: hw/pci/devices/host-dec.[hc]
F: hw/misc/macio/
F: hw/unin_pci.c
F: hw/dec_pci.[hc]
Old World
M: Alexander Graf <agraf@suse.de>
L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc/mac_oldworld.c
F: hw/pci/devices/host-grackle.c
F: hw/misc/macio/
F: hw/grackle_pci.c
PReP
M: Andreas Färber <andreas.faerber@web.de>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc/prep.c
F: hw/pci/devices/host-prep.[hc]
F: hw/isa/pc87312.[hc]
F: hw/prep_pci.[hc]
F: hw/pc87312.[hc]
sPAPR
M: David Gibson <david@gibson.dropbear.id.au>
M: Alexander Graf <agraf@suse.de>
L: qemu-ppc@nongnu.org
S: Supported
F: hw/*/spapr*
F: hw/spapr*
virtex_ml507
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/pci/virtex_ml507.c
F: hw/virtex_ml507.c
SH4 Machines
------------
R2D
M: Magnus Damm <magnus.damm@gmail.com>
S: Maintained
F: hw/sh/r2d.c
F: hw/r2d.c
Shix
M: Magnus Damm <magnus.damm@gmail.com>
S: Orphan
F: hw/sh/shix.c
F: hw/shix.c
SPARC Machines
--------------
Sun4m
M: Blue Swirl <blauwirbel@gmail.com>
S: Maintained
F: hw/sparc/sun4m.c
F: hw/sun4m.c
Sun4u
M: Blue Swirl <blauwirbel@gmail.com>
S: Maintained
F: hw/sparc64/sun4u.c
F: hw/sun4u.c
Leon3
M: Fabien Chouteau <chouteau@adacore.com>
S: Maintained
F: hw/sparc/leon3.c
F: hw/*/grlib*
F: hw/leon3.c
F: hw/grlib*
S390 Machines
-------------
S390 Virtio
M: Alexander Graf <agraf@suse.de>
S: Maintained
F: hw/s390/s390-*.c
S390 Virtio-ccw
M: Cornelia Huck <cornelia.huck@de.ibm.com>
M: Alexander Graf <agraf@suse.de>
S: Supported
F: hw/s390x/s390-virtio-ccw.c
F: hw/s390x/css.[hc]
T: git git://github.com/cohuck/qemu virtio-ccw-upstr
F: hw/s390-*.c
UniCore32 Machines
-------------
PKUnity-3 SoC initramfs-with-busybox
M: Guan Xuetao <gxt@mprc.pku.edu.cn>
S: Maintained
F: hw/*/puv3*
F: hw/puv3*
F: hw/unicore32/
X86 Machines
@@ -498,91 +462,90 @@ X86 Machines
PC
M: Anthony Liguori <aliguori@us.ibm.com>
S: Supported
F: hw/i386/pc.[ch]
F: hw/i386/pc_piix.c
F: hw/pc.[ch]
F: hw/pc_piix.c
Xtensa Machines
---------------
sim
M: Max Filippov <jcmvbkbc@gmail.com>
S: Maintained
F: hw/xtensa/xtensa_sim.c
F: hw/xtensa_sim.c
Avnet LX60
M: Max Filippov <jcmvbkbc@gmail.com>
S: Maintained
F: hw/xtensa/xtensa_lx60.c
F: hw/xtensa_lx60.c
Devices
-------
IDE
M: Kevin Wolf <kwolf@redhat.com>
S: Odd Fixes
F: include/hw/ide.h
F: hw/ide/
OMAP
M: Peter Maydell <peter.maydell@linaro.org>
S: Maintained
F: hw/*/omap*
F: hw/omap*
PCI
M: Michael S. Tsirkin <mst@redhat.com>
S: Supported
F: include/hw/pci/*
F: hw/pci/*
F: hw/acpi/*
F: hw/pci*
F: hw/piix*
ppc4xx
M: Alexander Graf <agraf@suse.de>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc/ppc4*.c
F: hw/ppc4xx*.[hc]
ppce500
M: Alexander Graf <agraf@suse.de>
M: Scott Wood <scottwood@freescale.com>
L: qemu-ppc@nongnu.org
S: Supported
F: hw/ppc/e500_*
F: hw/ppce500_*
SCSI
M: Paolo Bonzini <pbonzini@redhat.com>
S: Supported
F: include/hw/scsi*
F: hw/scsi/*
F: hw/virtio-scsi.*
F: hw/scsi*
T: git git://github.com/bonzini/qemu.git scsi-next
LSI53C895A
M: Paul Brook <paul@codesourcery.com>
S: Odd Fixes
F: hw/scsi/lsi53c895a.c
F: hw/lsi53c895a.c
SSI
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
S: Maintained
F: hw/ssi/*
F: hw/block/m25p80.c
F: hw/ssi.*
F: hw/m25p80.c
USB
M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained
F: hw/usb/*
F: hw/usb*
VFIO
M: Alex Williamson <alex.williamson@redhat.com>
S: Supported
F: hw/pci/vfio.c
F: hw/vfio*
vhost
M: Michael S. Tsirkin <mst@redhat.com>
S: Supported
F: hw/*/*vhost*
F: hw/vhost*
virtio
M: Anthony Liguori <aliguori@us.ibm.com>
S: Supported
F: hw/*/virtio*
F: hw/virtio*
virtio-9p
M: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
@@ -595,26 +558,25 @@ virtio-blk
M: Kevin Wolf <kwolf@redhat.com>
M: Stefan Hajnoczi <stefanha@redhat.com>
S: Supported
F: hw/block/virtio-blk.c
virtio-ccw
M: Cornelia Huck <cornelia.huck@de.ibm.com>
S: Supported
F: hw/s390x/virtio-ccw.[hc]
T: git git://github.com/cohuck/qemu virtio-ccw-upstr
F: hw/virtio-blk*
virtio-serial
M: Amit Shah <amit.shah@redhat.com>
S: Supported
F: hw/char/virtio-serial-bus.c
F: hw/char/virtio-console.c
F: hw/virtio-serial*
F: hw/virtio-console*
Xilinx EDK
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained
F: hw/*/xilinx_*
F: include/hw/xilinx.h
F: hw/xilinx_axi*
F: hw/xilinx_uartlite.c
F: hw/xilinx_intc.c
F: hw/xilinx_ethlite.c
F: hw/xilinx_timer.c
F: hw/xilinx.h
F: hw/xilinx_spi.c
Subsystems
----------
@@ -622,7 +584,6 @@ Audio
M: Vassili Karpov (malc) <av1474@comtv.ru>
S: Maintained
F: audio/
F: hw/audio/
Block
M: Kevin Wolf <kwolf@redhat.com>
@@ -630,7 +591,6 @@ M: Stefan Hajnoczi <stefanha@redhat.com>
S: Supported
F: block*
F: block/
F: hw/block/
Character Devices
M: Anthony Liguori <aliguori@us.ibm.com>
@@ -644,12 +604,6 @@ F: qom/cpu.c
F: include/qemu/cpu.h
F: target-i386/cpu.c
ICC Bus
M: Igor Mammedov <imammedo@redhat.com>
S: Supported
F: include/hw/cpu/icc_bus.h
F: hw/cpu/icc_bus.c
Device Tree
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
M: Alexander Graf <agraf@suse.de>
@@ -668,7 +622,7 @@ S: Supported
F: ui/qemu-spice.h
F: ui/spice-*.c
F: audio/spiceaudio.c
F: hw/display/qxl*
F: hw/qxl*
Graphics
M: Anthony Liguori <aliguori@us.ibm.com>

View File

@@ -19,12 +19,6 @@ seems to have been used for an in-tree build. You can fix this by running \
endif
endif
CONFIG_SOFTMMU := $(if $(filter %-softmmu,$(TARGET_DIRS)),y)
CONFIG_USER_ONLY := $(if $(filter %-user,$(TARGET_DIRS)),y)
CONFIG_ALL=y
-include config-all-devices.mak
-include config-all-disas.mak
include $(SRC_PATH)/rules.mak
config-host.mak: $(SRC_PATH)/configure
@echo $@ is out-of-date, running configure
@@ -41,9 +35,6 @@ GENERATED_HEADERS = config-host.h qemu-options.def
GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h
GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c
GENERATED_HEADERS += trace/generated-events.h
GENERATED_SOURCES += trace/generated-events.c
GENERATED_HEADERS += trace/generated-tracers.h
ifeq ($(TRACE_BACKEND),dtrace)
GENERATED_HEADERS += trace/generated-tracers-dtrace.h
@@ -75,17 +66,14 @@ endif
SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) BUILD_DIR=$(BUILD_DIR)
SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %-config-devices.mak.d, $(TARGET_DIRS))
SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS))
ifeq ($(SUBDIR_DEVICES_MAK),)
config-all-devices.mak:
$(call quiet-command,echo '# no devices' > $@," GEN $@")
else
config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
$(call quiet-command, sed -n \
's|^\([^=]*\)=\(.*\)$$|\1:=$$(findstring y,$$(\1)\2)|p' \
$(SUBDIR_DEVICES_MAK) | sort -u > $@, \
" GEN $@")
$(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@," GEN $@")
endif
-include $(SUBDIR_DEVICES_MAK_DEP)
@@ -113,6 +101,12 @@ endif
defconfig:
rm -f config-all-devices.mak $(SUBDIR_DEVICES_MAK)
-include config-all-devices.mak
-include config-all-disas.mak
CONFIG_SOFTMMU := $(if $(filter %-softmmu,$(TARGET_DIRS)),y)
CONFIG_USER_ONLY := $(if $(filter %-user,$(TARGET_DIRS)),y)
CONFIG_ALL=y
ifneq ($(wildcard config-host.mak),)
include $(SRC_PATH)/Makefile.objs
include $(SRC_PATH)/tests/Makefile
@@ -129,9 +123,6 @@ qemu-options.def: $(SRC_PATH)/qemu-options.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@")
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
$(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
subdir-%:
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
@@ -145,15 +136,6 @@ pixman/Makefile: $(SRC_PATH)/pixman/configure
$(SRC_PATH)/pixman/configure:
(cd $(SRC_PATH)/pixman; autoreconf -v --install)
DTC_MAKE_ARGS=-I$(SRC_PATH)/dtc VPATH=$(SRC_PATH)/dtc -C dtc V="$(V)" LIBFDT_srcdir=$(SRC_PATH)/dtc/libfdt
DTC_CFLAGS=$(CFLAGS) $(QEMU_CFLAGS) -I$(BUILD_DIR)/dtc -I$(SRC_PATH)/dtc -I$(SRC_PATH)/dtc/libfdt
subdir-dtc:dtc/libfdt dtc/tests
$(call quiet-command,$(MAKE) $(DTC_MAKE_ARGS) CFLAGS="$(DTC_CFLAGS)" LDFLAGS="$(LDFLAGS)" ARFLAGS="$(ARFLAGS)" CC="$(CC)" AR="$(AR)" LD="$(LD)" $(SUBDIR_MAKEFLAGS) libfdt/libfdt.a,)
dtc/%:
mkdir -p $@
$(SUBDIR_RULES): libqemuutil.a libqemustub.a $(common-obj-y)
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
@@ -166,13 +148,11 @@ recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
version.o: $(SRC_PATH)/version.rc config-host.h | version.lo
version.lo: $(SRC_PATH)/version.rc config-host.h
version.o: $(SRC_PATH)/version.rc config-host.h
$(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@")
version-obj-$(CONFIG_WIN32) += version.o
version-lobj-$(CONFIG_WIN32) += version.lo
Makefile: $(version-obj-y) $(version-lobj-y)
Makefile: $(version-obj-y)
######################################################################
# Build libraries
@@ -273,7 +253,6 @@ distclean: clean
rm -rf $$d || exit 1 ; \
done
if test -f pixman/config.log; then make -C pixman distclean; fi
if test -f dtc/version_gen.h; then make $(DTC_MAKE_ARGS) clean; fi
KEYMAPS=da en-gb et fr fr-ch is lt modifiers no pt-br sv \
ar de en-us fi fr-be hr it lv nl pl ru th \
@@ -287,13 +266,10 @@ acpi-dsdt.aml q35-acpi-dsdt.aml \
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
efi-pcnet.rom efi-rtl8139.rom efi-virtio.rom \
qemu-icon.bmp \
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
multiboot.bin linuxboot.bin kvmvapic.bin \
s390-zipl.rom \
s390-ccw.img \
spapr-rtas.bin slof.bin \
palcode-clipper
else
@@ -306,13 +282,10 @@ install-doc: $(DOCS)
$(INSTALL_DATA) QMP/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
ifdef CONFIG_POSIX
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1"
ifneq ($(TOOLS),)
$(INSTALL_DATA) qemu-img.1 "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
endif
endif
ifdef CONFIG_VIRTFS
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
@@ -340,9 +313,6 @@ ifneq ($(BLOBS),)
set -e; for x in $(BLOBS); do \
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
done
endif
ifeq ($(CONFIG_GTK),y)
$(MAKE) -C po $@
endif
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
set -e; for x in $(KEYMAPS); do \
@@ -358,8 +328,7 @@ test speed: all
.PHONY: TAGS
TAGS:
rm -f $@
find "$(SRC_PATH)" -name '*.[hc]' -exec etags --append {} +
find "$(SRC_PATH)" -name '*.[hc]' -print0 | xargs -0 etags
cscope:
rm -f ./cscope.*

View File

@@ -16,7 +16,16 @@ block-obj-y += qapi-types.o qapi-visit.o
block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
block-obj-y += qemu-coroutine-sleep.o
block-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o
ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
block-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
else
ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y)
block-obj-$(CONFIG_POSIX) += coroutine-sigaltstack.o
else
block-obj-$(CONFIG_POSIX) += coroutine-gthread.o
endif
endif
block-obj-$(CONFIG_WIN32) += coroutine-win32.o
ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
@@ -32,7 +41,6 @@ libcacard-y += libcacard/vcard.o libcacard/vreader.o
libcacard-y += libcacard/vcard_emul_nss.o
libcacard-y += libcacard/vcard_emul_type.o
libcacard-y += libcacard/card_7816.o
libcacard-y += libcacard/vcardt.o
######################################################################
# Target independent part of system emulation. The long term path is to
@@ -43,7 +51,6 @@ ifeq ($(CONFIG_SOFTMMU),y)
common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/
common-obj-y += net/
common-obj-y += readline.o
common-obj-y += qdev-monitor.o device-hotplug.o
common-obj-$(CONFIG_WIN32) += os-win32.o
common-obj-$(CONFIG_POSIX) += os-posix.o
@@ -65,8 +72,8 @@ common-obj-y += ui/
common-obj-y += bt-host.o bt-vhci.o
common-obj-y += dma-helpers.o
common-obj-y += qtest.o
common-obj-y += vl.o
common-obj-y += tpm.o
common-obj-$(CONFIG_SLIRP) += slirp/
@@ -79,15 +86,10 @@ common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y)
######################################################################
# qapi
common-obj-y += qmp-marshal.o
common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o
common-obj-y += qmp.o hmp.o
endif
######################################################################
# some qapi visitors are used by both system and user emulation:
common-obj-y += qapi-visit.o qapi-types.o
#######################################################################
# Target-independent parts used in system and user emulation
common-obj-y += qemu-log.o

View File

@@ -1,8 +1,8 @@
# -*- Mode: makefile -*-
include ../config-host.mak
include config-target.mak
include config-devices.mak
include config-target.mak
include $(SRC_PATH)/rules.mak
$(call set-vpath, $(SRC_PATH))
@@ -18,7 +18,7 @@ ifdef CONFIG_USER_ONLY
QEMU_PROG=qemu-$(TARGET_ARCH2)
else
# system emulator name
ifneq (,$(findstring -mwindows,$(libs_softmmu)))
ifneq (,$(findstring -mwindows,$(LIBS)))
# Terminate program name with a 'w' because the linker builds a windows executable.
QEMU_PROGW=qemu-system-$(TARGET_ARCH2)w$(EXESUF)
endif # windows executable
@@ -31,6 +31,10 @@ PROGS+=$(QEMU_PROGW)
endif
STPFILES=
ifndef CONFIG_HAIKU
LIBS+=-lm
endif
config-target.h: config-target.h-timestamp
config-target.h-timestamp: config-target.mak
@@ -60,12 +64,6 @@ all: $(PROGS) stap
# Dummy command so that make thinks it has done something
@true
CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y)
CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
CONFIG_NO_GET_MEMORY_MAPPING = $(if $(subst n,,$(CONFIG_HAVE_GET_MEMORY_MAPPING)),n,y)
CONFIG_NO_CORE_DUMP = $(if $(subst n,,$(CONFIG_HAVE_CORE_DUMP)),n,y)
#########################################################
# cpu emulator library
obj-y = exec.o translate-all.o cpu-exec.o
@@ -76,7 +74,6 @@ obj-y += fpu/softfloat.o
obj-y += target-$(TARGET_BASE_ARCH)/
obj-y += disas.o
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
#########################################################
# Linux user emulator target
@@ -105,17 +102,22 @@ endif #CONFIG_BSD_USER
#########################################################
# System emulator target
ifdef CONFIG_SOFTMMU
CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y)
CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
CONFIG_NO_GET_MEMORY_MAPPING = $(if $(subst n,,$(CONFIG_HAVE_GET_MEMORY_MAPPING)),n,y)
CONFIG_NO_CORE_DUMP = $(if $(subst n,,$(CONFIG_HAVE_CORE_DUMP)),n,y)
obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o
obj-y += qtest.o
obj-y += hw/
obj-$(CONFIG_FDT) += device_tree.o
obj-$(CONFIG_KVM) += kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
obj-y += memory.o savevm.o cputlb.o
obj-$(CONFIG_HAVE_GET_MEMORY_MAPPING) += memory_mapping.o
obj-$(CONFIG_HAVE_CORE_DUMP) += dump.o
obj-$(CONFIG_NO_GET_MEMORY_MAPPING) += memory_mapping-stub.o
obj-$(CONFIG_NO_CORE_DUMP) += dump-stub.o
LIBS+=$(libs_softmmu)
LIBS+=-lz
# xen support
obj-$(CONFIG_XEN) += xen-all.o xen-mapcache.o
@@ -145,10 +147,6 @@ include $(SRC_PATH)/Makefile.objs
all-obj-y = $(obj-y)
all-obj-y += $(addprefix ../, $(common-obj-y))
ifndef CONFIG_HAIKU
LIBS+=-lm
endif
ifdef QEMU_PROGW
# The linker builds a windows executable. Make also a console executable.
$(QEMU_PROGW): $(all-obj-y) ../libqemuutil.a ../libqemustub.a

View File

@@ -136,24 +136,6 @@ Example:
Note: The "ready to complete" status is always reset by a BLOCK_JOB_ERROR
event.
DEVICE_DELETED
-----------------
Emitted whenever the device removal completion is acknowledged
by the guest.
At this point, it's safe to reuse the specified device ID.
Device removal can be initiated by the guest or by HMP/QMP commands.
Data:
- "device": device name (json-string, optional)
- "path": device path (json-string)
{ "event": "DEVICE_DELETED",
"data": { "device": "virtio-net-pci-0",
"path": "/machine/peripheral/virtio-net-pci-0" },
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
DEVICE_TRAY_MOVED
-----------------
@@ -446,17 +428,3 @@ Example:
Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
followed respectively by the RESET, SHUTDOWN, or STOP events.
GUEST_PANICKED
--------------
Emitted when guest OS panic is detected.
Data:
- "action": Action that has been taken (json-string, currently always "pause").
Example:
{ "event": "GUEST_PANICKED",
"data": { "action": "pause" } }

View File

@@ -99,15 +99,8 @@ class QMPShell(qmp.QEMUMonitorProtocol):
for arg in cmdargs[1:]:
opt = arg.split('=')
try:
if(len(opt) > 2):
opt[1] = '='.join(opt[1:])
value = int(opt[1])
except ValueError:
if opt[1] == 'true':
value = True
elif opt[1] == 'false':
value = False
else:
value = opt[1]
qmpcmd['arguments'][opt[0]] = value
return qmpcmd

37
TODO Normal file
View File

@@ -0,0 +1,37 @@
General:
-------
- cycle counter for all archs
- cpu_interrupt() win32/SMP fix
- merge PIC spurious interrupt patch
- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
- config file (at least for windows/Mac OS X)
- update doc: PCI infos.
- basic VGA optimizations
- better code fetch
- do not resize vga if invalid size.
- TLB code protection support for PPC
- disable SMC handling for ARM/SPARC/PPC (not finished)
- see undefined flags for BTx insn
- keyboard output buffer filling timing emulation
- tests for each target CPU
- fix all remaining thread lock issues (must put TBs in a specific invalid
state, find a solution for tb_flush()).
ppc specific:
------------
- TLB invalidate not needed if msr_pr changes
- enable shift optimizations ?
linux-user specific:
-------------------
- remove threading support as it cannot work at this point
- improve IPC syscalls
- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
issues, fix 16 bit uid issues)
- use kernel traps for unaligned accesses on ARM ?
lower priority:
--------------
- int15 ah=86: use better timing
- use -msoft-float on ARM

View File

@@ -1 +1 @@
1.5.1
1.4.1

View File

@@ -25,7 +25,6 @@ struct AioHandler
IOHandler *io_write;
AioFlushHandler *io_flush;
int deleted;
int pollfds_idx;
void *opaque;
QLIST_ENTRY(AioHandler) node;
};
@@ -86,10 +85,9 @@ void aio_set_fd_handler(AioContext *ctx,
node->io_write = io_write;
node->io_flush = io_flush;
node->opaque = opaque;
node->pollfds_idx = -1;
node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0);
node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP : 0);
node->pfd.events |= (io_write ? G_IO_OUT : 0);
}
aio_notify(ctx);
@@ -112,6 +110,13 @@ bool aio_pending(AioContext *ctx)
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
int revents;
/*
* FIXME: right now we cannot get G_IO_HUP and G_IO_ERR because
* main-loop.c is still select based (due to the slirp legacy).
* If main-loop.c ever switches to poll, G_IO_ERR should be
* tested too. Dispatching G_IO_ERR to both handlers should be
* okay, since handlers need to be ready for spurious wakeups.
*/
revents = node->pfd.revents & node->pfd.events;
if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
return true;
@@ -124,12 +129,30 @@ bool aio_pending(AioContext *ctx)
return false;
}
static bool aio_dispatch(AioContext *ctx)
bool aio_poll(AioContext *ctx, bool blocking)
{
static struct timeval tv0;
AioHandler *node;
bool progress = false;
fd_set rdfds, wrfds;
int max_fd = -1;
int ret;
bool busy, progress;
progress = false;
/*
* If there are callbacks left that have been queued, we need to call then.
* Do not call select in this case, because it is possible that the caller
* does not need a complete flush (as is the case for qemu_aio_wait loops).
*/
if (aio_bh_poll(ctx)) {
blocking = false;
progress = true;
}
/*
* Then dispatch any pending callbacks from the GSource.
*
* We have to walk very carefully in case qemu_aio_set_fd_handler is
* called while we're walking.
*/
@@ -143,14 +166,87 @@ static bool aio_dispatch(AioContext *ctx)
revents = node->pfd.revents & node->pfd.events;
node->pfd.revents = 0;
/* See comment in aio_pending. */
if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
node->io_read(node->opaque);
progress = true;
}
if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) {
node->io_write(node->opaque);
progress = true;
}
tmp = node;
node = QLIST_NEXT(node, node);
ctx->walking_handlers--;
if (!ctx->walking_handlers && tmp->deleted) {
QLIST_REMOVE(tmp, node);
g_free(tmp);
}
}
if (progress && !blocking) {
return true;
}
ctx->walking_handlers++;
FD_ZERO(&rdfds);
FD_ZERO(&wrfds);
/* fill fd sets */
busy = false;
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
/* If there aren't pending AIO operations, don't invoke callbacks.
* Otherwise, if there are no AIO requests, qemu_aio_wait() would
* wait indefinitely.
*/
if (!node->deleted && node->io_flush) {
if (node->io_flush(node->opaque) == 0) {
continue;
}
busy = true;
}
if (!node->deleted && node->io_read) {
FD_SET(node->pfd.fd, &rdfds);
max_fd = MAX(max_fd, node->pfd.fd + 1);
}
if (!node->deleted && node->io_write) {
FD_SET(node->pfd.fd, &wrfds);
max_fd = MAX(max_fd, node->pfd.fd + 1);
}
}
ctx->walking_handlers--;
/* No AIO operations? Get us out of here */
if (!busy) {
return progress;
}
/* wait until next event */
ret = select(max_fd, &rdfds, &wrfds, NULL, blocking ? NULL : &tv0);
/* if we have any readable fds, dispatch event */
if (ret > 0) {
/* we have to walk very carefully in case
* qemu_aio_set_fd_handler is called while we're walking */
node = QLIST_FIRST(&ctx->aio_handlers);
while (node) {
AioHandler *tmp;
ctx->walking_handlers++;
if (!node->deleted &&
(revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) &&
FD_ISSET(node->pfd.fd, &rdfds) &&
node->io_read) {
node->io_read(node->opaque);
progress = true;
}
if (!node->deleted &&
(revents & (G_IO_OUT | G_IO_ERR)) &&
FD_ISSET(node->pfd.fd, &wrfds) &&
node->io_write) {
node->io_write(node->opaque);
progress = true;
@@ -166,88 +262,6 @@ static bool aio_dispatch(AioContext *ctx)
g_free(tmp);
}
}
return progress;
}
bool aio_poll(AioContext *ctx, bool blocking)
{
AioHandler *node;
int ret;
bool busy, progress;
progress = false;
/*
* If there are callbacks left that have been queued, we need to call them.
* Do not call select in this case, because it is possible that the caller
* does not need a complete flush (as is the case for qemu_aio_wait loops).
*/
if (aio_bh_poll(ctx)) {
blocking = false;
progress = true;
}
if (aio_dispatch(ctx)) {
progress = true;
}
if (progress && !blocking) {
return true;
}
ctx->walking_handlers++;
g_array_set_size(ctx->pollfds, 0);
/* fill pollfds */
busy = false;
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
node->pollfds_idx = -1;
/* If there aren't pending AIO operations, don't invoke callbacks.
* Otherwise, if there are no AIO requests, qemu_aio_wait() would
* wait indefinitely.
*/
if (!node->deleted && node->io_flush) {
if (node->io_flush(node->opaque) == 0) {
continue;
}
busy = true;
}
if (!node->deleted && node->pfd.events) {
GPollFD pfd = {
.fd = node->pfd.fd,
.events = node->pfd.events,
};
node->pollfds_idx = ctx->pollfds->len;
g_array_append_val(ctx->pollfds, pfd);
}
}
ctx->walking_handlers--;
/* No AIO operations? Get us out of here */
if (!busy) {
return progress;
}
/* wait until next event */
ret = g_poll((GPollFD *)ctx->pollfds->data,
ctx->pollfds->len,
blocking ? -1 : 0);
/* if we have any readable fds, dispatch event */
if (ret > 0) {
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
if (node->pollfds_idx != -1) {
GPollFD *pfd = &g_array_index(ctx->pollfds, GPollFD,
node->pollfds_idx);
node->pfd.revents = pfd->revents;
}
}
if (aio_dispatch(ctx)) {
progress = true;
}
}
assert(progress || busy);

View File

@@ -35,20 +35,20 @@
#include "qemu/bitmap.h"
#include "sysemu/arch_init.h"
#include "audio/audio.h"
#include "hw/i386/pc.h"
#include "hw/pc.h"
#include "hw/pci/pci.h"
#include "hw/audio/audio.h"
#include "hw/audiodev.h"
#include "sysemu/kvm.h"
#include "migration/migration.h"
#include "hw/i386/smbios.h"
#include "exec/gdbstub.h"
#include "hw/smbios.h"
#include "exec/address-spaces.h"
#include "hw/audio/pcspk.h"
#include "hw/pcspk.h"
#include "migration/page_cache.h"
#include "qemu/config-file.h"
#include "qmp-commands.h"
#include "trace.h"
#include "exec/cpu-all.h"
#include "hw/acpi/acpi.h"
#ifdef DEBUG_ARCH_INIT
#define DPRINTF(fmt, ...) \
@@ -85,8 +85,6 @@ int graphic_depth = 15;
#define QEMU_ARCH QEMU_ARCH_MICROBLAZE
#elif defined(TARGET_MIPS)
#define QEMU_ARCH QEMU_ARCH_MIPS
#elif defined(TARGET_MOXIE)
#define QEMU_ARCH QEMU_ARCH_MOXIE
#elif defined(TARGET_OPENRISC)
#define QEMU_ARCH QEMU_ARCH_OPENRISC
#elif defined(TARGET_PPC)
@@ -116,6 +114,26 @@ const uint32_t arch_type = QEMU_ARCH;
#define RAM_SAVE_FLAG_CONTINUE 0x20
#define RAM_SAVE_FLAG_XBZRLE 0x40
#ifdef __ALTIVEC__
#include <altivec.h>
#define VECTYPE vector unsigned char
#define SPLAT(p) vec_splat(vec_ld(0, p), 0)
#define ALL_EQ(v1, v2) vec_all_eq(v1, v2)
/* altivec.h may redefine the bool macro as vector type.
* Reset it to POSIX semantics. */
#undef bool
#define bool _Bool
#elif defined __SSE2__
#include <emmintrin.h>
#define VECTYPE __m128i
#define SPLAT(p) _mm_set1_epi8(*(p))
#define ALL_EQ(v1, v2) (_mm_movemask_epi8(_mm_cmpeq_epi8(v1, v2)) == 0xFFFF)
#else
#define VECTYPE unsigned long
#define SPLAT(p) (*(p) * (~0UL / 255))
#define ALL_EQ(v1, v2) ((v1) == (v2))
#endif
static struct defconfig_file {
const char *filename;
@@ -146,10 +164,19 @@ int qemu_read_default_config_files(bool userconfig)
return 0;
}
static inline bool is_zero_page(uint8_t *p)
static int is_dup_page(uint8_t *page)
{
return buffer_find_nonzero_offset(p, TARGET_PAGE_SIZE) ==
TARGET_PAGE_SIZE;
VECTYPE *p = (VECTYPE *)page;
VECTYPE val = SPLAT(page);
int i;
for (i = 0; i < TARGET_PAGE_SIZE / sizeof(VECTYPE); i++) {
if (!ALL_EQ(val, p[i])) {
return 0;
}
}
return 1;
}
/* struct contains XBZRLE cache and a static page
@@ -183,7 +210,6 @@ int64_t xbzrle_cache_resize(int64_t new_size)
/* accounting for migration statistics */
typedef struct AccountingInfo {
uint64_t dup_pages;
uint64_t skipped_pages;
uint64_t norm_pages;
uint64_t iterations;
uint64_t xbzrle_bytes;
@@ -209,16 +235,6 @@ uint64_t dup_mig_pages_transferred(void)
return acct_info.dup_pages;
}
uint64_t skipped_mig_bytes_transferred(void)
{
return acct_info.skipped_pages * TARGET_PAGE_SIZE;
}
uint64_t skipped_mig_pages_transferred(void)
{
return acct_info.skipped_pages;
}
uint64_t norm_mig_bytes_transferred(void)
{
return acct_info.norm_pages * TARGET_PAGE_SIZE;
@@ -277,7 +293,8 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
if (!last_stage) {
cache_insert(XBZRLE.cache, current_addr, current_data);
cache_insert(XBZRLE.cache, current_addr,
g_memdup(current_data, TARGET_PAGE_SIZE));
}
acct_info.xbzrle_cache_miss++;
return -1;
@@ -330,7 +347,6 @@ static ram_addr_t last_offset;
static unsigned long *migration_bitmap;
static uint64_t migration_dirty_pages;
static uint32_t last_version;
static bool ram_bulk_stage;
static inline
ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr,
@@ -340,13 +356,7 @@ ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr,
unsigned long nr = base + (start >> TARGET_PAGE_BITS);
unsigned long size = base + (int128_get64(mr->size) >> TARGET_PAGE_BITS);
unsigned long next;
if (ram_bulk_stage && nr > base) {
next = nr + 1;
} else {
next = find_next_bit(migration_bitmap, size, nr);
}
unsigned long next = find_next_bit(migration_bitmap, size, nr);
if (next < size) {
clear_bit(next, migration_bitmap);
@@ -369,8 +379,6 @@ static inline bool migration_bitmap_set_dirty(MemoryRegion *mr,
return ret;
}
/* Needs iothread lock! */
static void migration_bitmap_sync(void)
{
RAMBlock *block;
@@ -406,7 +414,6 @@ static void migration_bitmap_sync(void)
if (end_time > start_time + 1000) {
s->dirty_pages_rate = num_dirty_pages_period * 1000
/ (end_time - start_time);
s->dirty_bytes_rate = s->dirty_pages_rate * TARGET_PAGE_SIZE;
start_time = end_time;
num_dirty_pages_period = 0;
}
@@ -444,7 +451,6 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
if (!block) {
block = QTAILQ_FIRST(&ram_list.blocks);
complete_round = true;
ram_bulk_stage = false;
}
} else {
uint8_t *p;
@@ -455,18 +461,13 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
/* In doubt sent page as normal */
bytes_sent = -1;
if (is_zero_page(p)) {
if (is_dup_page(p)) {
acct_info.dup_pages++;
if (!ram_bulk_stage) {
bytes_sent = save_block_hdr(f, block, offset, cont,
RAM_SAVE_FLAG_COMPRESS);
qemu_put_byte(f, 0);
bytes_sent++;
} else {
acct_info.skipped_pages++;
bytes_sent = 0;
}
} else if (!ram_bulk_stage && migrate_use_xbzrle()) {
qemu_put_byte(f, *p);
bytes_sent += 1;
} else if (migrate_use_xbzrle()) {
current_addr = block->offset + offset;
bytes_sent = save_xbzrle_page(f, p, current_addr, block,
offset, cont, last_stage);
@@ -478,7 +479,7 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
/* XBZRLE overflow or normal page */
if (bytes_sent == -1) {
bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE);
qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
bytes_sent += TARGET_PAGE_SIZE;
acct_info.norm_pages++;
}
@@ -553,7 +554,6 @@ static void reset_ram_globals(void)
last_sent_block = NULL;
last_offset = 0;
last_version = ram_list.version;
ram_bulk_stage = true;
}
#define MAX_WAIT 50 /* ms, half buffered_file limit */
@@ -567,6 +567,10 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
bitmap_set(migration_bitmap, 0, ram_pages);
migration_dirty_pages = ram_pages;
qemu_mutex_lock_ramlist();
bytes_transferred = 0;
reset_ram_globals();
if (migrate_use_xbzrle()) {
XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
TARGET_PAGE_SIZE,
@@ -580,14 +584,8 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
acct_clear();
}
qemu_mutex_lock_iothread();
qemu_mutex_lock_ramlist();
bytes_transferred = 0;
reset_ram_globals();
memory_global_dirty_log_start();
migration_bitmap_sync();
qemu_mutex_unlock_iothread();
qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);
@@ -691,9 +689,7 @@ static uint64_t ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE;
if (remaining_size < max_size) {
qemu_mutex_lock_iothread();
migration_bitmap_sync();
qemu_mutex_unlock_iothread();
remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE;
}
return remaining_size;
@@ -887,6 +883,7 @@ SaveVMHandlers savevm_ram_handlers = {
.cancel = ram_migration_cancel,
};
#ifdef HAS_AUDIO
struct soundhw {
const char *name;
const char *descr;
@@ -898,30 +895,96 @@ struct soundhw {
} init;
};
static struct soundhw soundhw[9];
static int soundhw_count;
static struct soundhw soundhw[] = {
#ifdef HAS_AUDIO_CHOICE
#ifdef CONFIG_PCSPK
{
"pcspk",
"PC speaker",
0,
1,
{ .init_isa = pcspk_audio_init }
},
#endif
void isa_register_soundhw(const char *name, const char *descr,
int (*init_isa)(ISABus *bus))
{
assert(soundhw_count < ARRAY_SIZE(soundhw) - 1);
soundhw[soundhw_count].name = name;
soundhw[soundhw_count].descr = descr;
soundhw[soundhw_count].isa = 1;
soundhw[soundhw_count].init.init_isa = init_isa;
soundhw_count++;
}
#ifdef CONFIG_SB16
{
"sb16",
"Creative Sound Blaster 16",
0,
1,
{ .init_isa = SB16_init }
},
#endif
void pci_register_soundhw(const char *name, const char *descr,
int (*init_pci)(PCIBus *bus))
{
assert(soundhw_count < ARRAY_SIZE(soundhw) - 1);
soundhw[soundhw_count].name = name;
soundhw[soundhw_count].descr = descr;
soundhw[soundhw_count].isa = 0;
soundhw[soundhw_count].init.init_pci = init_pci;
soundhw_count++;
}
#ifdef CONFIG_CS4231A
{
"cs4231a",
"CS4231A",
0,
1,
{ .init_isa = cs4231a_init }
},
#endif
#ifdef CONFIG_ADLIB
{
"adlib",
#ifdef HAS_YMF262
"Yamaha YMF262 (OPL3)",
#else
"Yamaha YM3812 (OPL2)",
#endif
0,
1,
{ .init_isa = Adlib_init }
},
#endif
#ifdef CONFIG_GUS
{
"gus",
"Gravis Ultrasound GF1",
0,
1,
{ .init_isa = GUS_init }
},
#endif
#ifdef CONFIG_AC97
{
"ac97",
"Intel 82801AA AC97 Audio",
0,
0,
{ .init_pci = ac97_init }
},
#endif
#ifdef CONFIG_ES1370
{
"es1370",
"ENSONIQ AudioPCI ES1370",
0,
0,
{ .init_pci = es1370_init }
},
#endif
#ifdef CONFIG_HDA
{
"hda",
"Intel HD Audio",
0,
0,
{ .init_pci = intel_hda_and_codec_init }
},
#endif
#endif /* HAS_AUDIO_CHOICE */
{ NULL, NULL, 0, 0, { NULL } }
};
void select_soundhw(const char *optarg)
{
@@ -930,16 +993,16 @@ void select_soundhw(const char *optarg)
if (is_help_option(optarg)) {
show_valid_cards:
if (soundhw_count) {
#ifdef HAS_AUDIO_CHOICE
printf("Valid sound card names (comma separated):\n");
for (c = soundhw; c->name; ++c) {
printf ("%-11s %s\n", c->name, c->descr);
}
printf("\n-soundhw all will enable all of the above\n");
} else {
#else
printf("Machine has no user-selectable audio hardware "
"(it may or may not have always-present audio hardware).\n");
}
#endif
exit(!is_help_option(optarg));
}
else {
@@ -987,30 +1050,32 @@ void select_soundhw(const char *optarg)
}
}
void audio_init(void)
void audio_init(ISABus *isa_bus, PCIBus *pci_bus)
{
struct soundhw *c;
ISABus *isa_bus = (ISABus *) object_resolve_path_type("", TYPE_ISA_BUS, NULL);
PCIBus *pci_bus = (PCIBus *) object_resolve_path_type("", TYPE_PCI_BUS, NULL);
for (c = soundhw; c->name; ++c) {
if (c->enabled) {
if (c->isa) {
if (!isa_bus) {
fprintf(stderr, "ISA bus not available for %s\n", c->name);
exit(1);
}
if (isa_bus) {
c->init.init_isa(isa_bus);
} else {
if (!pci_bus) {
fprintf(stderr, "PCI bus not available for %s\n", c->name);
exit(1);
}
} else {
if (pci_bus) {
c->init.init_pci(pci_bus);
}
}
}
}
}
#else
void select_soundhw(const char *optarg)
{
}
void audio_init(ISABus *isa_bus, PCIBus *pci_bus)
{
}
#endif
int qemu_uuid_parse(const char *str, uint8_t *uuid)
{
@@ -1029,21 +1094,16 @@ int qemu_uuid_parse(const char *str, uint8_t *uuid)
return -1;
}
#ifdef TARGET_I386
smbios_add_field(1, offsetof(struct smbios_type_1, uuid), uuid, 16);
smbios_add_field(1, offsetof(struct smbios_type_1, uuid), 16, uuid);
#endif
return 0;
}
void do_acpitable_option(const QemuOpts *opts)
void do_acpitable_option(const char *optarg)
{
#ifdef TARGET_I386
Error *err = NULL;
acpi_table_add(opts, &err);
if (err) {
fprintf(stderr, "Wrong acpi table provided: %s\n",
error_get_pretty(err));
error_free(err);
if (acpi_table_add(optarg) < 0) {
fprintf(stderr, "Wrong acpi table provided\n");
exit(1);
}
#endif
@@ -1053,6 +1113,7 @@ void do_smbios_option(const char *optarg)
{
#ifdef TARGET_I386
if (smbios_entry_add(optarg) < 0) {
fprintf(stderr, "Wrong smbios provided\n");
exit(1);
}
#endif
@@ -1065,6 +1126,15 @@ void cpudef_init(void)
#endif
}
int audio_available(void)
{
#ifdef HAS_AUDIO
return 1;
#else
return 0;
#endif
}
int tcg_available(void)
{
return 1;

13
async.c
View File

@@ -24,7 +24,6 @@
#include "qemu-common.h"
#include "block/aio.h"
#include "block/thread-pool.h"
#include "qemu/main-loop.h"
/***********************************************************/
@@ -173,10 +172,8 @@ aio_ctx_finalize(GSource *source)
{
AioContext *ctx = (AioContext *) source;
thread_pool_free(ctx->thread_pool);
aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL);
event_notifier_cleanup(&ctx->notifier);
g_array_free(ctx->pollfds, TRUE);
}
static GSourceFuncs aio_source_funcs = {
@@ -192,14 +189,6 @@ GSource *aio_get_g_source(AioContext *ctx)
return &ctx->source;
}
ThreadPool *aio_get_thread_pool(AioContext *ctx)
{
if (!ctx->thread_pool) {
ctx->thread_pool = thread_pool_new(ctx);
}
return ctx->thread_pool;
}
void aio_notify(AioContext *ctx)
{
event_notifier_set(&ctx->notifier);
@@ -209,8 +198,6 @@ AioContext *aio_context_new(void)
{
AioContext *ctx;
ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
ctx->thread_pool = NULL;
event_notifier_init(&ctx->notifier, false);
aio_set_event_notifier(ctx, &ctx->notifier,
(EventNotifierHandler *)

View File

@@ -25,7 +25,11 @@
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#ifdef __OpenBSD__
#include <soundcard.h>
#else
#include <sys/soundcard.h>
#endif
#include "qemu-common.h"
#include "qemu/main-loop.h"
#include "qemu/host-utils.h"

View File

@@ -1,8 +1,2 @@
common-obj-y += rng.o rng-egd.o
common-obj-$(CONFIG_POSIX) += rng-random.o
common-obj-y += msmouse.o
common-obj-$(CONFIG_BRLAPI) += baum.o
$(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
common-obj-$(CONFIG_TPM) += tpm.o

View File

@@ -10,8 +10,8 @@
* See the COPYING file in the top-level directory.
*/
#include "sysemu/rng.h"
#include "sysemu/char.h"
#include "qemu/rng.h"
#include "char/char.h"
#include "qapi/qmp/qerror.h"
#include "hw/qdev.h" /* just for DEFINE_PROP_CHR */
@@ -149,11 +149,6 @@ static void rng_egd_opened(RngBackend *b, Error **errp)
return;
}
if (qemu_chr_fe_claim(s->chr) != 0) {
error_set(errp, QERR_DEVICE_IN_USE, s->chr_name);
return;
}
/* FIXME we should resubmit pending requests when the CDS reconnects. */
qemu_chr_add_handlers(s->chr, rng_egd_chr_can_read, rng_egd_chr_read,
NULL, s);
@@ -196,7 +191,6 @@ static void rng_egd_finalize(Object *obj)
if (s->chr) {
qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
qemu_chr_fe_release(s->chr);
}
g_free(s->chr_name);

View File

@@ -10,8 +10,8 @@
* See the COPYING file in the top-level directory.
*/
#include "sysemu/rng-random.h"
#include "sysemu/rng.h"
#include "qemu/rng-random.h"
#include "qemu/rng.h"
#include "qapi/qmp/qerror.h"
#include "qemu/main-loop.h"
@@ -41,9 +41,6 @@ static void entropy_available(void *opaque)
ssize_t len;
len = read(s->fd, buffer, s->size);
if (len < 0 && errno == EAGAIN) {
return;
}
g_assert(len != -1);
s->receive_func(s->opaque, buffer, len);
@@ -77,7 +74,7 @@ static void rng_random_opened(RngBackend *b, Error **errp)
error_set(errp, QERR_INVALID_PARAMETER_VALUE,
"filename", "a valid filename");
} else {
s->fd = qemu_open(s->filename, O_RDONLY | O_NONBLOCK);
s->fd = open(s->filename, O_RDONLY | O_NONBLOCK);
if (s->fd == -1) {
error_set(errp, QERR_OPEN_FILE_FAILED, s->filename);
@@ -133,7 +130,7 @@ static void rng_random_finalize(Object *obj)
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
if (s->fd != -1) {
qemu_close(s->fd);
close(s->fd);
}
g_free(s->filename);

View File

@@ -10,7 +10,7 @@
* See the COPYING file in the top-level directory.
*/
#include "sysemu/rng.h"
#include "qemu/rng.h"
#include "qapi/qmp/qerror.h"
void rng_backend_request_entropy(RngBackend *s, size_t size,

View File

@@ -1,190 +0,0 @@
/*
* QEMU TPM Backend
*
* Copyright IBM, Corp. 2013
*
* Authors:
* Stefan Berger <stefanb@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
* Based on backends/rng.c by Anthony Liguori
*/
#include "sysemu/tpm_backend.h"
#include "qapi/qmp/qerror.h"
#include "sysemu/tpm.h"
#include "qemu/thread.h"
#include "sysemu/tpm_backend_int.h"
enum TpmType tpm_backend_get_type(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
return k->ops->type;
}
const char *tpm_backend_get_desc(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
return k->ops->desc();
}
void tpm_backend_destroy(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
return k->ops->destroy(s);
}
int tpm_backend_init(TPMBackend *s, TPMState *state,
TPMRecvDataCB *datacb)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
return k->ops->init(s, state, datacb);
}
int tpm_backend_startup_tpm(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
return k->ops->startup_tpm(s);
}
bool tpm_backend_had_startup_error(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
return k->ops->had_startup_error(s);
}
size_t tpm_backend_realloc_buffer(TPMBackend *s, TPMSizedBuffer *sb)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
return k->ops->realloc_buffer(sb);
}
void tpm_backend_deliver_request(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
k->ops->deliver_request(s);
}
void tpm_backend_reset(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
k->ops->reset(s);
}
void tpm_backend_cancel_cmd(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
k->ops->cancel_cmd(s);
}
bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
return k->ops->get_tpm_established_flag(s);
}
static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
{
TPMBackend *s = TPM_BACKEND(obj);
return s->opened;
}
void tpm_backend_open(TPMBackend *s, Error **errp)
{
object_property_set_bool(OBJECT(s), true, "opened", errp);
}
static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp)
{
TPMBackend *s = TPM_BACKEND(obj);
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
if (value == s->opened) {
return;
}
if (!value && s->opened) {
error_set(errp, QERR_PERMISSION_DENIED);
return;
}
if (k->opened) {
k->opened(s, errp);
}
if (!error_is_set(errp)) {
s->opened = value;
}
}
static void tpm_backend_instance_init(Object *obj)
{
object_property_add_bool(obj, "opened",
tpm_backend_prop_get_opened,
tpm_backend_prop_set_opened,
NULL);
}
void tpm_backend_thread_deliver_request(TPMBackendThread *tbt)
{
g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_PROCESS_CMD, NULL);
}
void tpm_backend_thread_create(TPMBackendThread *tbt,
GFunc func, gpointer user_data)
{
if (!tbt->pool) {
tbt->pool = g_thread_pool_new(func, user_data, 1, TRUE, NULL);
g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_INIT, NULL);
}
}
void tpm_backend_thread_end(TPMBackendThread *tbt)
{
if (tbt->pool) {
g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_END, NULL);
g_thread_pool_free(tbt->pool, FALSE, TRUE);
tbt->pool = NULL;
}
}
void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt,
GFunc func, gpointer user_data)
{
if (!tbt->pool) {
tpm_backend_thread_create(tbt, func, user_data);
} else {
g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_TPM_RESET,
NULL);
}
}
static const TypeInfo tpm_backend_info = {
.name = TYPE_TPM_BACKEND,
.parent = TYPE_OBJECT,
.instance_size = sizeof(TPMBackend),
.instance_init = tpm_backend_instance_init,
.class_size = sizeof(TPMBackendClass),
.abstract = true,
};
static void register_types(void)
{
type_register_static(&tpm_backend_info);
}
type_init(register_types);

View File

@@ -43,24 +43,19 @@
#endif
typedef struct BlkMigDevState {
/* Written during setup phase. Can be read without a lock. */
BlockDriverState *bs;
int shared_base;
int64_t total_sectors;
QSIMPLEQ_ENTRY(BlkMigDevState) entry;
/* Only used by migration thread. Does not need a lock. */
int bulk_completed;
int shared_base;
int64_t cur_sector;
int64_t cur_dirty;
/* Protected by block migration lock. */
unsigned long *aio_bitmap;
int64_t completed_sectors;
int64_t total_sectors;
int64_t dirty;
QSIMPLEQ_ENTRY(BlkMigDevState) entry;
unsigned long *aio_bitmap;
} BlkMigDevState;
typedef struct BlkMigBlock {
/* Only used by migration thread. */
uint8_t *buf;
BlkMigDevState *bmds;
int64_t sector;
@@ -68,49 +63,26 @@ typedef struct BlkMigBlock {
struct iovec iov;
QEMUIOVector qiov;
BlockDriverAIOCB *aiocb;
/* Protected by block migration lock. */
int ret;
QSIMPLEQ_ENTRY(BlkMigBlock) entry;
} BlkMigBlock;
typedef struct BlkMigState {
/* Written during setup phase. Can be read without a lock. */
int blk_enable;
int shared_base;
QSIMPLEQ_HEAD(bmds_list, BlkMigDevState) bmds_list;
int64_t total_sector_sum;
/* Protected by lock. */
QSIMPLEQ_HEAD(blk_list, BlkMigBlock) blk_list;
int submitted;
int read_done;
/* Only used by migration thread. Does not need a lock. */
int transferred;
int64_t total_sector_sum;
int prev_progress;
int bulk_completed;
/* Lock must be taken _inside_ the iothread lock. */
QemuMutex lock;
long double prev_time_offset;
} BlkMigState;
static BlkMigState block_mig_state;
static void blk_mig_lock(void)
{
qemu_mutex_lock(&block_mig_state.lock);
}
static void blk_mig_unlock(void)
{
qemu_mutex_unlock(&block_mig_state.lock);
}
/* Must run outside of the iothread lock during the bulk phase,
* or the VM will stall.
*/
static void blk_send(QEMUFile *f, BlkMigBlock * blk)
{
int len;
@@ -137,11 +109,9 @@ uint64_t blk_mig_bytes_transferred(void)
BlkMigDevState *bmds;
uint64_t sum = 0;
blk_mig_lock();
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
sum += bmds->completed_sectors;
}
blk_mig_unlock();
return sum << BDRV_SECTOR_BITS;
}
@@ -161,9 +131,6 @@ uint64_t blk_mig_bytes_total(void)
return sum << BDRV_SECTOR_BITS;
}
/* Called with migration lock held. */
static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
{
int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
@@ -176,8 +143,6 @@ static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
}
}
/* Called with migration lock held. */
static void bmds_set_aio_inflight(BlkMigDevState *bmds, int64_t sector_num,
int nb_sectors, int set)
{
@@ -212,26 +177,23 @@ static void alloc_aio_bitmap(BlkMigDevState *bmds)
bmds->aio_bitmap = g_malloc0(bitmap_size);
}
/* Never hold migration lock when yielding to the main loop! */
static void blk_mig_read_cb(void *opaque, int ret)
{
long double curr_time = qemu_get_clock_ns(rt_clock);
BlkMigBlock *blk = opaque;
blk_mig_lock();
blk->ret = ret;
block_mig_state.prev_time_offset = curr_time;
QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
bmds_set_aio_inflight(blk->bmds, blk->sector, blk->nr_sectors, 0);
block_mig_state.submitted--;
block_mig_state.read_done++;
assert(block_mig_state.submitted >= 0);
blk_mig_unlock();
}
/* Called with no lock taken. */
static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
{
int64_t total_sectors = bmds->total_sectors;
@@ -241,13 +203,11 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
int nr_sectors;
if (bmds->shared_base) {
qemu_mutex_lock_iothread();
while (cur_sector < total_sectors &&
!bdrv_is_allocated(bs, cur_sector, MAX_IS_ALLOCATED_SEARCH,
&nr_sectors)) {
cur_sector += nr_sectors;
}
qemu_mutex_unlock_iothread();
}
if (cur_sector >= total_sectors) {
@@ -276,23 +236,20 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
blk_mig_lock();
block_mig_state.submitted++;
blk_mig_unlock();
if (block_mig_state.submitted == 0) {
block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
}
qemu_mutex_lock_iothread();
blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
nr_sectors, blk_mig_read_cb, blk);
block_mig_state.submitted++;
bdrv_reset_dirty(bs, cur_sector, nr_sectors);
qemu_mutex_unlock_iothread();
bmds->cur_sector = cur_sector + nr_sectors;
return (bmds->cur_sector >= total_sectors);
}
/* Called with iothread lock taken. */
static void set_dirty_tracking(int enable)
{
BlkMigDevState *bmds;
@@ -348,8 +305,6 @@ static void init_blk_migration(QEMUFile *f)
bdrv_iterate(init_blk_migration_it, NULL);
}
/* Called with no lock taken. */
static int blk_mig_save_bulked_block(QEMUFile *f)
{
int64_t completed_sector_sum = 0;
@@ -396,8 +351,6 @@ static void blk_mig_reset_dirty_cursor(void)
}
}
/* Called with iothread lock taken. */
static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
int is_async)
{
@@ -408,12 +361,8 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
int ret = -EIO;
for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) {
blk_mig_lock();
if (bmds_aio_inflight(bmds, sector)) {
blk_mig_unlock();
bdrv_drain_all();
} else {
blk_mig_unlock();
}
if (bdrv_get_dirty(bmds->bs, sector)) {
@@ -433,13 +382,14 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
if (block_mig_state.submitted == 0) {
block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
}
blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov,
nr_sectors, blk_mig_read_cb, blk);
blk_mig_lock();
block_mig_state.submitted++;
bmds_set_aio_inflight(bmds, sector, nr_sectors, 1);
blk_mig_unlock();
} else {
ret = bdrv_read(bmds->bs, sector, blk->buf, nr_sectors);
if (ret < 0) {
@@ -467,9 +417,7 @@ error:
return ret;
}
/* Called with iothread lock taken.
*
* return value:
/* return value:
* 0: too much data for max_downtime
* 1: few enough data for max_downtime
*/
@@ -488,8 +436,6 @@ static int blk_mig_save_dirty_block(QEMUFile *f, int is_async)
return ret;
}
/* Called with no locks taken. */
static int flush_blks(QEMUFile *f)
{
BlkMigBlock *blk;
@@ -499,7 +445,6 @@ static int flush_blks(QEMUFile *f)
__FUNCTION__, block_mig_state.submitted, block_mig_state.read_done,
block_mig_state.transferred);
blk_mig_lock();
while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) {
if (qemu_file_rate_limit(f)) {
break;
@@ -508,12 +453,9 @@ static int flush_blks(QEMUFile *f)
ret = blk->ret;
break;
}
blk_send(f, blk);
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
blk_mig_unlock();
blk_send(f, blk);
blk_mig_lock();
g_free(blk->buf);
g_free(blk);
@@ -521,7 +463,6 @@ static int flush_blks(QEMUFile *f)
block_mig_state.transferred++;
assert(block_mig_state.read_done >= 0);
}
blk_mig_unlock();
DPRINTF("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__,
block_mig_state.submitted, block_mig_state.read_done,
@@ -529,8 +470,6 @@ static int flush_blks(QEMUFile *f)
return ret;
}
/* Called with iothread lock taken. */
static int64_t get_remaining_dirty(void)
{
BlkMigDevState *bmds;
@@ -543,8 +482,6 @@ static int64_t get_remaining_dirty(void)
return dirty << BDRV_SECTOR_BITS;
}
/* Called with iothread lock taken. */
static void blk_mig_cleanup(void)
{
BlkMigDevState *bmds;
@@ -554,7 +491,6 @@ static void blk_mig_cleanup(void)
set_dirty_tracking(0);
blk_mig_lock();
while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
bdrv_set_in_use(bmds->bs, 0);
@@ -568,7 +504,6 @@ static void blk_mig_cleanup(void)
g_free(blk->buf);
g_free(blk);
}
blk_mig_unlock();
}
static void block_migration_cancel(void *opaque)
@@ -583,18 +518,22 @@ static int block_save_setup(QEMUFile *f, void *opaque)
DPRINTF("Enter save live setup submitted %d transferred %d\n",
block_mig_state.submitted, block_mig_state.transferred);
qemu_mutex_lock_iothread();
init_blk_migration(f);
/* start track dirty blocks */
set_dirty_tracking(1);
qemu_mutex_unlock_iothread();
ret = flush_blks(f);
if (ret) {
blk_mig_cleanup();
return ret;
}
blk_mig_reset_dirty_cursor();
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
return ret;
return 0;
}
static int block_save_iterate(QEMUFile *f, void *opaque)
@@ -607,54 +546,46 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
ret = flush_blks(f);
if (ret) {
blk_mig_cleanup();
return ret;
}
blk_mig_reset_dirty_cursor();
/* control the rate of transfer */
blk_mig_lock();
while ((block_mig_state.submitted +
block_mig_state.read_done) * BLOCK_SIZE <
qemu_file_get_rate_limit(f)) {
blk_mig_unlock();
if (block_mig_state.bulk_completed == 0) {
/* first finish the bulk phase */
if (blk_mig_save_bulked_block(f) == 0) {
/* finished saving bulk on all devices */
block_mig_state.bulk_completed = 1;
}
ret = 0;
} else {
/* Always called with iothread lock taken for
* simplicity, block_save_complete also calls it.
*/
qemu_mutex_lock_iothread();
ret = blk_mig_save_dirty_block(f, 1);
qemu_mutex_unlock_iothread();
}
if (ret < 0) {
return ret;
}
blk_mig_lock();
if (ret != 0) {
/* no more dirty blocks */
break;
}
}
blk_mig_unlock();
}
if (ret < 0) {
blk_mig_cleanup();
return ret;
}
ret = flush_blks(f);
if (ret) {
blk_mig_cleanup();
return ret;
}
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
return qemu_ftell(f) - last_ftell;
}
/* Called with iothread lock taken. */
static int block_save_complete(QEMUFile *f, void *opaque)
{
int ret;
@@ -664,6 +595,7 @@ static int block_save_complete(QEMUFile *f, void *opaque)
ret = flush_blks(f);
if (ret) {
blk_mig_cleanup();
return ret;
}
@@ -671,17 +603,16 @@ static int block_save_complete(QEMUFile *f, void *opaque)
/* we know for sure that save bulk is completed and
all async read completed */
blk_mig_lock();
assert(block_mig_state.submitted == 0);
blk_mig_unlock();
do {
ret = blk_mig_save_dirty_block(f, 0);
} while (ret == 0);
blk_mig_cleanup();
if (ret < 0) {
return ret;
}
} while (ret == 0);
/* report completion */
qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);
@@ -689,18 +620,13 @@ static int block_save_complete(QEMUFile *f, void *opaque)
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
blk_mig_cleanup();
return 0;
}
static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
{
/* Estimate pending number of bytes to send */
uint64_t pending;
qemu_mutex_lock_iothread();
blk_mig_lock();
pending = get_remaining_dirty() +
uint64_t pending = get_remaining_dirty() +
block_mig_state.submitted * BLOCK_SIZE +
block_mig_state.read_done * BLOCK_SIZE;
@@ -708,8 +634,6 @@ static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
if (pending == 0 && !block_mig_state.bulk_completed) {
pending = BLOCK_SIZE;
}
blk_mig_unlock();
qemu_mutex_unlock_iothread();
DPRINTF("Enter save live pending %" PRIu64 "\n", pending);
return pending;
@@ -821,7 +745,6 @@ void blk_mig_init(void)
{
QSIMPLEQ_INIT(&block_mig_state.bmds_list);
QSIMPLEQ_INIT(&block_mig_state.blk_list);
qemu_mutex_init(&block_mig_state.lock);
register_savevm_live(NULL, "block", 0, 1, &savevm_block_handlers,
&block_mig_state);

533
block.c
View File

@@ -140,6 +140,8 @@ void bdrv_io_limits_disable(BlockDriverState *bs)
bs->slice_start = 0;
bs->slice_end = 0;
bs->slice_time = 0;
memset(&bs->io_base, 0, sizeof(bs->io_base));
}
static void bdrv_block_timer(void *opaque)
@@ -578,26 +580,6 @@ static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
return 0;
}
/**
* Set open flags for a given discard mode
*
* Return 0 on success, -1 if the discard mode was invalid.
*/
int bdrv_parse_discard_flags(const char *mode, int *flags)
{
*flags &= ~BDRV_O_UNMAP;
if (!strcmp(mode, "off") || !strcmp(mode, "ignore")) {
/* do nothing */
} else if (!strcmp(mode, "on") || !strcmp(mode, "unmap")) {
*flags |= BDRV_O_UNMAP;
} else {
return -1;
}
return 0;
}
/**
* Set open flags for a given cache mode
*
@@ -663,38 +645,17 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
/*
* Common part for opening disk images and files
*
* Removes all processed options from *options.
*/
static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
QDict *options, int flags, BlockDriver *drv)
const char *filename,
int flags, BlockDriver *drv)
{
int ret, open_flags;
const char *filename;
assert(drv != NULL);
assert(bs->file == NULL);
assert(options != NULL && bs->options != options);
if (file != NULL) {
filename = file->filename;
} else {
filename = qdict_get_try_str(options, "filename");
}
trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name);
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
return -ENOTSUP;
}
/* bdrv_open() with directly using a protocol as drv. This layer is already
* opened, so assign it to bs (while file becomes a closed BlockDriverState)
* and return immediately. */
if (file != NULL && drv->bdrv_file_open) {
bdrv_swap(file, bs);
return 0;
}
trace_bdrv_open_common(bs, filename, flags, drv->format_name);
bs->open_flags = flags;
bs->buffer_alignment = 512;
@@ -704,10 +665,10 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
bdrv_enable_copy_on_read(bs);
}
if (filename != NULL) {
pstrcpy(bs->filename, sizeof(bs->filename), filename);
} else {
bs->filename[0] = '\0';
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
return -ENOTSUP;
}
bs->drv = drv;
@@ -720,20 +681,16 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
/* Open the image, either directly or using a protocol */
if (drv->bdrv_file_open) {
assert(file == NULL);
assert(drv->bdrv_parse_filename || filename != NULL);
ret = drv->bdrv_file_open(bs, options, open_flags);
if (file != NULL) {
bdrv_swap(file, bs);
ret = 0;
} else {
if (file == NULL) {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Can't use '%s' as a "
"block driver for the protocol level",
drv->format_name);
ret = -EINVAL;
goto free_and_fail;
ret = drv->bdrv_file_open(bs, filename, open_flags);
}
} else {
assert(file != NULL);
bs->file = file;
ret = drv->bdrv_open(bs, options, open_flags);
ret = drv->bdrv_open(bs, open_flags);
}
if (ret < 0) {
@@ -747,7 +704,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
#ifndef _WIN32
if (bs->is_temporary) {
assert(filename != NULL);
unlink(filename);
}
#endif
@@ -763,136 +719,41 @@ free_and_fail:
/*
* Opens a file using a protocol (file, host_device, nbd, ...)
*
* options is a QDict of options to pass to the block drivers, or NULL for an
* empty set of options. The reference to the QDict belongs to the block layer
* after the call (even on failure), so if the caller intends to reuse the
* dictionary, it needs to use QINCREF() before calling bdrv_file_open.
*/
int bdrv_file_open(BlockDriverState **pbs, const char *filename,
QDict *options, int flags)
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
{
BlockDriverState *bs;
BlockDriver *drv;
const char *drvname;
int ret;
/* NULL means an empty set of options */
if (options == NULL) {
options = qdict_new();
drv = bdrv_find_protocol(filename);
if (!drv) {
return -ENOENT;
}
bs = bdrv_new("");
bs->options = options;
options = qdict_clone_shallow(options);
/* Fetch the file name from the options QDict if necessary */
if (!filename) {
filename = qdict_get_try_str(options, "filename");
} else if (filename && !qdict_haskey(options, "filename")) {
qdict_put(options, "filename", qstring_from_str(filename));
} else {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Can't specify 'file' and "
"'filename' options at the same time");
ret = -EINVAL;
goto fail;
}
/* Find the right block driver */
drvname = qdict_get_try_str(options, "driver");
if (drvname) {
drv = bdrv_find_whitelisted_format(drvname);
qdict_del(options, "driver");
} else if (filename) {
drv = bdrv_find_protocol(filename);
} else {
qerror_report(ERROR_CLASS_GENERIC_ERROR,
"Must specify either driver or file");
drv = NULL;
}
if (!drv) {
ret = -ENOENT;
goto fail;
}
/* Parse the filename and open it */
if (drv->bdrv_parse_filename && filename) {
Error *local_err = NULL;
drv->bdrv_parse_filename(filename, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
ret = -EINVAL;
goto fail;
}
qdict_del(options, "filename");
} else if (!drv->bdrv_parse_filename && !filename) {
qerror_report(ERROR_CLASS_GENERIC_ERROR,
"The '%s' block driver requires a file name",
drv->format_name);
ret = -EINVAL;
goto fail;
}
ret = bdrv_open_common(bs, NULL, options, flags, drv);
ret = bdrv_open_common(bs, NULL, filename, flags, drv);
if (ret < 0) {
goto fail;
bdrv_delete(bs);
return ret;
}
/* Check if any unknown options were used */
if (qdict_size(options) != 0) {
const QDictEntry *entry = qdict_first(options);
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Block protocol '%s' doesn't "
"support the option '%s'",
drv->format_name, entry->key);
ret = -EINVAL;
goto fail;
}
QDECREF(options);
bs->growable = 1;
*pbs = bs;
return 0;
fail:
QDECREF(options);
if (!bs->drv) {
QDECREF(bs->options);
}
bdrv_delete(bs);
return ret;
}
/*
* Opens the backing file for a BlockDriverState if not yet open
*
* options is a QDict of options to pass to the block drivers, or NULL for an
* empty set of options. The reference to the QDict is transferred to this
* function (even on failure), so if the caller intends to reuse the dictionary,
* it needs to use QINCREF() before calling bdrv_file_open.
*/
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options)
int bdrv_open_backing_file(BlockDriverState *bs)
{
char backing_filename[PATH_MAX];
int back_flags, ret;
BlockDriver *back_drv = NULL;
if (bs->backing_hd != NULL) {
QDECREF(options);
return 0;
}
/* NULL means an empty set of options */
if (options == NULL) {
options = qdict_new();
}
bs->open_flags &= ~BDRV_O_NO_BACKING;
if (qdict_haskey(options, "file.filename")) {
backing_filename[0] = '\0';
} else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
QDECREF(options);
if (bs->backing_file[0] == '\0') {
return 0;
}
@@ -907,9 +768,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options)
/* backing files always opened read-only */
back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT);
ret = bdrv_open(bs->backing_hd,
*backing_filename ? backing_filename : NULL, options,
back_flags, back_drv);
ret = bdrv_open(bs->backing_hd, backing_filename, back_flags, back_drv);
if (ret < 0) {
bdrv_delete(bs->backing_hd);
bs->backing_hd = NULL;
@@ -919,109 +778,68 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options)
return 0;
}
static void extract_subqdict(QDict *src, QDict **dst, const char *start)
{
const QDictEntry *entry, *next;
const char *p;
*dst = qdict_new();
entry = qdict_first(src);
while (entry != NULL) {
next = qdict_next(src, entry);
if (strstart(entry->key, start, &p)) {
qobject_incref(entry->value);
qdict_put_obj(*dst, p, entry->value);
qdict_del(src, entry->key);
}
entry = next;
}
}
/*
* Opens a disk image (raw, qcow2, vmdk, ...)
*
* options is a QDict of options to pass to the block drivers, or NULL for an
* empty set of options. The reference to the QDict belongs to the block layer
* after the call (even on failure), so if the caller intends to reuse the
* dictionary, it needs to use QINCREF() before calling bdrv_open.
*/
int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
int flags, BlockDriver *drv)
int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
BlockDriver *drv)
{
int ret;
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
char tmp_filename[PATH_MAX + 1];
BlockDriverState *file = NULL;
QDict *file_options = NULL;
/* NULL means an empty set of options */
if (options == NULL) {
options = qdict_new();
}
bs->options = options;
options = qdict_clone_shallow(options);
/* For snapshot=on, create a temporary qcow2 overlay */
if (flags & BDRV_O_SNAPSHOT) {
BlockDriverState *bs1;
int64_t total_size;
int is_protocol = 0;
BlockDriver *bdrv_qcow2;
QEMUOptionParameter *create_options;
QEMUOptionParameter *options;
char backing_filename[PATH_MAX];
if (qdict_size(options) != 0) {
error_report("Can't use snapshot=on with driver-specific options");
ret = -EINVAL;
goto fail;
}
assert(filename != NULL);
/* if snapshot, we create a temporary backing file and open it
instead of opening 'filename' directly */
/* if there is a backing file, use it */
bs1 = bdrv_new("");
ret = bdrv_open(bs1, filename, NULL, 0, drv);
ret = bdrv_open(bs1, filename, 0, drv);
if (ret < 0) {
bdrv_delete(bs1);
goto fail;
return ret;
}
total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
if (bs1->drv && bs1->drv->protocol_name)
is_protocol = 1;
bdrv_delete(bs1);
ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
if (ret < 0) {
goto fail;
return ret;
}
/* Real path is meaningless for protocols */
if (path_has_protocol(filename)) {
if (is_protocol)
snprintf(backing_filename, sizeof(backing_filename),
"%s", filename);
} else if (!realpath(filename, backing_filename)) {
ret = -errno;
goto fail;
}
else if (!realpath(filename, backing_filename))
return -errno;
bdrv_qcow2 = bdrv_find_format("qcow2");
create_options = parse_option_parameters("", bdrv_qcow2->create_options,
NULL);
options = parse_option_parameters("", bdrv_qcow2->create_options, NULL);
set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size);
set_option_parameter(create_options, BLOCK_OPT_BACKING_FILE,
backing_filename);
set_option_parameter_int(options, BLOCK_OPT_SIZE, total_size);
set_option_parameter(options, BLOCK_OPT_BACKING_FILE, backing_filename);
if (drv) {
set_option_parameter(create_options, BLOCK_OPT_BACKING_FMT,
set_option_parameter(options, BLOCK_OPT_BACKING_FMT,
drv->format_name);
}
ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options);
free_option_parameters(create_options);
ret = bdrv_create(bdrv_qcow2, tmp_filename, options);
free_option_parameters(options);
if (ret < 0) {
goto fail;
return ret;
}
filename = tmp_filename;
@@ -1034,12 +852,9 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
flags |= BDRV_O_ALLOW_RDWR;
}
extract_subqdict(options, &file_options, "file.");
ret = bdrv_file_open(&file, filename, file_options,
bdrv_open_flags(bs, flags));
ret = bdrv_file_open(&file, filename, bdrv_open_flags(bs, flags));
if (ret < 0) {
goto fail;
return ret;
}
/* Find the right image format driver */
@@ -1052,7 +867,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
}
/* Open the image */
ret = bdrv_open_common(bs, file, options, flags, drv);
ret = bdrv_open_common(bs, file, filename, flags, drv);
if (ret < 0) {
goto unlink_and_fail;
}
@@ -1064,27 +879,13 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
/* If there is a backing file, use it */
if ((flags & BDRV_O_NO_BACKING) == 0) {
QDict *backing_options;
extract_subqdict(options, &backing_options, "backing.");
ret = bdrv_open_backing_file(bs, backing_options);
ret = bdrv_open_backing_file(bs);
if (ret < 0) {
goto close_and_fail;
bdrv_close(bs);
return ret;
}
}
/* Check if any unknown options were used */
if (qdict_size(options) != 0) {
const QDictEntry *entry = qdict_first(options);
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Block format '%s' used by "
"device '%s' doesn't support the option '%s'",
drv->format_name, bs->device_name, entry->key);
ret = -EINVAL;
goto close_and_fail;
}
QDECREF(options);
if (!bdrv_key_required(bs)) {
bdrv_dev_change_media_cb(bs, true);
}
@@ -1103,15 +904,6 @@ unlink_and_fail:
if (bs->is_temporary) {
unlink(filename);
}
fail:
QDECREF(bs->options);
QDECREF(options);
bs->options = NULL;
return ret;
close_and_fail:
bdrv_close(bs);
QDECREF(options);
return ret;
}
@@ -1381,8 +1173,6 @@ void bdrv_close(BlockDriverState *bs)
bs->valid_key = 0;
bs->sg = 0;
bs->growable = 0;
QDECREF(bs->options);
bs->options = NULL;
if (bs->file != NULL) {
bdrv_delete(bs->file);
@@ -1478,10 +1268,11 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
bs_dest->enable_write_cache = bs_src->enable_write_cache;
/* i/o timing parameters */
bs_dest->slice_time = bs_src->slice_time;
bs_dest->slice_start = bs_src->slice_start;
bs_dest->slice_end = bs_src->slice_end;
bs_dest->slice_submitted = bs_src->slice_submitted;
bs_dest->io_limits = bs_src->io_limits;
bs_dest->io_base = bs_src->io_base;
bs_dest->throttled_reqs = bs_src->throttled_reqs;
bs_dest->block_timer = bs_src->block_timer;
bs_dest->io_limits_enabled = bs_src->io_limits_enabled;
@@ -1829,13 +1620,11 @@ int bdrv_commit_all(void)
BlockDriverState *bs;
QTAILQ_FOREACH(bs, &bdrv_states, list) {
if (bs->drv && bs->backing_hd) {
int ret = bdrv_commit(bs);
if (ret < 0) {
return ret;
}
}
}
return 0;
}
@@ -2178,21 +1967,27 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque)
}
/*
* Process a vectored synchronous request using coroutines
* Process a synchronous request using coroutines
*/
static int bdrv_rwv_co(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, bool is_write)
static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
int nb_sectors, bool is_write)
{
QEMUIOVector qiov;
struct iovec iov = {
.iov_base = (void *)buf,
.iov_len = nb_sectors * BDRV_SECTOR_SIZE,
};
Coroutine *co;
RwCo rwco = {
.bs = bs,
.sector_num = sector_num,
.nb_sectors = qiov->size >> BDRV_SECTOR_BITS,
.qiov = qiov,
.nb_sectors = nb_sectors,
.qiov = &qiov,
.is_write = is_write,
.ret = NOT_DONE,
};
assert((qiov->size & (BDRV_SECTOR_SIZE - 1)) == 0);
qemu_iovec_init_external(&qiov, &iov, 1);
/**
* In sync call context, when the vcpu is blocked, this throttling timer
@@ -2218,22 +2013,6 @@ static int bdrv_rwv_co(BlockDriverState *bs, int64_t sector_num,
return rwco.ret;
}
/*
* Process a synchronous request using coroutines
*/
static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
int nb_sectors, bool is_write)
{
QEMUIOVector qiov;
struct iovec iov = {
.iov_base = (void *)buf,
.iov_len = nb_sectors * BDRV_SECTOR_SIZE,
};
qemu_iovec_init_external(&qiov, &iov, 1);
return bdrv_rwv_co(bs, sector_num, &qiov, is_write);
}
/* return < 0 if error. See bdrv_write() for the return codes */
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
@@ -2267,11 +2046,6 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
return bdrv_rw_co(bs, sector_num, (uint8_t *)buf, nb_sectors, true);
}
int bdrv_writev(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov)
{
return bdrv_rwv_co(bs, sector_num, qiov, true);
}
int bdrv_pread(BlockDriverState *bs, int64_t offset,
void *buf, int count1)
{
@@ -2317,15 +2091,15 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
return count1;
}
int bdrv_pwritev(BlockDriverState *bs, int64_t offset, QEMUIOVector *qiov)
int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
const void *buf, int count1)
{
uint8_t tmp_buf[BDRV_SECTOR_SIZE];
int len, nb_sectors, count;
int64_t sector_num;
int ret;
count = qiov->size;
count = count1;
/* first write to align to sector start */
len = (BDRV_SECTOR_SIZE - offset) & (BDRV_SECTOR_SIZE - 1);
if (len > count)
@@ -2334,32 +2108,24 @@ int bdrv_pwritev(BlockDriverState *bs, int64_t offset, QEMUIOVector *qiov)
if (len > 0) {
if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
return ret;
qemu_iovec_to_buf(qiov, 0, tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)),
len);
memcpy(tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), buf, len);
if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0)
return ret;
count -= len;
if (count == 0)
return qiov->size;
return count1;
sector_num++;
buf += len;
}
/* write the sectors "in place" */
nb_sectors = count >> BDRV_SECTOR_BITS;
if (nb_sectors > 0) {
QEMUIOVector qiov_inplace;
qemu_iovec_init(&qiov_inplace, qiov->niov);
qemu_iovec_concat(&qiov_inplace, qiov, len,
nb_sectors << BDRV_SECTOR_BITS);
ret = bdrv_writev(bs, sector_num, &qiov_inplace);
qemu_iovec_destroy(&qiov_inplace);
if (ret < 0) {
if ((ret = bdrv_write(bs, sector_num, buf, nb_sectors)) < 0)
return ret;
}
sector_num += nb_sectors;
len = nb_sectors << BDRV_SECTOR_BITS;
buf += len;
count -= len;
}
@@ -2367,24 +2133,11 @@ int bdrv_pwritev(BlockDriverState *bs, int64_t offset, QEMUIOVector *qiov)
if (count > 0) {
if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
return ret;
qemu_iovec_to_buf(qiov, qiov->size - count, tmp_buf, count);
memcpy(tmp_buf, buf, count);
if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0)
return ret;
}
return qiov->size;
}
int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
const void *buf, int count1)
{
QEMUIOVector qiov;
struct iovec iov = {
.iov_base = (void *) buf,
.iov_len = count1,
};
qemu_iovec_init_external(&qiov, &iov, 1);
return bdrv_pwritev(bs, offset, &qiov);
return count1;
}
/*
@@ -2928,7 +2681,6 @@ int bdrv_has_zero_init(BlockDriverState *bs)
typedef struct BdrvCoIsAllocatedData {
BlockDriverState *bs;
BlockDriverState *base;
int64_t sector_num;
int nb_sectors;
int *pnum;
@@ -3061,44 +2813,6 @@ int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top,
return 0;
}
/* Coroutine wrapper for bdrv_is_allocated_above() */
static void coroutine_fn bdrv_is_allocated_above_co_entry(void *opaque)
{
BdrvCoIsAllocatedData *data = opaque;
BlockDriverState *top = data->bs;
BlockDriverState *base = data->base;
data->ret = bdrv_co_is_allocated_above(top, base, data->sector_num,
data->nb_sectors, data->pnum);
data->done = true;
}
/*
* Synchronous wrapper around bdrv_co_is_allocated_above().
*
* See bdrv_co_is_allocated_above() for details.
*/
int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
int64_t sector_num, int nb_sectors, int *pnum)
{
Coroutine *co;
BdrvCoIsAllocatedData data = {
.bs = top,
.base = base,
.sector_num = sector_num,
.nb_sectors = nb_sectors,
.pnum = pnum,
.done = false,
};
co = qemu_coroutine_create(bdrv_is_allocated_above_co_entry);
qemu_coroutine_enter(co, &data);
while (!data.done) {
qemu_aio_wait();
}
return data.ret;
}
BlockInfo *bdrv_query_info(BlockDriverState *bs)
{
BlockInfo *info = g_malloc0(sizeof(*info));
@@ -3266,29 +2980,14 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
int64_t pos, int size)
{
QEMUIOVector qiov;
struct iovec iov = {
.iov_base = (void *) buf,
.iov_len = size,
};
qemu_iovec_init_external(&qiov, &iov, 1);
return bdrv_writev_vmstate(bs, &qiov, pos);
}
int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
{
BlockDriver *drv = bs->drv;
if (!drv) {
if (!drv)
return -ENOMEDIUM;
} else if (drv->bdrv_save_vmstate) {
return drv->bdrv_save_vmstate(bs, qiov, pos);
} else if (bs->file) {
return bdrv_writev_vmstate(bs->file, qiov, pos);
}
if (drv->bdrv_save_vmstate)
return drv->bdrv_save_vmstate(bs, buf, pos, size);
if (bs->file)
return bdrv_save_vmstate(bs->file, buf, pos, size);
return -ENOTSUP;
}
@@ -3426,7 +3125,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
if (bs->file) {
drv->bdrv_close(bs);
ret = bdrv_snapshot_goto(bs->file, snapshot_id);
open_ret = drv->bdrv_open(bs, NULL, bs->open_flags);
open_ret = drv->bdrv_open(bs, bs->open_flags);
if (open_ret < 0) {
bdrv_delete(bs->file);
bs->drv = NULL;
@@ -3845,7 +3544,6 @@ static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
bool is_write, double elapsed_time, uint64_t *wait)
{
uint64_t bps_limit = 0;
uint64_t extension;
double bytes_limit, bytes_base, bytes_res;
double slice_time, wait_time;
@@ -3864,9 +3562,9 @@ static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
slice_time = bs->slice_end - bs->slice_start;
slice_time /= (NANOSECONDS_PER_SECOND);
bytes_limit = bps_limit * slice_time;
bytes_base = bs->slice_submitted.bytes[is_write];
bytes_base = bs->nr_bytes[is_write] - bs->io_base.bytes[is_write];
if (bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL]) {
bytes_base += bs->slice_submitted.bytes[!is_write];
bytes_base += bs->nr_bytes[!is_write] - bs->io_base.bytes[!is_write];
}
/* bytes_base: the bytes of data which have been read/written; and
@@ -3893,12 +3591,10 @@ static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
* info can be kept until the timer fire, so it is increased and tuned
* based on the result of experiment.
*/
extension = wait_time * NANOSECONDS_PER_SECOND;
extension = DIV_ROUND_UP(extension, BLOCK_IO_SLICE_TIME) *
BLOCK_IO_SLICE_TIME;
bs->slice_end += extension;
bs->slice_time = wait_time * BLOCK_IO_SLICE_TIME * 10;
bs->slice_end += bs->slice_time - 3 * BLOCK_IO_SLICE_TIME;
if (wait) {
*wait = wait_time * NANOSECONDS_PER_SECOND;
*wait = wait_time * BLOCK_IO_SLICE_TIME * 10;
}
return true;
@@ -3926,9 +3622,9 @@ static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
slice_time = bs->slice_end - bs->slice_start;
slice_time /= (NANOSECONDS_PER_SECOND);
ios_limit = iops_limit * slice_time;
ios_base = bs->slice_submitted.ios[is_write];
ios_base = bs->nr_ops[is_write] - bs->io_base.ios[is_write];
if (bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL]) {
ios_base += bs->slice_submitted.ios[!is_write];
ios_base += bs->nr_ops[!is_write] - bs->io_base.ios[!is_write];
}
if (ios_base + 1 <= ios_limit) {
@@ -3939,7 +3635,7 @@ static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
return false;
}
/* Calc approx time to dispatch, in seconds */
/* Calc approx time to dispatch */
wait_time = (ios_base + 1) / iops_limit;
if (wait_time > elapsed_time) {
wait_time = wait_time - elapsed_time;
@@ -3947,10 +3643,10 @@ static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
wait_time = 0;
}
/* Exceeded current slice, extend it by another slice time */
bs->slice_end += BLOCK_IO_SLICE_TIME;
bs->slice_time = wait_time * BLOCK_IO_SLICE_TIME * 10;
bs->slice_end += bs->slice_time - 3 * BLOCK_IO_SLICE_TIME;
if (wait) {
*wait = wait_time * NANOSECONDS_PER_SECOND;
*wait = wait_time * BLOCK_IO_SLICE_TIME * 10;
}
return true;
@@ -3965,10 +3661,19 @@ static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors,
int bps_ret, iops_ret;
now = qemu_get_clock_ns(vm_clock);
if (now > bs->slice_end) {
if ((bs->slice_start < now)
&& (bs->slice_end > now)) {
bs->slice_end = now + bs->slice_time;
} else {
bs->slice_time = 5 * BLOCK_IO_SLICE_TIME;
bs->slice_start = now;
bs->slice_end = now + BLOCK_IO_SLICE_TIME;
memset(&bs->slice_submitted, 0, sizeof(bs->slice_submitted));
bs->slice_end = now + bs->slice_time;
bs->io_base.bytes[is_write] = bs->nr_bytes[is_write];
bs->io_base.bytes[!is_write] = bs->nr_bytes[!is_write];
bs->io_base.ios[is_write] = bs->nr_ops[is_write];
bs->io_base.ios[!is_write] = bs->nr_ops[!is_write];
}
elapsed_time = now - bs->slice_start;
@@ -3996,10 +3701,6 @@ static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors,
*wait = 0;
}
bs->slice_submitted.bytes[is_write] += (int64_t)nb_sectors *
BDRV_SECTOR_SIZE;
bs->slice_submitted.ios[is_write]++;
return false;
}
@@ -4447,11 +4148,6 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
bdrv_reset_dirty(bs, sector_num, nb_sectors);
}
/* Do nothing if disabled. */
if (!(bs->open_flags & BDRV_O_UNMAP)) {
return 0;
}
if (bs->drv->bdrv_co_discard) {
return bs->drv->bdrv_co_discard(bs, sector_num, nb_sectors);
} else if (bs->drv->bdrv_aio_discard) {
@@ -4735,8 +4431,7 @@ bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie)
void bdrv_img_create(const char *filename, const char *fmt,
const char *base_filename, const char *base_fmt,
char *options, uint64_t img_size, int flags,
Error **errp, bool quiet)
char *options, uint64_t img_size, int flags, Error **errp)
{
QEMUOptionParameter *param = NULL, *create_options = NULL;
QEMUOptionParameter *backing_fmt, *backing_file, *size;
@@ -4828,8 +4523,7 @@ void bdrv_img_create(const char *filename, const char *fmt,
bs = bdrv_new("");
ret = bdrv_open(bs, backing_file->value.s, NULL, back_flags,
backing_drv);
ret = bdrv_open(bs, backing_file->value.s, back_flags, backing_drv);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not open '%s'",
backing_file->value.s);
@@ -4846,23 +4540,18 @@ void bdrv_img_create(const char *filename, const char *fmt,
}
}
if (!quiet) {
printf("Formatting '%s', fmt=%s ", filename, fmt);
print_option_parameters(param);
puts("");
}
ret = bdrv_create(drv, filename, param);
if (ret < 0) {
if (ret == -ENOTSUP) {
error_setg(errp,"Formatting or formatting option not supported for "
"file format '%s'", fmt);
} else if (ret == -EFBIG) {
const char *cluster_size_hint = "";
if (get_option_parameter(create_options, BLOCK_OPT_CLUSTER_SIZE)) {
cluster_size_hint = " (try using a larger cluster size)";
}
error_setg(errp, "The image size is too large for file format '%s'%s",
fmt, cluster_size_hint);
error_setg(errp, "The image size is too large for file format '%s'",
fmt);
} else {
error_setg(errp, "%s: error while creating %s: %s", filename, fmt,
strerror(-ret));
@@ -4877,9 +4566,3 @@ out:
bdrv_delete(bs);
}
}
AioContext *bdrv_get_aio_context(BlockDriverState *bs)
{
/* Currently BlockDriverState always uses the main loop AioContext */
return qemu_get_aio_context();
}

View File

@@ -2,7 +2,6 @@ block-obj-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
block-obj-y += qed-check.o
block-obj-y += vhdx.o
block-obj-y += parallels.o blkdebug.o blkverify.o
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
block-obj-$(CONFIG_POSIX) += raw-posix.o
@@ -14,7 +13,6 @@ block-obj-$(CONFIG_LIBISCSI) += iscsi.o
block-obj-$(CONFIG_CURL) += curl.o
block-obj-$(CONFIG_RBD) += rbd.o
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
block-obj-$(CONFIG_LIBSSH2) += ssh.o
endif
common-obj-y += stream.o

View File

@@ -273,6 +273,11 @@ static int read_config(BDRVBlkdebugState *s, const char *filename)
int ret;
struct add_rule_data d;
/* Allow usage without config file */
if (!*filename) {
return 0;
}
f = fopen(filename, "r");
if (f == NULL) {
return -errno;
@@ -299,98 +304,43 @@ fail:
}
/* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
static void blkdebug_parse_filename(const char *filename, QDict *options,
Error **errp)
{
const char *c;
/* Parse the blkdebug: prefix */
if (!strstart(filename, "blkdebug:", &filename)) {
error_setg(errp, "File name string must start with 'blkdebug:'");
return;
}
/* Parse config file path */
c = strchr(filename, ':');
if (c == NULL) {
error_setg(errp, "blkdebug requires both config file and image path");
return;
}
if (c != filename) {
QString *config_path;
config_path = qstring_from_substr(filename, 0, c - filename - 1);
qdict_put(options, "config", config_path);
}
/* TODO Allow multi-level nesting and set file.filename here */
filename = c + 1;
qdict_put(options, "x-image", qstring_from_str(filename));
}
static QemuOptsList runtime_opts = {
.name = "blkdebug",
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
.desc = {
{
.name = "config",
.type = QEMU_OPT_STRING,
.help = "Path to the configuration file",
},
{
.name = "x-image",
.type = QEMU_OPT_STRING,
.help = "[internal use only, will be removed]",
},
{ /* end of list */ }
},
};
static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags)
static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVBlkdebugState *s = bs->opaque;
QemuOpts *opts;
Error *local_err = NULL;
const char *filename, *config;
int ret;
char *config, *c;
opts = qemu_opts_create_nofail(&runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
ret = -EINVAL;
goto fail;
/* Parse the blkdebug: prefix */
if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) {
return -EINVAL;
}
filename += strlen("blkdebug:");
/* Read rules from config file */
config = qemu_opt_get(opts, "config");
if (config) {
c = strchr(filename, ':');
if (c == NULL) {
return -EINVAL;
}
config = g_strdup(filename);
config[c - filename] = '\0';
ret = read_config(s, config);
g_free(config);
if (ret < 0) {
goto fail;
}
return ret;
}
filename = c + 1;
/* Set initial state */
s->state = 1;
/* Open the backing file */
filename = qemu_opt_get(opts, "x-image");
if (filename == NULL) {
ret = -EINVAL;
goto fail;
}
ret = bdrv_file_open(&bs->file, filename, NULL, flags);
ret = bdrv_file_open(&bs->file, filename, flags);
if (ret < 0) {
goto fail;
return ret;
}
ret = 0;
fail:
qemu_opts_del(opts);
return ret;
return 0;
}
static void error_callback_bh(void *opaque)
@@ -620,9 +570,9 @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
static BlockDriver bdrv_blkdebug = {
.format_name = "blkdebug",
.protocol_name = "blkdebug",
.instance_size = sizeof(BDRVBlkdebugState),
.bdrv_parse_filename = blkdebug_parse_filename,
.bdrv_file_open = blkdebug_open,
.bdrv_close = blkdebug_close,
.bdrv_getlength = blkdebug_getlength,

View File

@@ -69,100 +69,43 @@ static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb,
}
/* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */
static void blkverify_parse_filename(const char *filename, QDict *options,
Error **errp)
static int blkverify_open(BlockDriverState *bs, const char *filename, int flags)
{
const char *c;
QString *raw_path;
BDRVBlkverifyState *s = bs->opaque;
int ret;
char *raw, *c;
/* Parse the blkverify: prefix */
if (!strstart(filename, "blkverify:", &filename)) {
error_setg(errp, "File name string must start with 'blkverify:'");
return;
if (strncmp(filename, "blkverify:", strlen("blkverify:"))) {
return -EINVAL;
}
filename += strlen("blkverify:");
/* Parse the raw image filename */
c = strchr(filename, ':');
if (c == NULL) {
error_setg(errp, "blkverify requires raw copy and original image path");
return;
return -EINVAL;
}
/* TODO Implement option pass-through and set raw.filename here */
raw_path = qstring_from_substr(filename, 0, c - filename - 1);
qdict_put(options, "x-raw", raw_path);
/* TODO Allow multi-level nesting and set file.filename here */
filename = c + 1;
qdict_put(options, "x-image", qstring_from_str(filename));
}
static QemuOptsList runtime_opts = {
.name = "blkverify",
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
.desc = {
{
.name = "x-raw",
.type = QEMU_OPT_STRING,
.help = "[internal use only, will be removed]",
},
{
.name = "x-image",
.type = QEMU_OPT_STRING,
.help = "[internal use only, will be removed]",
},
{ /* end of list */ }
},
};
static int blkverify_open(BlockDriverState *bs, QDict *options, int flags)
{
BDRVBlkverifyState *s = bs->opaque;
QemuOpts *opts;
Error *local_err = NULL;
const char *filename, *raw;
int ret;
opts = qemu_opts_create_nofail(&runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
ret = -EINVAL;
goto fail;
}
/* Parse the raw image filename */
raw = qemu_opt_get(opts, "x-raw");
if (raw == NULL) {
ret = -EINVAL;
goto fail;
}
ret = bdrv_file_open(&bs->file, raw, NULL, flags);
raw = g_strdup(filename);
raw[c - filename] = '\0';
ret = bdrv_file_open(&bs->file, raw, flags);
g_free(raw);
if (ret < 0) {
goto fail;
return ret;
}
filename = c + 1;
/* Open the test file */
filename = qemu_opt_get(opts, "x-image");
if (filename == NULL) {
ret = -EINVAL;
goto fail;
}
s->test_file = bdrv_new("");
ret = bdrv_open(s->test_file, filename, NULL, flags, NULL);
ret = bdrv_open(s->test_file, filename, flags, NULL);
if (ret < 0) {
bdrv_delete(s->test_file);
s->test_file = NULL;
goto fail;
return ret;
}
ret = 0;
fail:
return ret;
return 0;
}
static void blkverify_close(BlockDriverState *bs)
@@ -402,12 +345,13 @@ static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs,
static BlockDriver bdrv_blkverify = {
.format_name = "blkverify",
.protocol_name = "blkverify",
.instance_size = sizeof(BDRVBlkverifyState),
.bdrv_parse_filename = blkverify_parse_filename,
.bdrv_getlength = blkverify_getlength,
.bdrv_file_open = blkverify_open,
.bdrv_close = blkverify_close,
.bdrv_getlength = blkverify_getlength,
.bdrv_aio_readv = blkverify_aio_readv,
.bdrv_aio_writev = blkverify_aio_writev,

View File

@@ -108,7 +108,7 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int bochs_open(BlockDriverState *bs, QDict *options, int flags)
static int bochs_open(BlockDriverState *bs, int flags)
{
BDRVBochsState *s = bs->opaque;
int i;

View File

@@ -53,7 +53,7 @@ static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int cloop_open(BlockDriverState *bs, QDict *options, int flags)
static int cloop_open(BlockDriverState *bs, int flags)
{
BDRVCloopState *s = bs->opaque;
uint32_t offsets_size, max_compressed_block_size = 1, i;

View File

@@ -58,7 +58,7 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int cow_open(BlockDriverState *bs, QDict *options, int flags)
static int cow_open(BlockDriverState *bs, int flags)
{
BDRVCowState *s = bs->opaque;
struct cow_header_v2 cow_header;
@@ -279,7 +279,7 @@ static int cow_create(const char *filename, QEMUOptionParameter *options)
return ret;
}
ret = bdrv_file_open(&cow_bs, filename, NULL, BDRV_O_RDWR);
ret = bdrv_file_open(&cow_bs, filename, BDRV_O_RDWR);
if (ret < 0) {
return ret;
}

View File

@@ -335,9 +335,11 @@ static void curl_clean_state(CURLState *s)
s->in_use = 0;
}
static void curl_parse_filename(const char *filename, QDict *options,
Error **errp)
static int curl_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVCURLState *s = bs->opaque;
CURLState *state = NULL;
double d;
#define RA_OPTSTR ":readahead="
char *file;
@@ -345,17 +347,19 @@ static void curl_parse_filename(const char *filename, QDict *options,
const char *ra_val;
int parse_state = 0;
static int inited = 0;
file = g_strdup(filename);
s->readahead_size = READ_AHEAD_SIZE;
/* Parse a trailing ":readahead=#:" param, if present. */
ra = file + strlen(file) - 1;
while (ra >= file) {
if (parse_state == 0) {
if (*ra == ':') {
if (*ra == ':')
parse_state++;
} else {
else
break;
}
} else if (parse_state == 1) {
if (*ra > '9' || *ra < '0') {
char *opt_start = ra - strlen(RA_OPTSTR) + 1;
@@ -364,77 +368,29 @@ static void curl_parse_filename(const char *filename, QDict *options,
ra_val = ra + 1;
ra -= strlen(RA_OPTSTR) - 1;
*ra = '\0';
qdict_put(options, "readahead", qstring_from_str(ra_val));
}
s->readahead_size = atoi(ra_val);
break;
} else {
break;
}
}
}
ra--;
}
qdict_put(options, "url", qstring_from_str(file));
g_free(file);
}
static QemuOptsList runtime_opts = {
.name = "curl",
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
.desc = {
{
.name = "url",
.type = QEMU_OPT_STRING,
.help = "URL to open",
},
{
.name = "readahead",
.type = QEMU_OPT_SIZE,
.help = "Readahead size",
},
{ /* end of list */ }
},
};
static int curl_open(BlockDriverState *bs, QDict *options, int flags)
{
BDRVCURLState *s = bs->opaque;
CURLState *state = NULL;
QemuOpts *opts;
Error *local_err = NULL;
const char *file;
double d;
static int inited = 0;
opts = qemu_opts_create_nofail(&runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
goto out_noclean;
}
s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE);
if ((s->readahead_size & 0x1ff) != 0) {
fprintf(stderr, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512\n",
s->readahead_size);
goto out_noclean;
}
file = qemu_opt_get(opts, "url");
if (file == NULL) {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "curl block driver requires "
"an 'url' option");
goto out_noclean;
}
if (!inited) {
curl_global_init(CURL_GLOBAL_ALL);
inited = 1;
}
DPRINTF("CURL: Opening %s\n", file);
s->url = g_strdup(file);
s->url = file;
state = curl_init_state(s);
if (!state)
goto out_noclean;
@@ -466,7 +422,6 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags)
curl_multi_setopt( s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb );
curl_multi_do(s);
qemu_opts_del(opts);
return 0;
out:
@@ -474,8 +429,7 @@ out:
curl_easy_cleanup(state->curl);
state->curl = NULL;
out_noclean:
g_free(s->url);
qemu_opts_del(opts);
g_free(file);
return -EINVAL;
}
@@ -617,7 +571,6 @@ static BlockDriver bdrv_http = {
.protocol_name = "http",
.instance_size = sizeof(BDRVCURLState),
.bdrv_parse_filename = curl_parse_filename,
.bdrv_file_open = curl_open,
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,
@@ -630,7 +583,6 @@ static BlockDriver bdrv_https = {
.protocol_name = "https",
.instance_size = sizeof(BDRVCURLState),
.bdrv_parse_filename = curl_parse_filename,
.bdrv_file_open = curl_open,
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,
@@ -643,7 +595,6 @@ static BlockDriver bdrv_ftp = {
.protocol_name = "ftp",
.instance_size = sizeof(BDRVCURLState),
.bdrv_parse_filename = curl_parse_filename,
.bdrv_file_open = curl_open,
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,
@@ -656,7 +607,6 @@ static BlockDriver bdrv_ftps = {
.protocol_name = "ftps",
.instance_size = sizeof(BDRVCURLState),
.bdrv_parse_filename = curl_parse_filename,
.bdrv_file_open = curl_open,
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,
@@ -669,7 +619,6 @@ static BlockDriver bdrv_tftp = {
.protocol_name = "tftp",
.instance_size = sizeof(BDRVCURLState),
.bdrv_parse_filename = curl_parse_filename,
.bdrv_file_open = curl_open,
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,

View File

@@ -51,16 +51,9 @@ typedef struct BDRVDMGState {
static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
{
int len;
if (!filename) {
return 0;
}
len = strlen(filename);
if (len > 4 && !strcmp(filename + len - 4, ".dmg")) {
int len=strlen(filename);
if(len>4 && !strcmp(filename+len-4,".dmg"))
return 2;
}
return 0;
}
@@ -92,7 +85,7 @@ static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
return 0;
}
static int dmg_open(BlockDriverState *bs, QDict *options, int flags)
static int dmg_open(BlockDriverState *bs, int flags)
{
BDRVDMGState *s = bs->opaque;
uint64_t info_begin,info_end,last_in_offset,last_out_offset;

View File

@@ -282,42 +282,13 @@ static int qemu_gluster_aio_flush_cb(void *opaque)
return (s->qemu_aio_count > 0);
}
/* TODO Convert to fine grained options */
static QemuOptsList runtime_opts = {
.name = "gluster",
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
.desc = {
{
.name = "filename",
.type = QEMU_OPT_STRING,
.help = "URL to the gluster image",
},
{ /* end of list */ }
},
};
static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
static int qemu_gluster_open(BlockDriverState *bs, const char *filename,
int bdrv_flags)
{
BDRVGlusterState *s = bs->opaque;
int open_flags = O_BINARY;
int ret = 0;
GlusterConf *gconf = g_malloc0(sizeof(GlusterConf));
QemuOpts *opts;
Error *local_err = NULL;
const char *filename;
opts = qemu_opts_create_nofail(&runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
ret = -EINVAL;
goto out;
}
filename = qemu_opt_get(opts, "filename");
s->glfs = qemu_gluster_init(gconf, filename);
if (!s->glfs) {
@@ -351,7 +322,6 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
qemu_gluster_aio_event_reader, NULL, qemu_gluster_aio_flush_cb, s);
out:
qemu_opts_del(opts);
qemu_gluster_gconf_free(gconf);
if (!ret) {
return ret;

View File

@@ -31,14 +31,14 @@
#include "qemu/error-report.h"
#include "block/block_int.h"
#include "trace.h"
#include "block/scsi.h"
#include "hw/scsi-defs.h"
#include <iscsi/iscsi.h>
#include <iscsi/scsi-lowlevel.h>
#ifdef __linux__
#include <scsi/sg.h>
#include <block/scsi.h>
#include <hw/scsi-defs.h>
#endif
typedef struct IscsiLun {
@@ -60,11 +60,8 @@ typedef struct IscsiAIOCB {
uint8_t *buf;
int status;
int canceled;
int retries;
size_t read_size;
size_t read_offset;
int64_t sector_num;
int nb_sectors;
#ifdef __linux__
sg_io_hdr_t *ioh;
#endif
@@ -72,7 +69,6 @@ typedef struct IscsiAIOCB {
#define NOP_INTERVAL 5000
#define MAX_NOP_FAILURES 3
#define ISCSI_CMD_RETRIES 5
static void
iscsi_bh_cb(void *p)
@@ -195,8 +191,6 @@ iscsi_process_write(void *arg)
iscsi_set_events(iscsilun);
}
static int
iscsi_aio_writev_acb(IscsiAIOCB *acb);
static void
iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
@@ -214,17 +208,7 @@ iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
}
acb->status = 0;
if (status != 0) {
if (status == SCSI_STATUS_CHECK_CONDITION
&& acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
&& acb->retries-- > 0) {
scsi_free_scsi_task(acb->task);
acb->task = NULL;
if (iscsi_aio_writev_acb(acb) == 0) {
iscsi_set_events(acb->iscsilun);
return;
}
}
if (status < 0) {
error_report("Failed to write16 data to iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
@@ -238,10 +222,15 @@ static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
}
static int
iscsi_aio_writev_acb(IscsiAIOCB *acb)
static BlockDriverAIOCB *
iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
{
struct iscsi_context *iscsi = acb->iscsilun->iscsi;
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
IscsiAIOCB *acb;
size_t size;
uint32_t num_sectors;
uint64_t lba;
@@ -250,13 +239,19 @@ iscsi_aio_writev_acb(IscsiAIOCB *acb)
#endif
int ret;
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
acb->iscsilun = iscsilun;
acb->qiov = qiov;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
/* this will allow us to get rid of 'buf' completely */
size = acb->nb_sectors * BDRV_SECTOR_SIZE;
size = nb_sectors * BDRV_SECTOR_SIZE;
#if !defined(LIBISCSI_FEATURE_IOVECTOR)
data.size = MIN(size, acb->qiov->size);
@@ -275,27 +270,28 @@ iscsi_aio_writev_acb(IscsiAIOCB *acb)
if (acb->task == NULL) {
error_report("iSCSI: Failed to allocate task for scsi WRITE16 "
"command. %s", iscsi_get_error(iscsi));
return -1;
qemu_aio_release(acb);
return NULL;
}
memset(acb->task, 0, sizeof(struct scsi_task));
acb->task->xfer_dir = SCSI_XFER_WRITE;
acb->task->cdb_size = 16;
acb->task->cdb[0] = 0x8a;
lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
lba = sector_qemu2lun(sector_num, iscsilun);
*(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32);
*(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff);
num_sectors = size / acb->iscsilun->block_size;
num_sectors = size / iscsilun->block_size;
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
acb->task->expxferlen = size;
#if defined(LIBISCSI_FEATURE_IOVECTOR)
ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task,
ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
iscsi_aio_write16_cb,
NULL,
acb);
#else
ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task,
ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
iscsi_aio_write16_cb,
&data,
acb);
@@ -303,46 +299,19 @@ iscsi_aio_writev_acb(IscsiAIOCB *acb)
if (ret != 0) {
scsi_free_scsi_task(acb->task);
g_free(acb->buf);
return -1;
qemu_aio_release(acb);
return NULL;
}
#if defined(LIBISCSI_FEATURE_IOVECTOR)
scsi_task_set_iov_out(acb->task, (struct scsi_iovec*) acb->qiov->iov, acb->qiov->niov);
#endif
return 0;
}
static BlockDriverAIOCB *
iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
{
IscsiLun *iscsilun = bs->opaque;
IscsiAIOCB *acb;
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
trace_iscsi_aio_writev(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
acb->iscsilun = iscsilun;
acb->qiov = qiov;
acb->nb_sectors = nb_sectors;
acb->sector_num = sector_num;
acb->retries = ISCSI_CMD_RETRIES;
if (iscsi_aio_writev_acb(acb) != 0) {
qemu_aio_release(acb);
return NULL;
}
iscsi_set_events(iscsilun);
return &acb->common;
}
static int
iscsi_aio_readv_acb(IscsiAIOCB *acb);
static void
iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *opaque)
@@ -357,16 +326,6 @@ iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
acb->status = 0;
if (status != 0) {
if (status == SCSI_STATUS_CHECK_CONDITION
&& acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
&& acb->retries-- > 0) {
scsi_free_scsi_task(acb->task);
acb->task = NULL;
if (iscsi_aio_readv_acb(acb) == 0) {
iscsi_set_events(acb->iscsilun);
return;
}
}
error_report("Failed to read16 data from iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
@@ -375,20 +334,35 @@ iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
iscsi_schedule_bh(acb);
}
static int
iscsi_aio_readv_acb(IscsiAIOCB *acb)
static BlockDriverAIOCB *
iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
{
struct iscsi_context *iscsi = acb->iscsilun->iscsi;
uint64_t lba;
uint32_t num_sectors;
int ret;
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
IscsiAIOCB *acb;
size_t qemu_read_size;
#if !defined(LIBISCSI_FEATURE_IOVECTOR)
int i;
#endif
int ret;
uint64_t lba;
uint32_t num_sectors;
qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb);
acb->iscsilun = iscsilun;
acb->qiov = qiov;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->read_size = qemu_read_size;
acb->buf = NULL;
/* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU
@@ -396,29 +370,30 @@ iscsi_aio_readv_acb(IscsiAIOCB *acb)
* data.
*/
acb->read_offset = 0;
if (acb->iscsilun->block_size > BDRV_SECTOR_SIZE) {
uint64_t bdrv_offset = BDRV_SECTOR_SIZE * acb->sector_num;
if (iscsilun->block_size > BDRV_SECTOR_SIZE) {
uint64_t bdrv_offset = BDRV_SECTOR_SIZE * sector_num;
acb->read_offset = bdrv_offset % acb->iscsilun->block_size;
acb->read_offset = bdrv_offset % iscsilun->block_size;
}
num_sectors = (acb->read_size + acb->iscsilun->block_size
num_sectors = (qemu_read_size + iscsilun->block_size
+ acb->read_offset - 1)
/ acb->iscsilun->block_size;
/ iscsilun->block_size;
acb->task = malloc(sizeof(struct scsi_task));
if (acb->task == NULL) {
error_report("iSCSI: Failed to allocate task for scsi READ16 "
"command. %s", iscsi_get_error(iscsi));
return -1;
qemu_aio_release(acb);
return NULL;
}
memset(acb->task, 0, sizeof(struct scsi_task));
acb->task->xfer_dir = SCSI_XFER_READ;
lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
acb->task->expxferlen = acb->read_size;
lba = sector_qemu2lun(sector_num, iscsilun);
acb->task->expxferlen = qemu_read_size;
switch (acb->iscsilun->type) {
switch (iscsilun->type) {
case TYPE_DISK:
acb->task->cdb_size = 16;
acb->task->cdb[0] = 0x88;
@@ -434,13 +409,14 @@ iscsi_aio_readv_acb(IscsiAIOCB *acb)
break;
}
ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task,
ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
iscsi_aio_read16_cb,
NULL,
acb);
if (ret != 0) {
scsi_free_scsi_task(acb->task);
return -1;
qemu_aio_release(acb);
return NULL;
}
#if defined(LIBISCSI_FEATURE_IOVECTOR)
@@ -452,39 +428,12 @@ iscsi_aio_readv_acb(IscsiAIOCB *acb)
acb->qiov->iov[i].iov_base);
}
#endif
return 0;
}
static BlockDriverAIOCB *
iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
{
IscsiLun *iscsilun = bs->opaque;
IscsiAIOCB *acb;
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
trace_iscsi_aio_readv(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
acb->nb_sectors = nb_sectors;
acb->sector_num = sector_num;
acb->iscsilun = iscsilun;
acb->qiov = qiov;
acb->read_size = BDRV_SECTOR_SIZE * (size_t)acb->nb_sectors;
acb->retries = ISCSI_CMD_RETRIES;
if (iscsi_aio_readv_acb(acb) != 0) {
qemu_aio_release(acb);
return NULL;
}
iscsi_set_events(iscsilun);
return &acb->common;
}
static int
iscsi_aio_flush_acb(IscsiAIOCB *acb);
static void
iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
@@ -497,17 +446,7 @@ iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
}
acb->status = 0;
if (status != 0) {
if (status == SCSI_STATUS_CHECK_CONDITION
&& acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
&& acb->retries-- > 0) {
scsi_free_scsi_task(acb->task);
acb->task = NULL;
if (iscsi_aio_flush_acb(acb) == 0) {
iscsi_set_events(acb->iscsilun);
return;
}
}
if (status < 0) {
error_report("Failed to sync10 data on iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
@@ -516,43 +455,29 @@ iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
iscsi_schedule_bh(acb);
}
static int
iscsi_aio_flush_acb(IscsiAIOCB *acb)
static BlockDriverAIOCB *
iscsi_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
struct iscsi_context *iscsi = acb->iscsilun->iscsi;
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
IscsiAIOCB *acb;
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
acb->iscsilun = iscsilun;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
acb->task = iscsi_synchronizecache10_task(iscsi, acb->iscsilun->lun,
acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun,
0, 0, 0, 0,
iscsi_synccache10_cb,
acb);
if (acb->task == NULL) {
error_report("iSCSI: Failed to send synchronizecache10 command. %s",
iscsi_get_error(iscsi));
return -1;
}
return 0;
}
static BlockDriverAIOCB *
iscsi_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
IscsiLun *iscsilun = bs->opaque;
IscsiAIOCB *acb;
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
acb->iscsilun = iscsilun;
acb->retries = ISCSI_CMD_RETRIES;
if (iscsi_aio_flush_acb(acb) != 0) {
qemu_aio_release(acb);
return NULL;
}
@@ -562,8 +487,6 @@ iscsi_aio_flush(BlockDriverState *bs,
return &acb->common;
}
static int iscsi_aio_discard_acb(IscsiAIOCB *acb);
static void
iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *opaque)
@@ -575,17 +498,7 @@ iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
}
acb->status = 0;
if (status != 0) {
if (status == SCSI_STATUS_CHECK_CONDITION
&& acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
&& acb->retries-- > 0) {
scsi_free_scsi_task(acb->task);
acb->task = NULL;
if (iscsi_aio_discard_acb(acb) == 0) {
iscsi_set_events(acb->iscsilun);
return;
}
}
if (status < 0) {
error_report("Failed to unmap data on iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
@@ -594,47 +507,34 @@ iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
iscsi_schedule_bh(acb);
}
static int iscsi_aio_discard_acb(IscsiAIOCB *acb) {
struct iscsi_context *iscsi = acb->iscsilun->iscsi;
struct unmap_list list[1];
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
list[0].lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
list[0].num = acb->nb_sectors * BDRV_SECTOR_SIZE / acb->iscsilun->block_size;
acb->task = iscsi_unmap_task(iscsi, acb->iscsilun->lun,
0, 0, &list[0], 1,
iscsi_unmap_cb,
acb);
if (acb->task == NULL) {
error_report("iSCSI: Failed to send unmap command. %s",
iscsi_get_error(iscsi));
return -1;
}
return 0;
}
static BlockDriverAIOCB *
iscsi_aio_discard(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
IscsiAIOCB *acb;
struct unmap_list list[1];
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
acb->iscsilun = iscsilun;
acb->nb_sectors = nb_sectors;
acb->sector_num = sector_num;
acb->retries = ISCSI_CMD_RETRIES;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
if (iscsi_aio_discard_acb(acb) != 0) {
list[0].lba = sector_qemu2lun(sector_num, iscsilun);
list[0].num = nb_sectors * BDRV_SECTOR_SIZE / iscsilun->block_size;
acb->task = iscsi_unmap_task(iscsi, iscsilun->lun,
0, 0, &list[0], 1,
iscsi_unmap_cb,
acb);
if (acb->task == NULL) {
error_report("iSCSI: Failed to send unmap command. %s",
iscsi_get_error(iscsi));
qemu_aio_release(acb);
return NULL;
}
@@ -923,98 +823,20 @@ static void iscsi_nop_timed_event(void *opaque)
}
#endif
static int iscsi_readcapacity_sync(IscsiLun *iscsilun)
{
struct scsi_task *task = NULL;
struct scsi_readcapacity10 *rc10 = NULL;
struct scsi_readcapacity16 *rc16 = NULL;
int ret = 0;
int retries = ISCSI_CMD_RETRIES;
do {
if (task != NULL) {
scsi_free_scsi_task(task);
task = NULL;
}
switch (iscsilun->type) {
case TYPE_DISK:
task = iscsi_readcapacity16_sync(iscsilun->iscsi, iscsilun->lun);
if (task != NULL && task->status == SCSI_STATUS_GOOD) {
rc16 = scsi_datain_unmarshall(task);
if (rc16 == NULL) {
error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
ret = -EINVAL;
} else {
iscsilun->block_size = rc16->block_length;
iscsilun->num_blocks = rc16->returned_lba + 1;
}
}
break;
case TYPE_ROM:
task = iscsi_readcapacity10_sync(iscsilun->iscsi, iscsilun->lun, 0, 0);
if (task != NULL && task->status == SCSI_STATUS_GOOD) {
rc10 = scsi_datain_unmarshall(task);
if (rc10 == NULL) {
error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
ret = -EINVAL;
} else {
iscsilun->block_size = rc10->block_size;
if (rc10->lba == 0) {
/* blank disk loaded */
iscsilun->num_blocks = 0;
} else {
iscsilun->num_blocks = rc10->lba + 1;
}
}
}
break;
default:
return 0;
}
} while (task != NULL && task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_UNIT_ATTENTION
&& retries-- > 0);
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
error_report("iSCSI: failed to send readcapacity10 command.");
ret = -EINVAL;
}
if (task) {
scsi_free_scsi_task(task);
}
return ret;
}
/* TODO Convert to fine grained options */
static QemuOptsList runtime_opts = {
.name = "iscsi",
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
.desc = {
{
.name = "filename",
.type = QEMU_OPT_STRING,
.help = "URL to the iscsi image",
},
{ /* end of list */ }
},
};
/*
* We support iscsi url's on the form
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
*/
static int iscsi_open(BlockDriverState *bs, QDict *options, int flags)
static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
{
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = NULL;
struct iscsi_url *iscsi_url = NULL;
struct scsi_task *task = NULL;
struct scsi_inquiry_standard *inq = NULL;
struct scsi_readcapacity10 *rc10 = NULL;
struct scsi_readcapacity16 *rc16 = NULL;
char *initiator_name = NULL;
QemuOpts *opts;
Error *local_err = NULL;
const char *filename;
int ret;
if ((BDRV_SECTOR_SIZE % 512) != 0) {
@@ -1024,18 +846,6 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags)
return -EINVAL;
}
opts = qemu_opts_create_nofail(&runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
ret = -EINVAL;
goto out;
}
filename = qemu_opt_get(opts, "filename");
iscsi_url = iscsi_parse_full_url(iscsi, filename);
if (iscsi_url == NULL) {
error_report("Failed to parse URL : %s", filename);
@@ -1115,9 +925,50 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags)
iscsilun->type = inq->periperal_device_type;
if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
scsi_free_scsi_task(task);
switch (iscsilun->type) {
case TYPE_DISK:
task = iscsi_readcapacity16_sync(iscsi, iscsilun->lun);
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
error_report("iSCSI: failed to send readcapacity16 command.");
ret = -EINVAL;
goto out;
}
rc16 = scsi_datain_unmarshall(task);
if (rc16 == NULL) {
error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
ret = -EINVAL;
goto out;
}
iscsilun->block_size = rc16->block_length;
iscsilun->num_blocks = rc16->returned_lba + 1;
break;
case TYPE_ROM:
task = iscsi_readcapacity10_sync(iscsi, iscsilun->lun, 0, 0);
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
error_report("iSCSI: failed to send readcapacity10 command.");
ret = -EINVAL;
goto out;
}
rc10 = scsi_datain_unmarshall(task);
if (rc10 == NULL) {
error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
ret = -EINVAL;
goto out;
}
iscsilun->block_size = rc10->block_size;
if (rc10->lba == 0) {
/* blank disk loaded */
iscsilun->num_blocks = 0;
} else {
iscsilun->num_blocks = rc10->lba + 1;
}
break;
default:
break;
}
bs->total_sectors = iscsilun->num_blocks *
iscsilun->block_size / BDRV_SECTOR_SIZE ;
@@ -1130,6 +981,8 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags)
bs->sg = 1;
}
ret = 0;
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
/* Set up a timer for sending out iSCSI NOPs */
iscsilun->nop_timer = qemu_new_timer_ms(rt_clock, iscsi_nop_timed_event, iscsilun);
@@ -1137,7 +990,6 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags)
#endif
out:
qemu_opts_del(opts);
if (initiator_name != NULL) {
g_free(initiator_name);
}
@@ -1171,26 +1023,6 @@ static void iscsi_close(BlockDriverState *bs)
memset(iscsilun, 0, sizeof(IscsiLun));
}
static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
{
IscsiLun *iscsilun = bs->opaque;
int ret = 0;
if (iscsilun->type != TYPE_DISK) {
return -ENOTSUP;
}
if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
return ret;
}
if (offset > iscsi_getlength(bs)) {
return -EINVAL;
}
return 0;
}
static int iscsi_has_zero_init(BlockDriverState *bs)
{
return 0;
@@ -1202,7 +1034,6 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options)
int64_t total_size = 0;
BlockDriverState bs;
IscsiLun *iscsilun = NULL;
QDict *bs_options;
memset(&bs, 0, sizeof(BlockDriverState));
@@ -1217,11 +1048,7 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options)
bs.opaque = g_malloc0(sizeof(struct IscsiLun));
iscsilun = bs.opaque;
bs_options = qdict_new();
qdict_put(bs_options, "filename", qstring_from_str(filename));
ret = iscsi_open(&bs, bs_options, 0);
QDECREF(bs_options);
ret = iscsi_open(&bs, filename, 0);
if (ret != 0) {
goto out;
}
@@ -1266,7 +1093,6 @@ static BlockDriver bdrv_iscsi = {
.create_options = iscsi_create_options,
.bdrv_getlength = iscsi_getlength,
.bdrv_truncate = iscsi_truncate,
.bdrv_aio_readv = iscsi_aio_readv,
.bdrv_aio_writev = iscsi_aio_writev,

View File

@@ -507,7 +507,7 @@ static void mirror_complete(BlockJob *job, Error **errp)
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
int ret;
ret = bdrv_open_backing_file(s->target, NULL);
ret = bdrv_open_backing_file(s->target);
if (ret < 0) {
char backing_filename[PATH_MAX];
bdrv_get_full_backing_filename(s->target, backing_filename,

View File

@@ -32,8 +32,6 @@
#include "block/block_int.h"
#include "qemu/module.h"
#include "qemu/sockets.h"
#include "qapi/qmp/qjson.h"
#include "qapi/qmp/qint.h"
#include <sys/types.h>
#include <unistd.h>
@@ -67,19 +65,17 @@ typedef struct BDRVNBDState {
Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
struct nbd_reply reply;
bool is_unix;
QemuOpts *socket_opts;
int is_unix;
char *host_spec;
char *export_name; /* An NBD server may export several devices */
} BDRVNBDState;
static int nbd_parse_uri(const char *filename, QDict *options)
static int nbd_parse_uri(BDRVNBDState *s, const char *filename)
{
URI *uri;
const char *p;
QueryParams *qp = NULL;
int ret = 0;
bool is_unix;
uri = uri_parse(filename);
if (!uri) {
@@ -88,11 +84,11 @@ static int nbd_parse_uri(const char *filename, QDict *options)
/* transport */
if (!strcmp(uri->scheme, "nbd")) {
is_unix = false;
s->is_unix = false;
} else if (!strcmp(uri->scheme, "nbd+tcp")) {
is_unix = false;
s->is_unix = false;
} else if (!strcmp(uri->scheme, "nbd+unix")) {
is_unix = true;
s->is_unix = true;
} else {
ret = -EINVAL;
goto out;
@@ -101,44 +97,32 @@ static int nbd_parse_uri(const char *filename, QDict *options)
p = uri->path ? uri->path : "/";
p += strspn(p, "/");
if (p[0]) {
qdict_put(options, "export", qstring_from_str(p));
s->export_name = g_strdup(p);
}
qp = query_params_parse(uri->query);
if (qp->n > 1 || (is_unix && !qp->n) || (!is_unix && qp->n)) {
if (qp->n > 1 || (s->is_unix && !qp->n) || (!s->is_unix && qp->n)) {
ret = -EINVAL;
goto out;
}
if (is_unix) {
if (s->is_unix) {
/* nbd+unix:///export?socket=path */
if (uri->server || uri->port || strcmp(qp->p[0].name, "socket")) {
ret = -EINVAL;
goto out;
}
qdict_put(options, "path", qstring_from_str(qp->p[0].value));
s->host_spec = g_strdup(qp->p[0].value);
} else {
QString *host;
/* nbd[+tcp]://host[:port]/export */
/* nbd[+tcp]://host:port/export */
if (!uri->server) {
ret = -EINVAL;
goto out;
}
/* strip braces from literal IPv6 address */
if (uri->server[0] == '[') {
host = qstring_from_substr(uri->server, 1,
strlen(uri->server) - 2);
} else {
host = qstring_from_str(uri->server);
}
qdict_put(options, "host", host);
if (uri->port) {
char* port_str = g_strdup_printf("%d", uri->port);
qdict_put(options, "port", qstring_from_str(port_str));
g_free(port_str);
if (!uri->port) {
uri->port = NBD_DEFAULT_PORT;
}
s->host_spec = g_strdup_printf("%s:%d", uri->server, uri->port);
}
out:
@@ -149,29 +133,16 @@ out:
return ret;
}
static void nbd_parse_filename(const char *filename, QDict *options,
Error **errp)
static int nbd_config(BDRVNBDState *s, const char *filename)
{
char *file;
char *export_name;
const char *host_spec;
const char *unixpath;
if (qdict_haskey(options, "host")
|| qdict_haskey(options, "port")
|| qdict_haskey(options, "path"))
{
error_setg(errp, "host/port/path and a file name may not be specified "
"at the same time");
return;
}
int err = -EINVAL;
if (strstr(filename, "://")) {
int ret = nbd_parse_uri(filename, options);
if (ret < 0) {
error_setg(errp, "No valid URL specified");
}
return;
return nbd_parse_uri(s, filename);
}
file = g_strdup(filename);
@@ -183,79 +154,34 @@ static void nbd_parse_filename(const char *filename, QDict *options,
}
export_name[0] = 0; /* truncate 'file' */
export_name += strlen(EN_OPTSTR);
qdict_put(options, "export", qstring_from_str(export_name));
s->export_name = g_strdup(export_name);
}
/* extract the host_spec - fail if it's not nbd:... */
if (!strstart(file, "nbd:", &host_spec)) {
error_setg(errp, "File name string for NBD must start with 'nbd:'");
goto out;
}
if (!*host_spec) {
goto out;
}
/* are we a UNIX or TCP socket? */
if (strstart(host_spec, "unix:", &unixpath)) {
qdict_put(options, "path", qstring_from_str(unixpath));
s->is_unix = true;
s->host_spec = g_strdup(unixpath);
} else {
InetSocketAddress *addr = NULL;
addr = inet_parse(host_spec, errp);
if (error_is_set(errp)) {
goto out;
s->is_unix = false;
s->host_spec = g_strdup(host_spec);
}
qdict_put(options, "host", qstring_from_str(addr->host));
qdict_put(options, "port", qstring_from_str(addr->port));
qapi_free_InetSocketAddress(addr);
}
err = 0;
out:
g_free(file);
if (err != 0) {
g_free(s->export_name);
g_free(s->host_spec);
}
return err;
}
static int nbd_config(BDRVNBDState *s, QDict *options)
{
Error *local_err = NULL;
if (qdict_haskey(options, "path")) {
if (qdict_haskey(options, "host")) {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "path and host may not "
"be used at the same time.");
return -EINVAL;
}
s->is_unix = true;
} else if (qdict_haskey(options, "host")) {
s->is_unix = false;
} else {
return -EINVAL;
}
s->socket_opts = qemu_opts_create_nofail(&socket_optslist);
qemu_opts_absorb_qdict(s->socket_opts, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
return -EINVAL;
}
if (!qemu_opt_get(s->socket_opts, "port")) {
qemu_opt_set_number(s->socket_opts, "port", NBD_DEFAULT_PORT);
}
s->export_name = g_strdup(qdict_get_try_str(options, "export"));
if (s->export_name) {
qdict_del(options, "export");
}
return 0;
}
static void nbd_coroutine_start(BDRVNBDState *s, struct nbd_request *request)
{
int i;
@@ -343,24 +269,14 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
s->send_coroutine = qemu_coroutine_self();
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write,
nbd_have_request, s);
if (qiov) {
if (!s->is_unix) {
socket_set_cork(s->sock, 1);
}
rc = nbd_send_request(s->sock, request);
if (rc >= 0) {
if (rc >= 0 && qiov) {
ret = qemu_co_sendv(s->sock, qiov->iov, qiov->niov,
offset, request->len);
if (ret != request->len) {
rc = -EIO;
return -EIO;
}
}
if (!s->is_unix) {
socket_set_cork(s->sock, 0);
}
} else {
rc = nbd_send_request(s->sock, request);
}
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
nbd_have_request, s);
s->send_coroutine = NULL;
@@ -412,12 +328,9 @@ static int nbd_establish_connection(BlockDriverState *bs)
size_t blocksize;
if (s->is_unix) {
sock = unix_socket_outgoing(qemu_opt_get(s->socket_opts, "path"));
sock = unix_socket_outgoing(s->host_spec);
} else {
sock = tcp_socket_outgoing_opts(s->socket_opts);
if (sock >= 0) {
socket_set_nodelay(sock);
}
sock = tcp_socket_outgoing_spec(s->host_spec);
}
/* Failed to establish connection */
@@ -463,7 +376,7 @@ static void nbd_teardown_connection(BlockDriverState *bs)
closesocket(s->sock);
}
static int nbd_open(BlockDriverState *bs, QDict *options, int flags)
static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
{
BDRVNBDState *s = bs->opaque;
int result;
@@ -472,7 +385,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags)
qemu_co_mutex_init(&s->free_sema);
/* Pop the config into our state object. Exit if invalid. */
result = nbd_config(s, options);
result = nbd_config(s, filename);
if (result != 0) {
return result;
}
@@ -618,7 +531,7 @@ static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
return 0;
}
request.type = NBD_CMD_TRIM;
request.from = sector_num * 512;
request.from = sector_num * 512;;
request.len = nb_sectors * 512;
nbd_coroutine_start(s, &request);
@@ -636,7 +549,7 @@ static void nbd_close(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
g_free(s->export_name);
qemu_opts_del(s->socket_opts);
g_free(s->host_spec);
nbd_teardown_connection(bs);
}
@@ -652,7 +565,6 @@ static BlockDriver bdrv_nbd = {
.format_name = "nbd",
.protocol_name = "nbd",
.instance_size = sizeof(BDRVNBDState),
.bdrv_parse_filename = nbd_parse_filename,
.bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv,
.bdrv_co_writev = nbd_co_writev,
@@ -666,7 +578,6 @@ static BlockDriver bdrv_nbd_tcp = {
.format_name = "nbd",
.protocol_name = "nbd+tcp",
.instance_size = sizeof(BDRVNBDState),
.bdrv_parse_filename = nbd_parse_filename,
.bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv,
.bdrv_co_writev = nbd_co_writev,
@@ -680,7 +591,6 @@ static BlockDriver bdrv_nbd_unix = {
.format_name = "nbd",
.protocol_name = "nbd+unix",
.instance_size = sizeof(BDRVNBDState),
.bdrv_parse_filename = nbd_parse_filename,
.bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv,
.bdrv_co_writev = nbd_co_writev,

View File

@@ -68,7 +68,7 @@ static int parallels_probe(const uint8_t *buf, int buf_size, const char *filenam
return 0;
}
static int parallels_open(BlockDriverState *bs, QDict *options, int flags)
static int parallels_open(BlockDriverState *bs, int flags)
{
BDRVParallelsState *s = bs->opaque;
int i;

View File

@@ -25,7 +25,7 @@
#include "block/block_int.h"
#include "qemu/module.h"
#include <zlib.h>
#include "qemu/aes.h"
#include "block/aes.h"
#include "migration/migration.h"
/**************************************************************/
@@ -92,7 +92,7 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int qcow_open(BlockDriverState *bs, QDict *options, int flags)
static int qcow_open(BlockDriverState *bs, int flags)
{
BDRVQcowState *s = bs->opaque;
int len, i, shift, ret;
@@ -679,7 +679,7 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
return ret;
}
ret = bdrv_file_open(&qcow_bs, filename, NULL, BDRV_O_RDWR);
ret = bdrv_file_open(&qcow_bs, filename, BDRV_O_RDWR);
if (ret < 0) {
return ret;
}
@@ -787,21 +787,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
uint8_t *out_buf;
uint64_t cluster_offset;
if (nb_sectors != s->cluster_sectors) {
ret = -EINVAL;
/* Zero-pad last write if image size is not cluster aligned */
if (sector_num + nb_sectors == bs->total_sectors &&
nb_sectors < s->cluster_sectors) {
uint8_t *pad_buf = qemu_blockalign(bs, s->cluster_size);
memset(pad_buf, 0, s->cluster_size);
memcpy(pad_buf, buf, nb_sectors * BDRV_SECTOR_SIZE);
ret = qcow_write_compressed(bs, sector_num,
pad_buf, s->cluster_sectors);
qemu_vfree(pad_buf);
}
return ret;
}
if (nb_sectors != s->cluster_sectors)
return -EINVAL;
out_buf = g_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);

View File

@@ -29,13 +29,12 @@
#include "block/qcow2.h"
#include "trace.h"
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
bool exact_size)
int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size)
{
BDRVQcowState *s = bs->opaque;
int new_l1_size2, ret, i;
int new_l1_size, new_l1_size2, ret, i;
uint64_t *new_l1_table;
int64_t new_l1_table_offset, new_l1_size;
int64_t new_l1_table_offset;
uint8_t data[12];
if (min_size <= s->l1_size)
@@ -54,13 +53,8 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
}
}
if (new_l1_size > INT_MAX) {
return -EFBIG;
}
#ifdef DEBUG_ALLOC2
fprintf(stderr, "grow l1_table from %d to %" PRId64 "\n",
s->l1_size, new_l1_size);
fprintf(stderr, "grow l1_table from %d to %d\n", s->l1_size, new_l1_size);
#endif
new_l1_size2 = sizeof(uint64_t) * new_l1_size;
@@ -397,8 +391,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
int *num, uint64_t *cluster_offset)
{
BDRVQcowState *s = bs->opaque;
unsigned int l2_index;
uint64_t l1_index, l2_offset, *l2_table;
unsigned int l1_index, l2_index;
uint64_t l2_offset, *l2_table;
int l1_bits, c;
unsigned int index_in_cluster, nb_clusters;
uint64_t nb_available, nb_needed;
@@ -513,8 +507,8 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
int *new_l2_index)
{
BDRVQcowState *s = bs->opaque;
unsigned int l2_index;
uint64_t l1_index, l2_offset;
unsigned int l1_index, l2_index;
uint64_t l2_offset;
uint64_t *l2_table = NULL;
int ret;
@@ -528,7 +522,6 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
}
}
assert(l1_index < s->l1_size);
l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
/* seek the l2 table of the given l2 offset */
@@ -678,7 +671,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
}
/* Update L2 table. */
if (s->use_lazy_refcounts) {
if (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS) {
qcow2_mark_dirty(bs);
}
if (qcow2_need_accurate_refcounts(s)) {
@@ -766,50 +759,31 @@ out:
* Check if there already is an AIO write request in flight which allocates
* the same cluster. In this case we need to wait until the previous
* request has completed and updated the L2 table accordingly.
*
* Returns:
* 0 if there was no dependency. *cur_bytes indicates the number of
* bytes from guest_offset that can be read before the next
* dependency must be processed (or the request is complete)
*
* -EAGAIN if we had to wait for another request, previously gathered
* information on cluster allocation may be invalid now. The caller
* must start over anyway, so consider *cur_bytes undefined.
*/
static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
uint64_t *cur_bytes, QCowL2Meta **m)
unsigned int *nb_clusters)
{
BDRVQcowState *s = bs->opaque;
QCowL2Meta *old_alloc;
uint64_t bytes = *cur_bytes;
QLIST_FOREACH(old_alloc, &s->cluster_allocs, next_in_flight) {
uint64_t start = guest_offset;
uint64_t end = start + bytes;
uint64_t old_start = l2meta_cow_start(old_alloc);
uint64_t old_end = l2meta_cow_end(old_alloc);
uint64_t start = guest_offset >> s->cluster_bits;
uint64_t end = start + *nb_clusters;
uint64_t old_start = old_alloc->offset >> s->cluster_bits;
uint64_t old_end = old_start + old_alloc->nb_clusters;
if (end <= old_start || start >= old_end) {
if (end < old_start || start > old_end) {
/* No intersection */
} else {
if (start < old_start) {
/* Stop at the start of a running allocation */
bytes = old_start - start;
*nb_clusters = old_start - start;
} else {
bytes = 0;
*nb_clusters = 0;
}
/* Stop if already an l2meta exists. After yielding, it wouldn't
* be valid any more, so we'd have to clean up the old L2Metas
* and deal with requests depending on them before starting to
* gather new ones. Not worth the trouble. */
if (bytes == 0 && *m) {
*cur_bytes = 0;
return 0;
}
if (bytes == 0) {
if (*nb_clusters == 0) {
/* Wait for the dependency to complete. We need to recheck
* the free/allocated clusters when we continue. */
qemu_co_mutex_unlock(&s->lock);
@@ -820,117 +794,13 @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
}
}
/* Make sure that existing clusters and new allocations are only used up to
* the next dependency if we shortened the request above */
*cur_bytes = bytes;
if (!*nb_clusters) {
abort();
}
return 0;
}
/*
* Checks how many already allocated clusters that don't require a copy on
* write there are at the given guest_offset (up to *bytes). If
* *host_offset is not zero, only physically contiguous clusters beginning at
* this host offset are counted.
*
* Note that guest_offset may not be cluster aligned. In this case, the
* returned *host_offset points to exact byte referenced by guest_offset and
* therefore isn't cluster aligned as well.
*
* Returns:
* 0: if no allocated clusters are available at the given offset.
* *bytes is normally unchanged. It is set to 0 if the cluster
* is allocated and doesn't need COW, but doesn't have the right
* physical offset.
*
* 1: if allocated clusters that don't require a COW are available at
* the requested offset. *bytes may have decreased and describes
* the length of the area that can be written to.
*
* -errno: in error cases
*/
static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m)
{
BDRVQcowState *s = bs->opaque;
int l2_index;
uint64_t cluster_offset;
uint64_t *l2_table;
unsigned int nb_clusters;
unsigned int keep_clusters;
int ret, pret;
trace_qcow2_handle_copied(qemu_coroutine_self(), guest_offset, *host_offset,
*bytes);
assert(*host_offset == 0 || offset_into_cluster(s, guest_offset)
== offset_into_cluster(s, *host_offset));
/*
* Calculate the number of clusters to look for. We stop at L2 table
* boundaries to keep things simple.
*/
nb_clusters =
size_to_clusters(s, offset_into_cluster(s, guest_offset) + *bytes);
l2_index = offset_to_l2_index(s, guest_offset);
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
/* Find L2 entry for the first involved cluster */
ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
if (ret < 0) {
return ret;
}
cluster_offset = be64_to_cpu(l2_table[l2_index]);
/* Check how many clusters are already allocated and don't need COW */
if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL
&& (cluster_offset & QCOW_OFLAG_COPIED))
{
/* If a specific host_offset is required, check it */
bool offset_matches =
(cluster_offset & L2E_OFFSET_MASK) == *host_offset;
if (*host_offset != 0 && !offset_matches) {
*bytes = 0;
ret = 0;
goto out;
}
/* We keep all QCOW_OFLAG_COPIED clusters */
keep_clusters =
count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], 0,
QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);
assert(keep_clusters <= nb_clusters);
*bytes = MIN(*bytes,
keep_clusters * s->cluster_size
- offset_into_cluster(s, guest_offset));
ret = 1;
} else {
ret = 0;
}
/* Cleanup */
out:
pret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
if (pret < 0) {
return pret;
}
/* Only return a host offset if we actually made progress. Otherwise we
* would make requirements for handle_alloc() that it can't fulfill */
if (ret) {
*host_offset = (cluster_offset & L2E_OFFSET_MASK)
+ offset_into_cluster(s, guest_offset);
}
return ret;
}
/*
* Allocates new clusters for the given guest_offset.
*
@@ -954,10 +824,16 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
uint64_t *host_offset, unsigned int *nb_clusters)
{
BDRVQcowState *s = bs->opaque;
int ret;
trace_qcow2_do_alloc_clusters_offset(qemu_coroutine_self(), guest_offset,
*host_offset, *nb_clusters);
ret = handle_dependencies(bs, guest_offset, nb_clusters);
if (ret < 0) {
return ret;
}
/* Allocate new clusters */
trace_qcow2_cluster_alloc_phys(qemu_coroutine_self());
if (*host_offset == 0) {
@@ -969,7 +845,7 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
*host_offset = cluster_offset;
return 0;
} else {
int ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters);
ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters);
if (ret < 0) {
return ret;
}
@@ -978,151 +854,6 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
}
}
/*
* Allocates new clusters for an area that either is yet unallocated or needs a
* copy on write. If *host_offset is non-zero, clusters are only allocated if
* the new allocation can match the specified host offset.
*
* Note that guest_offset may not be cluster aligned. In this case, the
* returned *host_offset points to exact byte referenced by guest_offset and
* therefore isn't cluster aligned as well.
*
* Returns:
* 0: if no clusters could be allocated. *bytes is set to 0,
* *host_offset is left unchanged.
*
* 1: if new clusters were allocated. *bytes may be decreased if the
* new allocation doesn't cover all of the requested area.
* *host_offset is updated to contain the host offset of the first
* newly allocated cluster.
*
* -errno: in error cases
*/
static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m)
{
BDRVQcowState *s = bs->opaque;
int l2_index;
uint64_t *l2_table;
uint64_t entry;
unsigned int nb_clusters;
int ret;
uint64_t alloc_cluster_offset;
trace_qcow2_handle_alloc(qemu_coroutine_self(), guest_offset, *host_offset,
*bytes);
assert(*bytes > 0);
/*
* Calculate the number of clusters to look for. We stop at L2 table
* boundaries to keep things simple.
*/
nb_clusters =
size_to_clusters(s, offset_into_cluster(s, guest_offset) + *bytes);
l2_index = offset_to_l2_index(s, guest_offset);
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
/* Find L2 entry for the first involved cluster */
ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
if (ret < 0) {
return ret;
}
entry = be64_to_cpu(l2_table[l2_index]);
/* For the moment, overwrite compressed clusters one by one */
if (entry & QCOW_OFLAG_COMPRESSED) {
nb_clusters = 1;
} else {
nb_clusters = count_cow_clusters(s, nb_clusters, l2_table, l2_index);
}
/* This function is only called when there were no non-COW clusters, so if
* we can't find any unallocated or COW clusters either, something is
* wrong with our code. */
assert(nb_clusters > 0);
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
if (ret < 0) {
return ret;
}
/* Allocate, if necessary at a given offset in the image file */
alloc_cluster_offset = start_of_cluster(s, *host_offset);
ret = do_alloc_cluster_offset(bs, guest_offset, &alloc_cluster_offset,
&nb_clusters);
if (ret < 0) {
goto fail;
}
/* Can't extend contiguous allocation */
if (nb_clusters == 0) {
*bytes = 0;
return 0;
}
/*
* Save info needed for meta data update.
*
* requested_sectors: Number of sectors from the start of the first
* newly allocated cluster to the end of the (possibly shortened
* before) write request.
*
* avail_sectors: Number of sectors from the start of the first
* newly allocated to the end of the last newly allocated cluster.
*
* nb_sectors: The number of sectors from the start of the first
* newly allocated cluster to the end of the area that the write
* request actually writes to (excluding COW at the end)
*/
int requested_sectors =
(*bytes + offset_into_cluster(s, guest_offset))
>> BDRV_SECTOR_BITS;
int avail_sectors = nb_clusters
<< (s->cluster_bits - BDRV_SECTOR_BITS);
int alloc_n_start = offset_into_cluster(s, guest_offset)
>> BDRV_SECTOR_BITS;
int nb_sectors = MIN(requested_sectors, avail_sectors);
QCowL2Meta *old_m = *m;
*m = g_malloc0(sizeof(**m));
**m = (QCowL2Meta) {
.next = old_m,
.alloc_offset = alloc_cluster_offset,
.offset = start_of_cluster(s, guest_offset),
.nb_clusters = nb_clusters,
.nb_available = nb_sectors,
.cow_start = {
.offset = 0,
.nb_sectors = alloc_n_start,
},
.cow_end = {
.offset = nb_sectors * BDRV_SECTOR_SIZE,
.nb_sectors = avail_sectors - nb_sectors,
},
};
qemu_co_queue_init(&(*m)->dependent_requests);
QLIST_INSERT_HEAD(&s->cluster_allocs, *m, next_in_flight);
*host_offset = alloc_cluster_offset + offset_into_cluster(s, guest_offset);
*bytes = MIN(*bytes, (nb_sectors * BDRV_SECTOR_SIZE)
- offset_into_cluster(s, guest_offset));
assert(*bytes != 0);
return 1;
fail:
if (*m && (*m)->nb_clusters > 0) {
QLIST_REMOVE(*m, next_in_flight);
}
return ret;
}
/*
* alloc_cluster_offset
*
@@ -1146,110 +877,161 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
int n_start, int n_end, int *num, uint64_t *host_offset, QCowL2Meta **m)
{
BDRVQcowState *s = bs->opaque;
uint64_t start, remaining;
int l2_index, ret, sectors;
uint64_t *l2_table;
unsigned int nb_clusters, keep_clusters;
uint64_t cluster_offset;
uint64_t cur_bytes;
int ret;
trace_qcow2_alloc_clusters_offset(qemu_coroutine_self(), offset,
n_start, n_end);
assert(n_start * BDRV_SECTOR_SIZE == offset_into_cluster(s, offset));
offset = start_of_cluster(s, offset);
/* Find L2 entry for the first involved cluster */
again:
start = offset + (n_start << BDRV_SECTOR_BITS);
remaining = (n_end - n_start) << BDRV_SECTOR_BITS;
cluster_offset = 0;
*host_offset = 0;
cur_bytes = 0;
*m = NULL;
while (true) {
if (!*host_offset) {
*host_offset = start_of_cluster(s, cluster_offset);
ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
if (ret < 0) {
return ret;
}
assert(remaining >= cur_bytes);
start += cur_bytes;
remaining -= cur_bytes;
cluster_offset += cur_bytes;
if (remaining == 0) {
break;
}
cur_bytes = remaining;
/*
* Now start gathering as many contiguous clusters as possible:
*
* 1. Check for overlaps with in-flight allocations
*
* a) Overlap not in the first cluster -> shorten this request and
* let the caller handle the rest in its next loop iteration.
*
* b) Real overlaps of two requests. Yield and restart the search
* for contiguous clusters (the situation could have changed
* while we were sleeping)
*
* c) TODO: Request starts in the same cluster as the in-flight
* allocation ends. Shorten the COW of the in-fight allocation,
* set cluster_offset to write to the same cluster and set up
* the right synchronisation between the in-flight request and
* the new one.
* Calculate the number of clusters to look for. We stop at L2 table
* boundaries to keep things simple.
*/
ret = handle_dependencies(bs, start, &cur_bytes, m);
nb_clusters = MIN(size_to_clusters(s, n_end << BDRV_SECTOR_BITS),
s->l2_size - l2_index);
cluster_offset = be64_to_cpu(l2_table[l2_index]);
/*
* Check how many clusters are already allocated and don't need COW, and how
* many need a new allocation.
*/
if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL
&& (cluster_offset & QCOW_OFLAG_COPIED))
{
/* We keep all QCOW_OFLAG_COPIED clusters */
keep_clusters =
count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], 0,
QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);
assert(keep_clusters <= nb_clusters);
nb_clusters -= keep_clusters;
} else {
keep_clusters = 0;
cluster_offset = 0;
}
if (nb_clusters > 0) {
/* For the moment, overwrite compressed clusters one by one */
uint64_t entry = be64_to_cpu(l2_table[l2_index + keep_clusters]);
if (entry & QCOW_OFLAG_COMPRESSED) {
nb_clusters = 1;
} else {
nb_clusters = count_cow_clusters(s, nb_clusters, l2_table,
l2_index + keep_clusters);
}
}
cluster_offset &= L2E_OFFSET_MASK;
/*
* The L2 table isn't used any more after this. As long as the cache works
* synchronously, it's important to release it before calling
* do_alloc_cluster_offset, which may yield if we need to wait for another
* request to complete. If we still had the reference, we could use up the
* whole cache with sleeping requests.
*/
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
if (ret < 0) {
return ret;
}
/* If there is something left to allocate, do that now */
if (nb_clusters > 0) {
uint64_t alloc_offset;
uint64_t alloc_cluster_offset;
uint64_t keep_bytes = keep_clusters * s->cluster_size;
/* Calculate start and size of allocation */
alloc_offset = offset + keep_bytes;
if (keep_clusters == 0) {
alloc_cluster_offset = 0;
} else {
alloc_cluster_offset = cluster_offset + keep_bytes;
}
/* Allocate, if necessary at a given offset in the image file */
ret = do_alloc_cluster_offset(bs, alloc_offset, &alloc_cluster_offset,
&nb_clusters);
if (ret == -EAGAIN) {
/* Currently handle_dependencies() doesn't yield if we already had
* an allocation. If it did, we would have to clean up the L2Meta
* structs before starting over. */
assert(*m == NULL);
goto again;
} else if (ret < 0) {
return ret;
} else if (cur_bytes == 0) {
break;
} else {
/* handle_dependencies() may have decreased cur_bytes (shortened
* the allocations below) so that the next dependency is processed
* correctly during the next loop iteration. */
goto fail;
}
/* save info needed for meta data update */
if (nb_clusters > 0) {
/*
* 2. Count contiguous COPIED clusters.
* requested_sectors: Number of sectors from the start of the first
* newly allocated cluster to the end of the (possibly shortened
* before) write request.
*
* avail_sectors: Number of sectors from the start of the first
* newly allocated to the end of the last newly allocated cluster.
*
* nb_sectors: The number of sectors from the start of the first
* newly allocated cluster to the end of the aread that the write
* request actually writes to (excluding COW at the end)
*/
ret = handle_copied(bs, start, &cluster_offset, &cur_bytes, m);
if (ret < 0) {
return ret;
} else if (ret) {
continue;
} else if (cur_bytes == 0) {
break;
int requested_sectors = n_end - keep_clusters * s->cluster_sectors;
int avail_sectors = nb_clusters
<< (s->cluster_bits - BDRV_SECTOR_BITS);
int alloc_n_start = keep_clusters == 0 ? n_start : 0;
int nb_sectors = MIN(requested_sectors, avail_sectors);
if (keep_clusters == 0) {
cluster_offset = alloc_cluster_offset;
}
/*
* 3. If the request still hasn't completed, allocate new clusters,
* considering any cluster_offset of steps 1c or 2.
*/
ret = handle_alloc(bs, start, &cluster_offset, &cur_bytes, m);
if (ret < 0) {
return ret;
} else if (ret) {
continue;
} else {
assert(cur_bytes == 0);
break;
*m = g_malloc0(sizeof(**m));
**m = (QCowL2Meta) {
.alloc_offset = alloc_cluster_offset,
.offset = alloc_offset & ~(s->cluster_size - 1),
.nb_clusters = nb_clusters,
.nb_available = nb_sectors,
.cow_start = {
.offset = 0,
.nb_sectors = alloc_n_start,
},
.cow_end = {
.offset = nb_sectors * BDRV_SECTOR_SIZE,
.nb_sectors = avail_sectors - nb_sectors,
},
};
qemu_co_queue_init(&(*m)->dependent_requests);
QLIST_INSERT_HEAD(&s->cluster_allocs, *m, next_in_flight);
}
}
*num = (n_end - n_start) - (remaining >> BDRV_SECTOR_BITS);
assert(*num > 0);
assert(*host_offset != 0);
/* Some cleanup work */
sectors = (keep_clusters + nb_clusters) << (s->cluster_bits - 9);
if (sectors > n_end) {
sectors = n_end;
}
assert(sectors > n_start);
*num = sectors - n_start;
*host_offset = cluster_offset;
return 0;
fail:
if (*m && (*m)->nb_clusters > 0) {
QLIST_REMOVE(*m, next_in_flight);
}
return ret;
}
static int decompress_buffer(uint8_t *out_buf, int out_buf_size,

View File

@@ -532,6 +532,8 @@ static int update_cluster_refcount(BlockDriverState *bs,
return ret;
}
bdrv_flush(bs->file);
return get_refcount(bs, cluster_index);
}
@@ -667,11 +669,7 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
}
}
/* The cluster refcount was incremented, either by qcow2_alloc_clusters()
* or explicitly by update_cluster_refcount(). Refcount blocks must be
* flushed before the caller's L2 table updates.
*/
qcow2_cache_set_dependency(bs, s->l2_table_cache, s->refcount_block_cache);
bdrv_flush(bs->file);
return offset;
}
@@ -747,9 +745,10 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
if (l1_table_offset != s->l1_table_offset) {
l1_table = g_malloc0(align_offset(l1_size2, 512));
l1_allocated = 1;
ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
if (ret < 0) {
if (bdrv_pread(bs->file, l1_table_offset,
l1_table, l1_size2) != l1_size2)
{
ret = -EIO;
goto fail;
}
@@ -789,6 +788,10 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
if (ret < 0) {
goto fail;
}
/* TODO Flushing once for the whole function should
* be enough */
bdrv_flush(bs->file);
}
/* compressed clusters are never modified */
refcount = 2;
@@ -801,7 +804,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
}
if (refcount < 0) {
ret = refcount;
ret = -EIO;
goto fail;
}
}
@@ -832,7 +835,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
}
if (refcount < 0) {
ret = refcount;
ret = -EIO;
goto fail;
} else if (refcount == 1) {
l2_offset |= QCOW_OFLAG_COPIED;
@@ -844,24 +847,22 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
}
}
ret = bdrv_flush(bs);
ret = 0;
fail:
if (l2_table) {
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
}
/* Update L1 only if it isn't deleted anyway (addend = -1) */
if (ret == 0 && addend >= 0 && l1_modified) {
for (i = 0; i < l1_size; i++) {
if (addend >= 0 && l1_modified) {
for(i = 0; i < l1_size; i++)
cpu_to_be64s(&l1_table[i]);
}
ret = bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table, l1_size2);
for (i = 0; i < l1_size; i++) {
if (bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table,
l1_size2) < 0)
goto fail;
for(i = 0; i < l1_size; i++)
be64_to_cpus(&l1_table[i]);
}
}
if (l1_allocated)
g_free(l1_table);
return ret;
@@ -919,12 +920,6 @@ static void inc_refcounts(BlockDriverState *bs,
}
}
/* Flags for check_refcounts_l1() and check_refcounts_l2() */
enum {
CHECK_OFLAG_COPIED = 0x1, /* check QCOW_OFLAG_COPIED matches refcount */
CHECK_FRAG_INFO = 0x2, /* update BlockFragInfo counters */
};
/*
* Increases the refcount in the given refcount table for the all clusters
* referenced in the L2 table. While doing so, performs some checks on L2
@@ -935,11 +930,10 @@ enum {
*/
static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
uint16_t *refcount_table, int refcount_table_size, int64_t l2_offset,
int flags)
int check_copied)
{
BDRVQcowState *s = bs->opaque;
uint64_t *l2_table, l2_entry;
uint64_t next_contiguous_offset = 0;
int i, l2_size, nb_csectors, refcount;
/* Read L2 table from disk */
@@ -970,18 +964,6 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
l2_entry &= s->cluster_offset_mask;
inc_refcounts(bs, res, refcount_table, refcount_table_size,
l2_entry & ~511, nb_csectors * 512);
if (flags & CHECK_FRAG_INFO) {
res->bfi.allocated_clusters++;
res->bfi.compressed_clusters++;
/* Compressed clusters are fragmented by nature. Since they
* take up sub-sector space but we only have sector granularity
* I/O we need to re-read the same sectors even for adjacent
* compressed clusters.
*/
res->bfi.fragmented_clusters++;
}
break;
case QCOW2_CLUSTER_ZERO:
@@ -995,7 +977,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
/* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
uint64_t offset = l2_entry & L2E_OFFSET_MASK;
if (flags & CHECK_OFLAG_COPIED) {
if (check_copied) {
refcount = get_refcount(bs, offset >> s->cluster_bits);
if (refcount < 0) {
fprintf(stderr, "Can't get refcount for offset %"
@@ -1009,15 +991,6 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
}
}
if (flags & CHECK_FRAG_INFO) {
res->bfi.allocated_clusters++;
if (next_contiguous_offset &&
offset != next_contiguous_offset) {
res->bfi.fragmented_clusters++;
}
next_contiguous_offset = offset + s->cluster_size;
}
/* Mark cluster as used */
inc_refcounts(bs, res, refcount_table,refcount_table_size,
offset, s->cluster_size);
@@ -1061,7 +1034,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
uint16_t *refcount_table,
int refcount_table_size,
int64_t l1_table_offset, int l1_size,
int flags)
int check_copied)
{
BDRVQcowState *s = bs->opaque;
uint64_t *l1_table, l2_offset, l1_size2;
@@ -1090,7 +1063,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
l2_offset = l1_table[i];
if (l2_offset) {
/* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
if (flags & CHECK_OFLAG_COPIED) {
if (check_copied) {
refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED)
>> s->cluster_bits);
if (refcount < 0) {
@@ -1119,7 +1092,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
/* Process and check L2 entries */
ret = check_refcounts_l2(bs, res, refcount_table,
refcount_table_size, l2_offset, flags);
refcount_table_size, l2_offset, check_copied);
if (ret < 0) {
goto fail;
}
@@ -1145,7 +1118,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
BdrvCheckMode fix)
{
BDRVQcowState *s = bs->opaque;
int64_t size, i, highest_cluster;
int64_t size, i;
int nb_clusters, refcount1, refcount2;
QCowSnapshot *sn;
uint16_t *refcount_table;
@@ -1155,17 +1128,13 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
nb_clusters = size_to_clusters(s, size);
refcount_table = g_malloc0(nb_clusters * sizeof(uint16_t));
res->bfi.total_clusters =
size_to_clusters(s, bs->total_sectors * BDRV_SECTOR_SIZE);
/* header */
inc_refcounts(bs, res, refcount_table, nb_clusters,
0, s->cluster_size);
/* current L1 table */
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
s->l1_table_offset, s->l1_size,
CHECK_OFLAG_COPIED | CHECK_FRAG_INFO);
s->l1_table_offset, s->l1_size, 1);
if (ret < 0) {
goto fail;
}
@@ -1220,7 +1189,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
}
/* compare ref counts */
for (i = 0, highest_cluster = 0; i < nb_clusters; i++) {
for(i = 0; i < nb_clusters; i++) {
refcount1 = get_refcount(bs, i);
if (refcount1 < 0) {
fprintf(stderr, "Can't get refcount for cluster %" PRId64 ": %s\n",
@@ -1230,11 +1199,6 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
}
refcount2 = refcount_table[i];
if (refcount1 > 0 || refcount2 > 0) {
highest_cluster = i;
}
if (refcount1 != refcount2) {
/* Check if we're allowed to fix the mismatch */
@@ -1269,7 +1233,6 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
}
}
res->image_end_offset = (highest_cluster + 1) * s->cluster_size;
ret = 0;
fail:

View File

@@ -381,6 +381,11 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
goto fail;
}
ret = bdrv_flush(bs);
if (ret < 0) {
goto fail;
}
/* Append the new snapshot to the snapshot list */
new_snapshot_list = g_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
if (s->snapshots) {

View File

@@ -25,11 +25,10 @@
#include "block/block_int.h"
#include "qemu/module.h"
#include <zlib.h>
#include "qemu/aes.h"
#include "block/aes.h"
#include "block/qcow2.h"
#include "qemu/error-report.h"
#include "qapi/qmp/qerror.h"
#include "qapi/qmp/qbool.h"
#include "trace.h"
/*
@@ -286,28 +285,12 @@ static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
return ret;
}
static QemuOptsList qcow2_runtime_opts = {
.name = "qcow2",
.head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head),
.desc = {
{
.name = "lazy_refcounts",
.type = QEMU_OPT_BOOL,
.help = "Postpone refcount updates",
},
{ /* end of list */ }
},
};
static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
static int qcow2_open(BlockDriverState *bs, int flags)
{
BDRVQcowState *s = bs->opaque;
int len, i, ret = 0;
QCowHeader header;
QemuOpts *opts;
Error *local_err = NULL;
uint64_t ext_end;
uint64_t l1_vm_state_index;
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
if (ret < 0) {
@@ -425,14 +408,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
/* read the level 1 table */
s->l1_size = header.l1_size;
l1_vm_state_index = size_to_l1(s, header.size);
if (l1_vm_state_index > INT_MAX) {
ret = -EFBIG;
goto fail;
}
s->l1_vm_state_index = l1_vm_state_index;
s->l1_vm_state_index = size_to_l1(s, header.size);
/* the L1 table must contain at least enough entries to put
header.size bytes */
if (s->l1_size < s->l1_vm_state_index) {
@@ -519,28 +495,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
}
}
/* Enable lazy_refcounts according to image and command line options */
opts = qemu_opts_create_nofail(&qcow2_runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
ret = -EINVAL;
goto fail;
}
s->use_lazy_refcounts = qemu_opt_get_bool(opts, QCOW2_OPT_LAZY_REFCOUNTS,
(s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS));
qemu_opts_del(opts);
if (s->use_lazy_refcounts && s->qcow_version < 3) {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Lazy refcounts require "
"a qcow2 image with at least qemu 1.1 compatibility level");
ret = -EINVAL;
goto fail;
}
#ifdef DEBUG_ALLOC
{
BdrvCheckResult result = {0};
@@ -866,9 +820,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
goto fail;
}
while (l2meta != NULL) {
QCowL2Meta *next;
if (l2meta != NULL) {
ret = qcow2_alloc_cluster_link_l2(bs, l2meta);
if (ret < 0) {
goto fail;
@@ -879,11 +831,12 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
QLIST_REMOVE(l2meta, next_in_flight);
}
qemu_co_mutex_unlock(&s->lock);
qemu_co_queue_restart_all(&l2meta->dependent_requests);
qemu_co_mutex_lock(&s->lock);
next = l2meta->next;
g_free(l2meta);
l2meta = next;
l2meta = NULL;
}
remaining_sectors -= cur_nr_sectors;
@@ -896,17 +849,12 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
fail:
qemu_co_mutex_unlock(&s->lock);
while (l2meta != NULL) {
QCowL2Meta *next;
if (l2meta != NULL) {
if (l2meta->nb_clusters != 0) {
QLIST_REMOVE(l2meta, next_in_flight);
}
qemu_co_queue_restart_all(&l2meta->dependent_requests);
next = l2meta->next;
g_free(l2meta);
l2meta = next;
}
qemu_iovec_destroy(&hd_qiov);
@@ -945,7 +893,6 @@ static void qcow2_invalidate_cache(BlockDriverState *bs)
AES_KEY aes_encrypt_key;
AES_KEY aes_decrypt_key;
uint32_t crypt_method = 0;
QDict *options;
/*
* Backing files are read-only which makes all of their metadata immutable,
@@ -960,14 +907,8 @@ static void qcow2_invalidate_cache(BlockDriverState *bs)
qcow2_close(bs);
options = qdict_new();
qdict_put(options, QCOW2_OPT_LAZY_REFCOUNTS,
qbool_from_int(s->use_lazy_refcounts));
memset(s, 0, sizeof(BDRVQcowState));
qcow2_open(bs, options, flags);
QDECREF(options);
qcow2_open(bs, flags);
if (crypt_method) {
s->crypt_method = crypt_method;
@@ -1268,7 +1209,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
return ret;
}
ret = bdrv_file_open(&bs, filename, NULL, BDRV_O_RDWR);
ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR);
if (ret < 0) {
return ret;
}
@@ -1320,7 +1261,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
*/
BlockDriver* drv = bdrv_find_format("qcow2");
assert(drv != NULL);
ret = bdrv_open(bs, filename, NULL,
ret = bdrv_open(bs, filename,
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv);
if (ret < 0) {
goto out;
@@ -1488,8 +1429,7 @@ static coroutine_fn int qcow2_co_discard(BlockDriverState *bs,
static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
{
BDRVQcowState *s = bs->opaque;
int64_t new_l1_size;
int ret;
int ret, new_l1_size;
if (offset & 511) {
error_report("The new size must be a multiple of 512");
@@ -1546,21 +1486,8 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
return 0;
}
if (nb_sectors != s->cluster_sectors) {
ret = -EINVAL;
/* Zero-pad last write if image size is not cluster aligned */
if (sector_num + nb_sectors == bs->total_sectors &&
nb_sectors < s->cluster_sectors) {
uint8_t *pad_buf = qemu_blockalign(bs, s->cluster_size);
memset(pad_buf, 0, s->cluster_size);
memcpy(pad_buf, buf, nb_sectors * BDRV_SECTOR_SIZE);
ret = qcow2_write_compressed(bs, sector_num,
pad_buf, s->cluster_sectors);
qemu_vfree(pad_buf);
}
return ret;
}
if (nb_sectors != s->cluster_sectors)
return -EINVAL;
out_buf = g_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
@@ -1674,8 +1601,8 @@ static void dump_refcounts(BlockDriverState *bs)
}
#endif
static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
int64_t pos)
static int qcow2_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
int64_t pos, int size)
{
BDRVQcowState *s = bs->opaque;
int growable = bs->growable;
@@ -1683,7 +1610,7 @@ static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
bs->growable = 1;
ret = bdrv_pwritev(bs, qcow2_vm_state_offset(s) + pos, qiov);
ret = bdrv_pwrite(bs, qcow2_vm_state_offset(s) + pos, buf, size);
bs->growable = growable;
return ret;

View File

@@ -25,7 +25,7 @@
#ifndef BLOCK_QCOW2_H
#define BLOCK_QCOW2_H
#include "qemu/aes.h"
#include "block/aes.h"
#include "block/coroutine.h"
//#define DEBUG_ALLOC
@@ -58,9 +58,6 @@
#define DEFAULT_CLUSTER_SIZE 65536
#define QCOW2_OPT_LAZY_REFCOUNTS "lazy_refcounts"
typedef struct QCowHeader {
uint32_t magic;
uint32_t version;
@@ -176,7 +173,6 @@ typedef struct BDRVQcowState {
int flags;
int qcow_version;
bool use_lazy_refcounts;
uint64_t incompatible_features;
uint64_t compatible_features;
@@ -250,9 +246,6 @@ typedef struct QCowL2Meta
*/
Qcow2COWRegion cow_end;
/** Pointer to next L2Meta of the same write request */
struct QCowL2Meta *next;
QLIST_ENTRY(QCowL2Meta) next_in_flight;
} QCowL2Meta;
@@ -269,32 +262,17 @@ enum {
#define REFT_OFFSET_MASK 0xffffffffffffff00ULL
static inline int64_t start_of_cluster(BDRVQcowState *s, int64_t offset)
{
return offset & ~(s->cluster_size - 1);
}
static inline int64_t offset_into_cluster(BDRVQcowState *s, int64_t offset)
{
return offset & (s->cluster_size - 1);
}
static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
{
return (size + (s->cluster_size - 1)) >> s->cluster_bits;
}
static inline int64_t size_to_l1(BDRVQcowState *s, int64_t size)
static inline int size_to_l1(BDRVQcowState *s, int64_t size)
{
int shift = s->cluster_bits + s->l2_bits;
return (size + (1ULL << shift) - 1) >> shift;
}
static inline int offset_to_l2_index(BDRVQcowState *s, int64_t offset)
{
return (offset >> s->cluster_bits) & (s->l2_size - 1);
}
static inline int64_t align_offset(int64_t offset, int n)
{
offset = (offset + n - 1) & ~(n - 1);
@@ -320,17 +298,6 @@ static inline bool qcow2_need_accurate_refcounts(BDRVQcowState *s)
return !(s->incompatible_features & QCOW2_INCOMPAT_DIRTY);
}
static inline uint64_t l2meta_cow_start(QCowL2Meta *m)
{
return m->offset + m->cow_start.offset;
}
static inline uint64_t l2meta_cow_end(QCowL2Meta *m)
{
return m->offset + m->cow_end.offset
+ (m->cow_end.nb_sectors << BDRV_SECTOR_BITS);
}
// FIXME Need qcow2_ prefix to global functions
/* qcow2.c functions */
@@ -360,8 +327,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
BdrvCheckMode fix);
/* qcow2-cluster.c functions */
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
bool exact_size);
int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size);
void qcow2_l2_cache_reset(BlockDriverState *bs);
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,

View File

@@ -373,7 +373,7 @@ static void bdrv_qed_rebind(BlockDriverState *bs)
s->bs = bs;
}
static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags)
static int bdrv_qed_open(BlockDriverState *bs, int flags)
{
BDRVQEDState *s = bs->opaque;
QEDHeader le_header;
@@ -558,7 +558,7 @@ static int qed_create(const char *filename, uint32_t cluster_size,
return ret;
}
ret = bdrv_file_open(&bs, filename, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB);
ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR | BDRV_O_CACHE_WB);
if (ret < 0) {
return ret;
}
@@ -1526,7 +1526,7 @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs)
bdrv_qed_close(bs);
memset(s, 0, sizeof(BDRVQEDState));
bdrv_qed_open(bs, NULL, bs->open_flags);
bdrv_qed_open(bs, bs->open_flags);
}
static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result,

View File

@@ -262,42 +262,15 @@ error:
}
#endif
static QemuOptsList raw_runtime_opts = {
.name = "raw",
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
.desc = {
{
.name = "filename",
.type = QEMU_OPT_STRING,
.help = "File name of the image",
},
{ /* end of list */ }
},
};
static int raw_open_common(BlockDriverState *bs, QDict *options,
static int raw_open_common(BlockDriverState *bs, const char *filename,
int bdrv_flags, int open_flags)
{
BDRVRawState *s = bs->opaque;
QemuOpts *opts;
Error *local_err = NULL;
const char *filename;
int fd, ret;
opts = qemu_opts_create_nofail(&raw_runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
ret = -EINVAL;
goto fail;
}
filename = qemu_opt_get(opts, "filename");
ret = raw_normalize_devicepath(&filename);
if (ret != 0) {
goto fail;
return ret;
}
s->open_flags = open_flags;
@@ -307,18 +280,16 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
fd = qemu_open(filename, s->open_flags, 0644);
if (fd < 0) {
ret = -errno;
if (ret == -EROFS) {
if (ret == -EROFS)
ret = -EACCES;
}
goto fail;
return ret;
}
s->fd = fd;
#ifdef CONFIG_LINUX_AIO
if (raw_set_aio(&s->aio_ctx, &s->use_aio, bdrv_flags)) {
qemu_close(fd);
ret = -errno;
goto fail;
return -errno;
}
#endif
@@ -329,18 +300,15 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
}
#endif
ret = 0;
fail:
qemu_opts_del(opts);
return ret;
return 0;
}
static int raw_open(BlockDriverState *bs, QDict *options, int flags)
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
s->type = FTYPE_FILE;
return raw_open_common(bs, options, flags, 0);
return raw_open_common(bs, filename, flags, 0);
}
static int raw_reopen_prepare(BDRVReopenState *state,
@@ -782,7 +750,6 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
BlockDriverCompletionFunc *cb, void *opaque, int type)
{
RawPosixAIOData *acb = g_slice_new(RawPosixAIOData);
ThreadPool *pool;
acb->bs = bs;
acb->aio_type = type;
@@ -796,8 +763,7 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
acb->aio_offset = sector_num * 512;
trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
}
static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
@@ -1324,11 +1290,10 @@ static int check_hdev_writable(BDRVRawState *s)
return 0;
}
static int hdev_open(BlockDriverState *bs, QDict *options, int flags)
static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
int ret;
const char *filename = qdict_get_str(options, "filename");
#if defined(__APPLE__) && defined(__MACH__)
if (strstart(filename, "/dev/cdrom", NULL)) {
@@ -1369,7 +1334,7 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags)
}
#endif
ret = raw_open_common(bs, options, flags, 0);
ret = raw_open_common(bs, filename, flags, 0);
if (ret < 0) {
return ret;
}
@@ -1448,7 +1413,6 @@ static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
{
BDRVRawState *s = bs->opaque;
RawPosixAIOData *acb;
ThreadPool *pool;
if (fd_open(bs) < 0)
return NULL;
@@ -1460,8 +1424,7 @@ static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
acb->aio_offset = 0;
acb->aio_ioctl_buf = buf;
acb->aio_ioctl_cmd = req;
pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
}
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -1563,7 +1526,7 @@ static BlockDriver bdrv_host_device = {
};
#ifdef __linux__
static int floppy_open(BlockDriverState *bs, QDict *options, int flags)
static int floppy_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
int ret;
@@ -1571,7 +1534,7 @@ static int floppy_open(BlockDriverState *bs, QDict *options, int flags)
s->type = FTYPE_FD;
/* open will not fail even if no floppy is inserted, so add O_NONBLOCK */
ret = raw_open_common(bs, options, flags, O_NONBLOCK);
ret = raw_open_common(bs, filename, flags, O_NONBLOCK);
if (ret)
return ret;
@@ -1685,14 +1648,14 @@ static BlockDriver bdrv_host_floppy = {
.bdrv_eject = floppy_eject,
};
static int cdrom_open(BlockDriverState *bs, QDict *options, int flags)
static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
s->type = FTYPE_CD;
/* open will not fail even if no CD is inserted, so add O_NONBLOCK */
return raw_open_common(bs, options, flags, O_NONBLOCK);
return raw_open_common(bs, filename, flags, O_NONBLOCK);
}
static int cdrom_probe_device(const char *filename)
@@ -1793,14 +1756,14 @@ static BlockDriver bdrv_host_cdrom = {
#endif /* __linux__ */
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
static int cdrom_open(BlockDriverState *bs, QDict *options, int flags)
static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
int ret;
s->type = FTYPE_CD;
ret = raw_open_common(bs, options, flags, 0);
ret = raw_open_common(bs, filename, flags, 0);
if (ret)
return ret;

View File

@@ -144,7 +144,6 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
BlockDriverCompletionFunc *cb, void *opaque, int type)
{
RawWin32AIOData *acb = g_slice_new(RawWin32AIOData);
ThreadPool *pool;
acb->bs = bs;
acb->hfile = hfile;
@@ -158,8 +157,7 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
acb->aio_offset = sector_num * 512;
trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
}
int qemu_ftruncate64(int fd, int64_t length)
@@ -221,49 +219,20 @@ static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped)
}
}
static QemuOptsList raw_runtime_opts = {
.name = "raw",
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
.desc = {
{
.name = "filename",
.type = QEMU_OPT_STRING,
.help = "File name of the image",
},
{ /* end of list */ }
},
};
static int raw_open(BlockDriverState *bs, QDict *options, int flags)
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
int access_flags;
DWORD overlapped;
QemuOpts *opts;
Error *local_err = NULL;
const char *filename;
int ret;
s->type = FTYPE_FILE;
opts = qemu_opts_create_nofail(&raw_runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
ret = -EINVAL;
goto fail;
}
filename = qemu_opt_get(opts, "filename");
raw_parse_flags(flags, &access_flags, &overlapped);
if ((flags & BDRV_O_NATIVE_AIO) && aio == NULL) {
aio = win32_aio_init();
if (aio == NULL) {
ret = -EINVAL;
goto fail;
return -EINVAL;
}
}
@@ -273,27 +242,20 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags)
if (s->hfile == INVALID_HANDLE_VALUE) {
int err = GetLastError();
if (err == ERROR_ACCESS_DENIED) {
ret = -EACCES;
} else {
ret = -EINVAL;
}
goto fail;
if (err == ERROR_ACCESS_DENIED)
return -EACCES;
return -EINVAL;
}
if (flags & BDRV_O_NATIVE_AIO) {
ret = win32_aio_attach(aio, s->hfile);
int ret = win32_aio_attach(aio, s->hfile);
if (ret < 0) {
CloseHandle(s->hfile);
goto fail;
return ret;
}
s->aio = aio;
}
ret = 0;
fail:
qemu_opts_del(opts);
return ret;
return 0;
}
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
@@ -530,13 +492,12 @@ static int hdev_probe_device(const char *filename)
return 0;
}
static int hdev_open(BlockDriverState *bs, QDict *options, int flags)
static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
int access_flags, create_flags;
DWORD overlapped;
char device_name[64];
const char *filename = qdict_get_str(options, "filename");
if (strstart(filename, "/dev/cdrom", NULL)) {
if (find_cdrom(device_name, sizeof(device_name)) < 0)

View File

@@ -3,7 +3,7 @@
#include "block/block_int.h"
#include "qemu/module.h"
static int raw_open(BlockDriverState *bs, QDict *options, int flags)
static int raw_open(BlockDriverState *bs, int flags)
{
bs->sg = bs->file->sg;
return 0;

View File

@@ -63,8 +63,7 @@
typedef enum {
RBD_AIO_READ,
RBD_AIO_WRITE,
RBD_AIO_DISCARD,
RBD_AIO_FLUSH
RBD_AIO_DISCARD
} RBDAIOCmd;
typedef struct RBDAIOCB {
@@ -380,7 +379,8 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
r = rcb->ret;
if (acb->cmd != RBD_AIO_READ) {
if (acb->cmd == RBD_AIO_WRITE ||
acb->cmd == RBD_AIO_DISCARD) {
if (r < 0) {
acb->ret = r;
acb->error = 1;
@@ -441,21 +441,7 @@ static int qemu_rbd_aio_flush_cb(void *opaque)
return (s->qemu_aio_count > 0);
}
/* TODO Convert to fine grained options */
static QemuOptsList runtime_opts = {
.name = "rbd",
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
.desc = {
{
.name = "filename",
.type = QEMU_OPT_STRING,
.help = "Specification of the rbd image",
},
{ /* end of list */ }
},
};
static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags)
static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRBDState *s = bs->opaque;
char pool[RBD_MAX_POOL_NAME_SIZE];
@@ -463,35 +449,20 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags)
char conf[RBD_MAX_CONF_SIZE];
char clientname_buf[RBD_MAX_CONF_SIZE];
char *clientname;
QemuOpts *opts;
Error *local_err = NULL;
const char *filename;
int r;
opts = qemu_opts_create_nofail(&runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
qemu_opts_del(opts);
return -EINVAL;
}
filename = qemu_opt_get(opts, "filename");
if (qemu_rbd_parsename(filename, pool, sizeof(pool),
snap_buf, sizeof(snap_buf),
s->name, sizeof(s->name),
conf, sizeof(conf)) < 0) {
r = -EINVAL;
goto failed_opts;
return -EINVAL;
}
clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
r = rados_create(&s->cluster, clientname);
if (r < 0) {
error_report("error initializing");
goto failed_opts;
return r;
}
s->snap = NULL;
@@ -557,7 +528,6 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags)
NULL, qemu_rbd_aio_flush_cb, s);
qemu_opts_del(opts);
return 0;
failed:
@@ -567,8 +537,6 @@ failed_open:
failed_shutdown:
rados_shutdown(s->cluster);
g_free(s->snap);
failed_opts:
qemu_opts_del(opts);
return r;
}
@@ -690,16 +658,6 @@ static int rbd_aio_discard_wrapper(rbd_image_t image,
#endif
}
static int rbd_aio_flush_wrapper(rbd_image_t image,
rbd_completion_t comp)
{
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
return rbd_aio_flush(image, comp);
#else
return -ENOTSUP;
#endif
}
static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
@@ -720,7 +678,7 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
acb = qemu_aio_get(&rbd_aiocb_info, bs, cb, opaque);
acb->cmd = cmd;
acb->qiov = qiov;
if (cmd == RBD_AIO_DISCARD || cmd == RBD_AIO_FLUSH) {
if (cmd == RBD_AIO_DISCARD) {
acb->bounce = NULL;
} else {
acb->bounce = qemu_blockalign(bs, qiov->size);
@@ -764,9 +722,6 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
case RBD_AIO_DISCARD:
r = rbd_aio_discard_wrapper(s->image, off, size, c);
break;
case RBD_AIO_FLUSH:
r = rbd_aio_flush_wrapper(s->image, c);
break;
default:
r = -EINVAL;
}
@@ -806,16 +761,6 @@ static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
RBD_AIO_WRITE);
}
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
static BlockDriverAIOCB *qemu_rbd_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb,
void *opaque)
{
return rbd_start_aio(bs, 0, NULL, 0, cb, opaque, RBD_AIO_FLUSH);
}
#else
static int qemu_rbd_co_flush(BlockDriverState *bs)
{
#if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1)
@@ -826,7 +771,6 @@ static int qemu_rbd_co_flush(BlockDriverState *bs)
return 0;
#endif
}
#endif
static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
{
@@ -1004,12 +948,7 @@ static BlockDriver bdrv_rbd = {
.bdrv_aio_readv = qemu_rbd_aio_readv,
.bdrv_aio_writev = qemu_rbd_aio_writev,
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
.bdrv_aio_flush = qemu_rbd_aio_flush,
#else
.bdrv_co_flush_to_disk = qemu_rbd_co_flush,
#endif
#ifdef LIBRBD_SUPPORTS_DISCARD
.bdrv_aio_discard = qemu_rbd_aio_discard,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -364,7 +364,7 @@ static int vdi_probe(const uint8_t *buf, int buf_size, const char *filename)
return result;
}
static int vdi_open(BlockDriverState *bs, QDict *options, int flags)
static int vdi_open(BlockDriverState *bs, int flags)
{
BDRVVdiState *s = bs->opaque;
VdiHeader header;

View File

@@ -1,972 +0,0 @@
/*
* Block driver for Hyper-V VHDX Images
*
* Copyright (c) 2013 Red Hat, Inc.,
*
* Authors:
* Jeff Cody <jcody@redhat.com>
*
* This is based on the "VHDX Format Specification v0.95", published 4/12/2012
* by Microsoft:
* https://www.microsoft.com/en-us/download/details.aspx?id=29681
*
* This work is licensed under the terms of the GNU LGPL, version 2 or later.
* See the COPYING.LIB file in the top-level directory.
*
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "qemu/crc32c.h"
#include "block/vhdx.h"
/* Several metadata and region table data entries are identified by
* guids in a MS-specific GUID format. */
/* ------- Known Region Table GUIDs ---------------------- */
static const MSGUID bat_guid = { .data1 = 0x2dc27766,
.data2 = 0xf623,
.data3 = 0x4200,
.data4 = { 0x9d, 0x64, 0x11, 0x5e,
0x9b, 0xfd, 0x4a, 0x08} };
static const MSGUID metadata_guid = { .data1 = 0x8b7ca206,
.data2 = 0x4790,
.data3 = 0x4b9a,
.data4 = { 0xb8, 0xfe, 0x57, 0x5f,
0x05, 0x0f, 0x88, 0x6e} };
/* ------- Known Metadata Entry GUIDs ---------------------- */
static const MSGUID file_param_guid = { .data1 = 0xcaa16737,
.data2 = 0xfa36,
.data3 = 0x4d43,
.data4 = { 0xb3, 0xb6, 0x33, 0xf0,
0xaa, 0x44, 0xe7, 0x6b} };
static const MSGUID virtual_size_guid = { .data1 = 0x2FA54224,
.data2 = 0xcd1b,
.data3 = 0x4876,
.data4 = { 0xb2, 0x11, 0x5d, 0xbe,
0xd8, 0x3b, 0xf4, 0xb8} };
static const MSGUID page83_guid = { .data1 = 0xbeca12ab,
.data2 = 0xb2e6,
.data3 = 0x4523,
.data4 = { 0x93, 0xef, 0xc3, 0x09,
0xe0, 0x00, 0xc7, 0x46} };
static const MSGUID phys_sector_guid = { .data1 = 0xcda348c7,
.data2 = 0x445d,
.data3 = 0x4471,
.data4 = { 0x9c, 0xc9, 0xe9, 0x88,
0x52, 0x51, 0xc5, 0x56} };
static const MSGUID parent_locator_guid = { .data1 = 0xa8d35f2d,
.data2 = 0xb30b,
.data3 = 0x454d,
.data4 = { 0xab, 0xf7, 0xd3,
0xd8, 0x48, 0x34,
0xab, 0x0c} };
static const MSGUID logical_sector_guid = { .data1 = 0x8141bf1d,
.data2 = 0xa96f,
.data3 = 0x4709,
.data4 = { 0xba, 0x47, 0xf2,
0x33, 0xa8, 0xfa,
0xab, 0x5f} };
/* Each parent type must have a valid GUID; this is for parent images
* of type 'VHDX'. If we were to allow e.g. a QCOW2 parent, we would
* need to make up our own QCOW2 GUID type */
static const MSGUID parent_vhdx_guid = { .data1 = 0xb04aefb7,
.data2 = 0xd19e,
.data3 = 0x4a81,
.data4 = { 0xb7, 0x89, 0x25, 0xb8,
0xe9, 0x44, 0x59, 0x13} };
#define META_FILE_PARAMETER_PRESENT 0x01
#define META_VIRTUAL_DISK_SIZE_PRESENT 0x02
#define META_PAGE_83_PRESENT 0x04
#define META_LOGICAL_SECTOR_SIZE_PRESENT 0x08
#define META_PHYS_SECTOR_SIZE_PRESENT 0x10
#define META_PARENT_LOCATOR_PRESENT 0x20
#define META_ALL_PRESENT \
(META_FILE_PARAMETER_PRESENT | META_VIRTUAL_DISK_SIZE_PRESENT | \
META_PAGE_83_PRESENT | META_LOGICAL_SECTOR_SIZE_PRESENT | \
META_PHYS_SECTOR_SIZE_PRESENT)
typedef struct VHDXMetadataEntries {
VHDXMetadataTableEntry file_parameters_entry;
VHDXMetadataTableEntry virtual_disk_size_entry;
VHDXMetadataTableEntry page83_data_entry;
VHDXMetadataTableEntry logical_sector_size_entry;
VHDXMetadataTableEntry phys_sector_size_entry;
VHDXMetadataTableEntry parent_locator_entry;
uint16_t present;
} VHDXMetadataEntries;
typedef struct VHDXSectorInfo {
uint32_t bat_idx; /* BAT entry index */
uint32_t sectors_avail; /* sectors available in payload block */
uint32_t bytes_left; /* bytes left in the block after data to r/w */
uint32_t bytes_avail; /* bytes available in payload block */
uint64_t file_offset; /* absolute offset in bytes, in file */
uint64_t block_offset; /* block offset, in bytes */
} VHDXSectorInfo;
typedef struct BDRVVHDXState {
CoMutex lock;
int curr_header;
VHDXHeader *headers[2];
VHDXRegionTableHeader rt;
VHDXRegionTableEntry bat_rt; /* region table for the BAT */
VHDXRegionTableEntry metadata_rt; /* region table for the metadata */
VHDXMetadataTableHeader metadata_hdr;
VHDXMetadataEntries metadata_entries;
VHDXFileParameters params;
uint32_t block_size;
uint32_t block_size_bits;
uint32_t sectors_per_block;
uint32_t sectors_per_block_bits;
uint64_t virtual_disk_size;
uint32_t logical_sector_size;
uint32_t physical_sector_size;
uint64_t chunk_ratio;
uint32_t chunk_ratio_bits;
uint32_t logical_sector_size_bits;
uint32_t bat_entries;
VHDXBatEntry *bat;
uint64_t bat_offset;
VHDXParentLocatorHeader parent_header;
VHDXParentLocatorEntry *parent_entries;
} BDRVVHDXState;
uint32_t vhdx_checksum_calc(uint32_t crc, uint8_t *buf, size_t size,
int crc_offset)
{
uint32_t crc_new;
uint32_t crc_orig;
assert(buf != NULL);
if (crc_offset > 0) {
memcpy(&crc_orig, buf + crc_offset, sizeof(crc_orig));
memset(buf + crc_offset, 0, sizeof(crc_orig));
}
crc_new = crc32c(crc, buf, size);
if (crc_offset > 0) {
memcpy(buf + crc_offset, &crc_orig, sizeof(crc_orig));
}
return crc_new;
}
/* Validates the checksum of the buffer, with an in-place CRC.
*
* Zero is substituted during crc calculation for the original crc field,
* and the crc field is restored afterwards. But the buffer will be modifed
* during the calculation, so this may not be not suitable for multi-threaded
* use.
*
* crc_offset: byte offset in buf of the buffer crc
* buf: buffer pointer
* size: size of buffer (must be > crc_offset+4)
*
* returns true if checksum is valid, false otherwise
*/
bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset)
{
uint32_t crc_orig;
uint32_t crc;
assert(buf != NULL);
assert(size > (crc_offset + 4));
memcpy(&crc_orig, buf + crc_offset, sizeof(crc_orig));
crc_orig = le32_to_cpu(crc_orig);
crc = vhdx_checksum_calc(0xffffffff, buf, size, crc_offset);
return crc == crc_orig;
}
/*
* Per the MS VHDX Specification, for every VHDX file:
* - The header section is fixed size - 1 MB
* - The header section is always the first "object"
* - The first 64KB of the header is the File Identifier
* - The first uint64 (8 bytes) is the VHDX Signature ("vhdxfile")
* - The following 512 bytes constitute a UTF-16 string identifiying the
* software that created the file, and is optional and diagnostic only.
*
* Therefore, we probe by looking for the vhdxfile signature "vhdxfile"
*/
static int vhdx_probe(const uint8_t *buf, int buf_size, const char *filename)
{
if (buf_size >= 8 && !memcmp(buf, "vhdxfile", 8)) {
return 100;
}
return 0;
}
/* All VHDX structures on disk are little endian */
static void vhdx_header_le_import(VHDXHeader *h)
{
assert(h != NULL);
le32_to_cpus(&h->signature);
le32_to_cpus(&h->checksum);
le64_to_cpus(&h->sequence_number);
leguid_to_cpus(&h->file_write_guid);
leguid_to_cpus(&h->data_write_guid);
leguid_to_cpus(&h->log_guid);
le16_to_cpus(&h->log_version);
le16_to_cpus(&h->version);
le32_to_cpus(&h->log_length);
le64_to_cpus(&h->log_offset);
}
/* opens the specified header block from the VHDX file header section */
static int vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s)
{
int ret = 0;
VHDXHeader *header1;
VHDXHeader *header2;
bool h1_valid = false;
bool h2_valid = false;
uint64_t h1_seq = 0;
uint64_t h2_seq = 0;
uint8_t *buffer;
header1 = qemu_blockalign(bs, sizeof(VHDXHeader));
header2 = qemu_blockalign(bs, sizeof(VHDXHeader));
buffer = qemu_blockalign(bs, VHDX_HEADER_SIZE);
s->headers[0] = header1;
s->headers[1] = header2;
/* We have to read the whole VHDX_HEADER_SIZE instead of
* sizeof(VHDXHeader), because the checksum is over the whole
* region */
ret = bdrv_pread(bs->file, VHDX_HEADER1_OFFSET, buffer, VHDX_HEADER_SIZE);
if (ret < 0) {
goto fail;
}
/* copy over just the relevant portion that we need */
memcpy(header1, buffer, sizeof(VHDXHeader));
vhdx_header_le_import(header1);
if (vhdx_checksum_is_valid(buffer, VHDX_HEADER_SIZE, 4) &&
!memcmp(&header1->signature, "head", 4) &&
header1->version == 1) {
h1_seq = header1->sequence_number;
h1_valid = true;
}
ret = bdrv_pread(bs->file, VHDX_HEADER2_OFFSET, buffer, VHDX_HEADER_SIZE);
if (ret < 0) {
goto fail;
}
/* copy over just the relevant portion that we need */
memcpy(header2, buffer, sizeof(VHDXHeader));
vhdx_header_le_import(header2);
if (vhdx_checksum_is_valid(buffer, VHDX_HEADER_SIZE, 4) &&
!memcmp(&header2->signature, "head", 4) &&
header2->version == 1) {
h2_seq = header2->sequence_number;
h2_valid = true;
}
/* If there is only 1 valid header (or no valid headers), we
* don't care what the sequence numbers are */
if (h1_valid && !h2_valid) {
s->curr_header = 0;
} else if (!h1_valid && h2_valid) {
s->curr_header = 1;
} else if (!h1_valid && !h2_valid) {
ret = -EINVAL;
goto fail;
} else {
/* If both headers are valid, then we choose the active one by the
* highest sequence number. If the sequence numbers are equal, that is
* invalid */
if (h1_seq > h2_seq) {
s->curr_header = 0;
} else if (h2_seq > h1_seq) {
s->curr_header = 1;
} else {
ret = -EINVAL;
goto fail;
}
}
ret = 0;
goto exit;
fail:
qerror_report(ERROR_CLASS_GENERIC_ERROR, "No valid VHDX header found");
qemu_vfree(header1);
qemu_vfree(header2);
s->headers[0] = NULL;
s->headers[1] = NULL;
exit:
qemu_vfree(buffer);
return ret;
}
static int vhdx_open_region_tables(BlockDriverState *bs, BDRVVHDXState *s)
{
int ret = 0;
uint8_t *buffer;
int offset = 0;
VHDXRegionTableEntry rt_entry;
uint32_t i;
bool bat_rt_found = false;
bool metadata_rt_found = false;
/* We have to read the whole 64KB block, because the crc32 is over the
* whole block */
buffer = qemu_blockalign(bs, VHDX_HEADER_BLOCK_SIZE);
ret = bdrv_pread(bs->file, VHDX_REGION_TABLE_OFFSET, buffer,
VHDX_HEADER_BLOCK_SIZE);
if (ret < 0) {
goto fail;
}
memcpy(&s->rt, buffer, sizeof(s->rt));
le32_to_cpus(&s->rt.signature);
le32_to_cpus(&s->rt.checksum);
le32_to_cpus(&s->rt.entry_count);
le32_to_cpus(&s->rt.reserved);
offset += sizeof(s->rt);
if (!vhdx_checksum_is_valid(buffer, VHDX_HEADER_BLOCK_SIZE, 4) ||
memcmp(&s->rt.signature, "regi", 4)) {
ret = -EINVAL;
goto fail;
}
/* Per spec, maximum region table entry count is 2047 */
if (s->rt.entry_count > 2047) {
ret = -EINVAL;
goto fail;
}
for (i = 0; i < s->rt.entry_count; i++) {
memcpy(&rt_entry, buffer + offset, sizeof(rt_entry));
offset += sizeof(rt_entry);
leguid_to_cpus(&rt_entry.guid);
le64_to_cpus(&rt_entry.file_offset);
le32_to_cpus(&rt_entry.length);
le32_to_cpus(&rt_entry.data_bits);
/* see if we recognize the entry */
if (guid_eq(rt_entry.guid, bat_guid)) {
/* must be unique; if we have already found it this is invalid */
if (bat_rt_found) {
ret = -EINVAL;
goto fail;
}
bat_rt_found = true;
s->bat_rt = rt_entry;
continue;
}
if (guid_eq(rt_entry.guid, metadata_guid)) {
/* must be unique; if we have already found it this is invalid */
if (metadata_rt_found) {
ret = -EINVAL;
goto fail;
}
metadata_rt_found = true;
s->metadata_rt = rt_entry;
continue;
}
if (rt_entry.data_bits & VHDX_REGION_ENTRY_REQUIRED) {
/* cannot read vhdx file - required region table entry that
* we do not understand. per spec, we must fail to open */
ret = -ENOTSUP;
goto fail;
}
}
ret = 0;
fail:
qemu_vfree(buffer);
return ret;
}
/* Metadata initial parser
*
* This loads all the metadata entry fields. This may cause additional
* fields to be processed (e.g. parent locator, etc..).
*
* There are 5 Metadata items that are always required:
* - File Parameters (block size, has a parent)
* - Virtual Disk Size (size, in bytes, of the virtual drive)
* - Page 83 Data (scsi page 83 guid)
* - Logical Sector Size (logical sector size in bytes, either 512 or
* 4096. We only support 512 currently)
* - Physical Sector Size (512 or 4096)
*
* Also, if the File Parameters indicate this is a differencing file,
* we must also look for the Parent Locator metadata item.
*/
static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
{
int ret = 0;
uint8_t *buffer;
int offset = 0;
uint32_t i = 0;
VHDXMetadataTableEntry md_entry;
buffer = qemu_blockalign(bs, VHDX_METADATA_TABLE_MAX_SIZE);
ret = bdrv_pread(bs->file, s->metadata_rt.file_offset, buffer,
VHDX_METADATA_TABLE_MAX_SIZE);
if (ret < 0) {
goto exit;
}
memcpy(&s->metadata_hdr, buffer, sizeof(s->metadata_hdr));
offset += sizeof(s->metadata_hdr);
le64_to_cpus(&s->metadata_hdr.signature);
le16_to_cpus(&s->metadata_hdr.reserved);
le16_to_cpus(&s->metadata_hdr.entry_count);
if (memcmp(&s->metadata_hdr.signature, "metadata", 8)) {
ret = -EINVAL;
goto exit;
}
s->metadata_entries.present = 0;
if ((s->metadata_hdr.entry_count * sizeof(md_entry)) >
(VHDX_METADATA_TABLE_MAX_SIZE - offset)) {
ret = -EINVAL;
goto exit;
}
for (i = 0; i < s->metadata_hdr.entry_count; i++) {
memcpy(&md_entry, buffer + offset, sizeof(md_entry));
offset += sizeof(md_entry);
leguid_to_cpus(&md_entry.item_id);
le32_to_cpus(&md_entry.offset);
le32_to_cpus(&md_entry.length);
le32_to_cpus(&md_entry.data_bits);
le32_to_cpus(&md_entry.reserved2);
if (guid_eq(md_entry.item_id, file_param_guid)) {
if (s->metadata_entries.present & META_FILE_PARAMETER_PRESENT) {
ret = -EINVAL;
goto exit;
}
s->metadata_entries.file_parameters_entry = md_entry;
s->metadata_entries.present |= META_FILE_PARAMETER_PRESENT;
continue;
}
if (guid_eq(md_entry.item_id, virtual_size_guid)) {
if (s->metadata_entries.present & META_VIRTUAL_DISK_SIZE_PRESENT) {
ret = -EINVAL;
goto exit;
}
s->metadata_entries.virtual_disk_size_entry = md_entry;
s->metadata_entries.present |= META_VIRTUAL_DISK_SIZE_PRESENT;
continue;
}
if (guid_eq(md_entry.item_id, page83_guid)) {
if (s->metadata_entries.present & META_PAGE_83_PRESENT) {
ret = -EINVAL;
goto exit;
}
s->metadata_entries.page83_data_entry = md_entry;
s->metadata_entries.present |= META_PAGE_83_PRESENT;
continue;
}
if (guid_eq(md_entry.item_id, logical_sector_guid)) {
if (s->metadata_entries.present &
META_LOGICAL_SECTOR_SIZE_PRESENT) {
ret = -EINVAL;
goto exit;
}
s->metadata_entries.logical_sector_size_entry = md_entry;
s->metadata_entries.present |= META_LOGICAL_SECTOR_SIZE_PRESENT;
continue;
}
if (guid_eq(md_entry.item_id, phys_sector_guid)) {
if (s->metadata_entries.present & META_PHYS_SECTOR_SIZE_PRESENT) {
ret = -EINVAL;
goto exit;
}
s->metadata_entries.phys_sector_size_entry = md_entry;
s->metadata_entries.present |= META_PHYS_SECTOR_SIZE_PRESENT;
continue;
}
if (guid_eq(md_entry.item_id, parent_locator_guid)) {
if (s->metadata_entries.present & META_PARENT_LOCATOR_PRESENT) {
ret = -EINVAL;
goto exit;
}
s->metadata_entries.parent_locator_entry = md_entry;
s->metadata_entries.present |= META_PARENT_LOCATOR_PRESENT;
continue;
}
if (md_entry.data_bits & VHDX_META_FLAGS_IS_REQUIRED) {
/* cannot read vhdx file - required region table entry that
* we do not understand. per spec, we must fail to open */
ret = -ENOTSUP;
goto exit;
}
}
if (s->metadata_entries.present != META_ALL_PRESENT) {
ret = -ENOTSUP;
goto exit;
}
ret = bdrv_pread(bs->file,
s->metadata_entries.file_parameters_entry.offset
+ s->metadata_rt.file_offset,
&s->params,
sizeof(s->params));
if (ret < 0) {
goto exit;
}
le32_to_cpus(&s->params.block_size);
le32_to_cpus(&s->params.data_bits);
/* We now have the file parameters, so we can tell if this is a
* differencing file (i.e.. has_parent), is dynamic or fixed
* sized (leave_blocks_allocated), and the block size */
/* The parent locator required iff the file parameters has_parent set */
if (s->params.data_bits & VHDX_PARAMS_HAS_PARENT) {
if (s->metadata_entries.present & META_PARENT_LOCATOR_PRESENT) {
/* TODO: parse parent locator fields */
ret = -ENOTSUP; /* temp, until differencing files are supported */
goto exit;
} else {
/* if has_parent is set, but there is not parent locator present,
* then that is an invalid combination */
ret = -EINVAL;
goto exit;
}
}
/* determine virtual disk size, logical sector size,
* and phys sector size */
ret = bdrv_pread(bs->file,
s->metadata_entries.virtual_disk_size_entry.offset
+ s->metadata_rt.file_offset,
&s->virtual_disk_size,
sizeof(uint64_t));
if (ret < 0) {
goto exit;
}
ret = bdrv_pread(bs->file,
s->metadata_entries.logical_sector_size_entry.offset
+ s->metadata_rt.file_offset,
&s->logical_sector_size,
sizeof(uint32_t));
if (ret < 0) {
goto exit;
}
ret = bdrv_pread(bs->file,
s->metadata_entries.phys_sector_size_entry.offset
+ s->metadata_rt.file_offset,
&s->physical_sector_size,
sizeof(uint32_t));
if (ret < 0) {
goto exit;
}
le64_to_cpus(&s->virtual_disk_size);
le32_to_cpus(&s->logical_sector_size);
le32_to_cpus(&s->physical_sector_size);
if (s->logical_sector_size == 0 || s->params.block_size == 0) {
ret = -EINVAL;
goto exit;
}
/* both block_size and sector_size are guaranteed powers of 2 */
s->sectors_per_block = s->params.block_size / s->logical_sector_size;
s->chunk_ratio = (VHDX_MAX_SECTORS_PER_BLOCK) *
(uint64_t)s->logical_sector_size /
(uint64_t)s->params.block_size;
/* These values are ones we will want to use for division / multiplication
* later on, and they are all guaranteed (per the spec) to be powers of 2,
* so we can take advantage of that for shift operations during
* reads/writes */
if (s->logical_sector_size & (s->logical_sector_size - 1)) {
ret = -EINVAL;
goto exit;
}
if (s->sectors_per_block & (s->sectors_per_block - 1)) {
ret = -EINVAL;
goto exit;
}
if (s->chunk_ratio & (s->chunk_ratio - 1)) {
ret = -EINVAL;
goto exit;
}
s->block_size = s->params.block_size;
if (s->block_size & (s->block_size - 1)) {
ret = -EINVAL;
goto exit;
}
s->logical_sector_size_bits = 31 - clz32(s->logical_sector_size);
s->sectors_per_block_bits = 31 - clz32(s->sectors_per_block);
s->chunk_ratio_bits = 63 - clz64(s->chunk_ratio);
s->block_size_bits = 31 - clz32(s->block_size);
ret = 0;
exit:
qemu_vfree(buffer);
return ret;
}
/* Parse the replay log. Per the VHDX spec, if the log is present
* it must be replayed prior to opening the file, even read-only.
*
* If read-only, we must replay the log in RAM (or refuse to open
* a dirty VHDX file read-only */
static int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s)
{
int ret = 0;
int i;
VHDXHeader *hdr;
hdr = s->headers[s->curr_header];
/* either the log guid, or log length is zero,
* then a replay log is present */
for (i = 0; i < sizeof(hdr->log_guid.data4); i++) {
ret |= hdr->log_guid.data4[i];
}
if (hdr->log_guid.data1 == 0 &&
hdr->log_guid.data2 == 0 &&
hdr->log_guid.data3 == 0 &&
ret == 0) {
goto exit;
}
/* per spec, only log version of 0 is supported */
if (hdr->log_version != 0) {
ret = -EINVAL;
goto exit;
}
if (hdr->log_length == 0) {
goto exit;
}
/* We currently do not support images with logs to replay */
ret = -ENOTSUP;
exit:
return ret;
}
static int vhdx_open(BlockDriverState *bs, QDict *options, int flags)
{
BDRVVHDXState *s = bs->opaque;
int ret = 0;
uint32_t i;
uint64_t signature;
uint32_t data_blocks_cnt, bitmap_blocks_cnt;
s->bat = NULL;
qemu_co_mutex_init(&s->lock);
/* validate the file signature */
ret = bdrv_pread(bs->file, 0, &signature, sizeof(uint64_t));
if (ret < 0) {
goto fail;
}
if (memcmp(&signature, "vhdxfile", 8)) {
ret = -EINVAL;
goto fail;
}
ret = vhdx_parse_header(bs, s);
if (ret) {
goto fail;
}
ret = vhdx_parse_log(bs, s);
if (ret) {
goto fail;
}
ret = vhdx_open_region_tables(bs, s);
if (ret) {
goto fail;
}
ret = vhdx_parse_metadata(bs, s);
if (ret) {
goto fail;
}
s->block_size = s->params.block_size;
/* the VHDX spec dictates that virtual_disk_size is always a multiple of
* logical_sector_size */
bs->total_sectors = s->virtual_disk_size >> s->logical_sector_size_bits;
data_blocks_cnt = s->virtual_disk_size >> s->block_size_bits;
if (s->virtual_disk_size - (data_blocks_cnt << s->block_size_bits)) {
data_blocks_cnt++;
}
bitmap_blocks_cnt = data_blocks_cnt >> s->chunk_ratio_bits;
if (data_blocks_cnt - (bitmap_blocks_cnt << s->chunk_ratio_bits)) {
bitmap_blocks_cnt++;
}
if (s->parent_entries) {
s->bat_entries = bitmap_blocks_cnt * (s->chunk_ratio + 1);
} else {
s->bat_entries = data_blocks_cnt +
((data_blocks_cnt - 1) >> s->chunk_ratio_bits);
}
s->bat_offset = s->bat_rt.file_offset;
if (s->bat_entries > s->bat_rt.length / sizeof(VHDXBatEntry)) {
/* BAT allocation is not large enough for all entries */
ret = -EINVAL;
goto fail;
}
s->bat = qemu_blockalign(bs, s->bat_rt.length);
ret = bdrv_pread(bs->file, s->bat_offset, s->bat, s->bat_rt.length);
if (ret < 0) {
goto fail;
}
for (i = 0; i < s->bat_entries; i++) {
le64_to_cpus(&s->bat[i]);
}
if (flags & BDRV_O_RDWR) {
ret = -ENOTSUP;
goto fail;
}
/* TODO: differencing files, write */
return 0;
fail:
qemu_vfree(s->headers[0]);
qemu_vfree(s->headers[1]);
qemu_vfree(s->bat);
qemu_vfree(s->parent_entries);
return ret;
}
static int vhdx_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
return 0;
}
/*
* Perform sector to block offset translations, to get various
* sector and file offsets into the image. See VHDXSectorInfo
*/
static void vhdx_block_translate(BDRVVHDXState *s, int64_t sector_num,
int nb_sectors, VHDXSectorInfo *sinfo)
{
uint32_t block_offset;
sinfo->bat_idx = sector_num >> s->sectors_per_block_bits;
/* effectively a modulo - this gives us the offset into the block
* (in sector sizes) for our sector number */
block_offset = sector_num - (sinfo->bat_idx << s->sectors_per_block_bits);
/* the chunk ratio gives us the interleaving of the sector
* bitmaps, so we need to advance our page block index by the
* sector bitmaps entry number */
sinfo->bat_idx += sinfo->bat_idx >> s->chunk_ratio_bits;
/* the number of sectors we can read/write in this cycle */
sinfo->sectors_avail = s->sectors_per_block - block_offset;
sinfo->bytes_left = sinfo->sectors_avail << s->logical_sector_size_bits;
if (sinfo->sectors_avail > nb_sectors) {
sinfo->sectors_avail = nb_sectors;
}
sinfo->bytes_avail = sinfo->sectors_avail << s->logical_sector_size_bits;
sinfo->file_offset = s->bat[sinfo->bat_idx] >> VHDX_BAT_FILE_OFF_BITS;
sinfo->block_offset = block_offset << s->logical_sector_size_bits;
/* The file offset must be past the header section, so must be > 0 */
if (sinfo->file_offset == 0) {
return;
}
/* block offset is the offset in vhdx logical sectors, in
* the payload data block. Convert that to a byte offset
* in the block, and add in the payload data block offset
* in the file, in bytes, to get the final read address */
sinfo->file_offset <<= 20; /* now in bytes, rather than 1MB units */
sinfo->file_offset += sinfo->block_offset;
}
static coroutine_fn int vhdx_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
BDRVVHDXState *s = bs->opaque;
int ret = 0;
VHDXSectorInfo sinfo;
uint64_t bytes_done = 0;
QEMUIOVector hd_qiov;
qemu_iovec_init(&hd_qiov, qiov->niov);
qemu_co_mutex_lock(&s->lock);
while (nb_sectors > 0) {
/* We are a differencing file, so we need to inspect the sector bitmap
* to see if we have the data or not */
if (s->params.data_bits & VHDX_PARAMS_HAS_PARENT) {
/* not supported yet */
ret = -ENOTSUP;
goto exit;
} else {
vhdx_block_translate(s, sector_num, nb_sectors, &sinfo);
qemu_iovec_reset(&hd_qiov);
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, sinfo.bytes_avail);
/* check the payload block state */
switch (s->bat[sinfo.bat_idx] & VHDX_BAT_STATE_BIT_MASK) {
case PAYLOAD_BLOCK_NOT_PRESENT: /* fall through */
case PAYLOAD_BLOCK_UNDEFINED: /* fall through */
case PAYLOAD_BLOCK_UNMAPPED: /* fall through */
case PAYLOAD_BLOCK_ZERO:
/* return zero */
qemu_iovec_memset(&hd_qiov, 0, 0, sinfo.bytes_avail);
break;
case PAYLOAD_BLOCK_FULL_PRESENT:
qemu_co_mutex_unlock(&s->lock);
ret = bdrv_co_readv(bs->file,
sinfo.file_offset >> BDRV_SECTOR_BITS,
sinfo.sectors_avail, &hd_qiov);
qemu_co_mutex_lock(&s->lock);
if (ret < 0) {
goto exit;
}
break;
case PAYLOAD_BLOCK_PARTIALLY_PRESENT:
/* we don't yet support difference files, fall through
* to error */
default:
ret = -EIO;
goto exit;
break;
}
nb_sectors -= sinfo.sectors_avail;
sector_num += sinfo.sectors_avail;
bytes_done += sinfo.bytes_avail;
}
}
ret = 0;
exit:
qemu_co_mutex_unlock(&s->lock);
qemu_iovec_destroy(&hd_qiov);
return ret;
}
static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
return -ENOTSUP;
}
static void vhdx_close(BlockDriverState *bs)
{
BDRVVHDXState *s = bs->opaque;
qemu_vfree(s->headers[0]);
qemu_vfree(s->headers[1]);
qemu_vfree(s->bat);
qemu_vfree(s->parent_entries);
}
static BlockDriver bdrv_vhdx = {
.format_name = "vhdx",
.instance_size = sizeof(BDRVVHDXState),
.bdrv_probe = vhdx_probe,
.bdrv_open = vhdx_open,
.bdrv_close = vhdx_close,
.bdrv_reopen_prepare = vhdx_reopen_prepare,
.bdrv_co_readv = vhdx_co_readv,
.bdrv_co_writev = vhdx_co_writev,
};
static void bdrv_vhdx_init(void)
{
bdrv_register(&bdrv_vhdx);
}
block_init(bdrv_vhdx_init);

View File

@@ -1,325 +0,0 @@
/*
* Block driver for Hyper-V VHDX Images
*
* Copyright (c) 2013 Red Hat, Inc.,
*
* Authors:
* Jeff Cody <jcody@redhat.com>
*
* This is based on the "VHDX Format Specification v0.95", published 4/12/2012
* by Microsoft:
* https://www.microsoft.com/en-us/download/details.aspx?id=29681
*
* This work is licensed under the terms of the GNU LGPL, version 2 or later.
* See the COPYING.LIB file in the top-level directory.
*
*/
#ifndef BLOCK_VHDX_H
#define BLOCK_VHDX_H
/* Structures and fields present in the VHDX file */
/* The header section has the following blocks,
* each block is 64KB:
*
* _____________________________________________________________________________
* | File Id. | Header 1 | Header 2 | Region Table | Reserved (768KB) |
* |----------|---------------|------------|--------------|--------------------|
* | | | | | |
* 0.........64KB...........128KB........192KB..........256KB................1MB
*/
#define VHDX_HEADER_BLOCK_SIZE (64*1024)
#define VHDX_FILE_ID_OFFSET 0
#define VHDX_HEADER1_OFFSET (VHDX_HEADER_BLOCK_SIZE*1)
#define VHDX_HEADER2_OFFSET (VHDX_HEADER_BLOCK_SIZE*2)
#define VHDX_REGION_TABLE_OFFSET (VHDX_HEADER_BLOCK_SIZE*3)
/*
* A note on the use of MS-GUID fields. For more details on the GUID,
* please see: https://en.wikipedia.org/wiki/Globally_unique_identifier.
*
* The VHDX specification only states that these are MS GUIDs, and which
* bytes are data1-data4. It makes no mention of what algorithm should be used
* to generate the GUID, nor what standard. However, looking at the specified
* known GUID fields, it appears the GUIDs are:
* Standard/DCE GUID type (noted by 10b in the MSB of byte 0 of .data4)
* Random algorithm (noted by 0x4XXX for .data3)
*/
/* ---- HEADER SECTION STRUCTURES ---- */
/* These structures are ones that are defined in the VHDX specification
* document */
typedef struct VHDXFileIdentifier {
uint64_t signature; /* "vhdxfile" in ASCII */
uint16_t creator[256]; /* optional; utf-16 string to identify
the vhdx file creator. Diagnotistic
only */
} VHDXFileIdentifier;
/* the guid is a 16 byte unique ID - the definition for this used by
* Microsoft is not just 16 bytes though - it is a structure that is defined,
* so we need to follow it here so that endianness does not trip us up */
typedef struct MSGUID {
uint32_t data1;
uint16_t data2;
uint16_t data3;
uint8_t data4[8];
} MSGUID;
#define guid_eq(a, b) \
(memcmp(&(a), &(b), sizeof(MSGUID)) == 0)
#define VHDX_HEADER_SIZE (4*1024) /* although the vhdx_header struct in disk
is only 582 bytes, for purposes of crc
the header is the first 4KB of the 64KB
block */
/* The full header is 4KB, although the actual header data is much smaller.
* But for the checksum calculation, it is over the entire 4KB structure,
* not just the defined portion of it */
typedef struct QEMU_PACKED VHDXHeader {
uint32_t signature; /* "head" in ASCII */
uint32_t checksum; /* CRC-32C hash of the whole header */
uint64_t sequence_number; /* Seq number of this header. Each
VHDX file has 2 of these headers,
and only the header with the highest
sequence number is valid */
MSGUID file_write_guid; /* 128 bit unique identifier. Must be
updated to new, unique value before
the first modification is made to
file */
MSGUID data_write_guid; /* 128 bit unique identifier. Must be
updated to new, unique value before
the first modification is made to
visible data. Visbile data is
defined as:
- system & user metadata
- raw block data
- disk size
- any change that will
cause the virtual disk
sector read to differ
This does not need to change if
blocks are re-arranged */
MSGUID log_guid; /* 128 bit unique identifier. If zero,
there is no valid log. If non-zero,
log entries with this guid are
valid. */
uint16_t log_version; /* version of the log format. Mustn't be
zero, unless log_guid is also zero */
uint16_t version; /* version of th evhdx file. Currently,
only supported version is "1" */
uint32_t log_length; /* length of the log. Must be multiple
of 1MB */
uint64_t log_offset; /* byte offset in the file of the log.
Must also be a multiple of 1MB */
} VHDXHeader;
/* Header for the region table block */
typedef struct QEMU_PACKED VHDXRegionTableHeader {
uint32_t signature; /* "regi" in ASCII */
uint32_t checksum; /* CRC-32C hash of the 64KB table */
uint32_t entry_count; /* number of valid entries */
uint32_t reserved;
} VHDXRegionTableHeader;
/* Individual region table entry. There may be a maximum of 2047 of these
*
* There are two known region table properties. Both are required.
* BAT (block allocation table): 2DC27766F62342009D64115E9BFD4A08
* Metadata: 8B7CA20647904B9AB8FE575F050F886E
*/
#define VHDX_REGION_ENTRY_REQUIRED 0x01 /* if set, parser must understand
this entry in order to open
file */
typedef struct QEMU_PACKED VHDXRegionTableEntry {
MSGUID guid; /* 128-bit unique identifier */
uint64_t file_offset; /* offset of the object in the file.
Must be multiple of 1MB */
uint32_t length; /* length, in bytes, of the object */
uint32_t data_bits;
} VHDXRegionTableEntry;
/* ---- LOG ENTRY STRUCTURES ---- */
#define VHDX_LOG_HDR_SIZE 64
typedef struct QEMU_PACKED VHDXLogEntryHeader {
uint32_t signature; /* "loge" in ASCII */
uint32_t checksum; /* CRC-32C hash of the 64KB table */
uint32_t entry_length; /* length in bytes, multiple of 1MB */
uint32_t tail; /* byte offset of first log entry of a
seq, where this entry is the last
entry */
uint64_t sequence_number; /* incremented with each log entry.
May not be zero. */
uint32_t descriptor_count; /* number of descriptors in this log
entry, must be >= 0 */
uint32_t reserved;
MSGUID log_guid; /* value of the log_guid from
vhdx_header. If not found in
vhdx_header, it is invalid */
uint64_t flushed_file_offset; /* see spec for full details - this
sould be vhdx file size in bytes */
uint64_t last_file_offset; /* size in bytes that all allocated
file structures fit into */
} VHDXLogEntryHeader;
#define VHDX_LOG_DESC_SIZE 32
typedef struct QEMU_PACKED VHDXLogDescriptor {
uint32_t signature; /* "zero" or "desc" in ASCII */
union {
uint32_t reserved; /* zero desc */
uint32_t trailing_bytes; /* data desc: bytes 4092-4096 of the
data sector */
};
union {
uint64_t zero_length; /* zero desc: length of the section to
zero */
uint64_t leading_bytes; /* data desc: bytes 0-7 of the data
sector */
};
uint64_t file_offset; /* file offset to write zeros - multiple
of 4kB */
uint64_t sequence_number; /* must match same field in
vhdx_log_entry_header */
} VHDXLogDescriptor;
typedef struct QEMU_PACKED VHDXLogDataSector {
uint32_t data_signature; /* "data" in ASCII */
uint32_t sequence_high; /* 4 MSB of 8 byte sequence_number */
uint8_t data[4084]; /* raw data, bytes 8-4091 (inclusive).
see the data descriptor field for the
other mising bytes */
uint32_t sequence_low; /* 4 LSB of 8 byte sequence_number */
} VHDXLogDataSector;
/* block states - different state values depending on whether it is a
* payload block, or a sector block. */
#define PAYLOAD_BLOCK_NOT_PRESENT 0
#define PAYLOAD_BLOCK_UNDEFINED 1
#define PAYLOAD_BLOCK_ZERO 2
#define PAYLOAD_BLOCK_UNMAPPED 5
#define PAYLOAD_BLOCK_FULL_PRESENT 6
#define PAYLOAD_BLOCK_PARTIALLY_PRESENT 7
#define SB_BLOCK_NOT_PRESENT 0
#define SB_BLOCK_PRESENT 6
/* per the spec */
#define VHDX_MAX_SECTORS_PER_BLOCK (1<<23)
/* upper 44 bits are the file offset in 1MB units lower 3 bits are the state
other bits are reserved */
#define VHDX_BAT_STATE_BIT_MASK 0x07
#define VHDX_BAT_FILE_OFF_BITS (64-44)
typedef uint64_t VHDXBatEntry;
/* ---- METADATA REGION STRUCTURES ---- */
#define VHDX_METADATA_ENTRY_SIZE 32
#define VHDX_METADATA_MAX_ENTRIES 2047 /* not including the header */
#define VHDX_METADATA_TABLE_MAX_SIZE \
(VHDX_METADATA_ENTRY_SIZE * (VHDX_METADATA_MAX_ENTRIES+1))
typedef struct QEMU_PACKED VHDXMetadataTableHeader {
uint64_t signature; /* "metadata" in ASCII */
uint16_t reserved;
uint16_t entry_count; /* number table entries. <= 2047 */
uint32_t reserved2[5];
} VHDXMetadataTableHeader;
#define VHDX_META_FLAGS_IS_USER 0x01 /* max 1024 entries */
#define VHDX_META_FLAGS_IS_VIRTUAL_DISK 0x02 /* virtual disk metadata if set,
otherwise file metdata */
#define VHDX_META_FLAGS_IS_REQUIRED 0x04 /* parse must understand this
entry to open the file */
typedef struct QEMU_PACKED VHDXMetadataTableEntry {
MSGUID item_id; /* 128-bit identifier for metadata */
uint32_t offset; /* byte offset of the metadata. At
least 64kB. Relative to start of
metadata region */
/* note: if length = 0, so is offset */
uint32_t length; /* length of metadata. <= 1MB. */
uint32_t data_bits; /* least-significant 3 bits are flags, the
rest are reserved (see above) */
uint32_t reserved2;
} VHDXMetadataTableEntry;
#define VHDX_PARAMS_LEAVE_BLOCKS_ALLOCED 0x01 /* Do not change any blocks to
be BLOCK_NOT_PRESENT.
If set indicates a fixed
size VHDX file */
#define VHDX_PARAMS_HAS_PARENT 0x02 /* has parent / backing file */
typedef struct QEMU_PACKED VHDXFileParameters {
uint32_t block_size; /* size of each payload block, always
power of 2, <= 256MB and >= 1MB. */
uint32_t data_bits; /* least-significant 2 bits are flags, the rest
are reserved (see above) */
} VHDXFileParameters;
typedef struct QEMU_PACKED VHDXVirtualDiskSize {
uint64_t virtual_disk_size; /* Size of the virtual disk, in bytes.
Must be multiple of the sector size,
max of 64TB */
} VHDXVirtualDiskSize;
typedef struct QEMU_PACKED VHDXPage83Data {
MSGUID page_83_data[16]; /* unique id for scsi devices that
support page 0x83 */
} VHDXPage83Data;
typedef struct QEMU_PACKED VHDXVirtualDiskLogicalSectorSize {
uint32_t logical_sector_size; /* virtual disk sector size (in bytes).
Can only be 512 or 4096 bytes */
} VHDXVirtualDiskLogicalSectorSize;
typedef struct QEMU_PACKED VHDXVirtualDiskPhysicalSectorSize {
uint32_t physical_sector_size; /* physical sector size (in bytes).
Can only be 512 or 4096 bytes */
} VHDXVirtualDiskPhysicalSectorSize;
typedef struct QEMU_PACKED VHDXParentLocatorHeader {
MSGUID locator_type[16]; /* type of the parent virtual disk. */
uint16_t reserved;
uint16_t key_value_count; /* number of key/value pairs for this
locator */
} VHDXParentLocatorHeader;
/* key and value strings are UNICODE strings, UTF-16 LE encoding, no NULs */
typedef struct QEMU_PACKED VHDXParentLocatorEntry {
uint32_t key_offset; /* offset in metadata for key, > 0 */
uint32_t value_offset; /* offset in metadata for value, >0 */
uint16_t key_length; /* length of entry key, > 0 */
uint16_t value_length; /* length of entry value, > 0 */
} VHDXParentLocatorEntry;
/* ----- END VHDX SPECIFICATION STRUCTURES ---- */
uint32_t vhdx_checksum_calc(uint32_t crc, uint8_t *buf, size_t size,
int crc_offset);
bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset);
static void leguid_to_cpus(MSGUID *guid)
{
le32_to_cpus(&guid->data1);
le16_to_cpus(&guid->data2);
le16_to_cpus(&guid->data3);
}
#endif

View File

@@ -32,25 +32,11 @@
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
#define VMDK4_COMPRESSION_DEFLATE 1
#define VMDK4_FLAG_NL_DETECT (1 << 0)
#define VMDK4_FLAG_RGD (1 << 1)
/* Zeroed-grain enable bit */
#define VMDK4_FLAG_ZERO_GRAIN (1 << 2)
#define VMDK4_FLAG_COMPRESS (1 << 16)
#define VMDK4_FLAG_MARKER (1 << 17)
#define VMDK4_GD_AT_END 0xffffffffffffffffULL
#define VMDK_GTE_ZEROED 0x1
/* VMDK internal error codes */
#define VMDK_OK 0
#define VMDK_ERROR (-1)
/* Cluster not allocated */
#define VMDK_UNALLOC (-2)
#define VMDK_ZEROED (-3)
#define BLOCK_OPT_ZEROED_GRAIN "zeroed_grain"
typedef struct {
uint32_t version;
uint32_t flags;
@@ -87,8 +73,6 @@ typedef struct VmdkExtent {
bool flat;
bool compressed;
bool has_marker;
bool has_zero_grain;
int version;
int64_t sectors;
int64_t end_sector;
int64_t flat_start_offset;
@@ -124,7 +108,6 @@ typedef struct VmdkMetaData {
unsigned int l2_index;
unsigned int l2_offset;
int valid;
uint32_t *l2_cache_entry;
} VmdkMetaData;
typedef struct VmdkGrainMarker {
@@ -507,11 +490,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
if (ret < 0) {
return ret;
}
if (header.capacity == 0) {
int64_t desc_offset = le64_to_cpu(header.desc_offset);
if (desc_offset) {
return vmdk_open_desc_file(bs, flags, desc_offset << 9);
}
if (header.capacity == 0 && header.desc_offset) {
return vmdk_open_desc_file(bs, flags, header.desc_offset << 9);
}
if (le64_to_cpu(header.gd_offset) == VMDK4_GD_AT_END) {
@@ -581,8 +561,6 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
extent->compressed =
le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE;
extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER;
extent->version = le32_to_cpu(header.version);
extent->has_zero_grain = le32_to_cpu(header.flags) & VMDK4_FLAG_ZERO_GRAIN;
ret = vmdk_init_tables(bs, extent);
if (ret) {
/* free extent allocated by vmdk_add_extent */
@@ -600,22 +578,22 @@ static int vmdk_parse_description(const char *desc, const char *opt_name,
opt_pos = strstr(desc, opt_name);
if (!opt_pos) {
return VMDK_ERROR;
return -1;
}
/* Skip "=\"" following opt_name */
opt_pos += strlen(opt_name) + 2;
if (opt_pos >= end) {
return VMDK_ERROR;
return -1;
}
opt_end = opt_pos;
while (opt_end < end && *opt_end != '"') {
opt_end++;
}
if (opt_end == end || buf_size < opt_end - opt_pos + 1) {
return VMDK_ERROR;
return -1;
}
pstrcpy(buf, opt_end - opt_pos + 1, opt_pos);
return VMDK_OK;
return 0;
}
/* Open an extent file and append to bs array */
@@ -683,7 +661,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
path_combine(extent_path, sizeof(extent_path),
desc_file_path, fname);
ret = bdrv_file_open(&extent_file, extent_path, NULL, bs->open_flags);
ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags);
if (ret) {
return ret;
}
@@ -745,7 +723,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
return vmdk_parse_extents(buf, bs, bs->file->filename);
}
static int vmdk_open(BlockDriverState *bs, QDict *options, int flags)
static int vmdk_open(BlockDriverState *bs, int flags)
{
int ret;
BDRVVmdkState *s = bs->opaque;
@@ -794,7 +772,7 @@ static int get_whole_cluster(BlockDriverState *bs,
int ret;
if (!vmdk_is_cid_valid(bs)) {
return VMDK_ERROR;
return -1;
}
/* floor offset to cluster */
@@ -802,31 +780,30 @@ static int get_whole_cluster(BlockDriverState *bs,
ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain,
extent->cluster_sectors);
if (ret < 0) {
return VMDK_ERROR;
return -1;
}
/* Write grain only into the active image */
ret = bdrv_write(extent->file, cluster_offset, whole_grain,
extent->cluster_sectors);
if (ret < 0) {
return VMDK_ERROR;
return -1;
}
}
return VMDK_OK;
return 0;
}
static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data)
{
uint32_t offset;
QEMU_BUILD_BUG_ON(sizeof(offset) != sizeof(m_data->offset));
offset = cpu_to_le32(m_data->offset);
/* update L2 table */
if (bdrv_pwrite_sync(
extent->file,
((int64_t)m_data->l2_offset * 512)
+ (m_data->l2_index * sizeof(m_data->offset)),
&offset, sizeof(offset)) < 0) {
return VMDK_ERROR;
&(m_data->offset),
sizeof(m_data->offset)
) < 0) {
return -1;
}
/* update backup L2 table */
if (extent->l1_backup_table_offset != 0) {
@@ -835,15 +812,13 @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data)
extent->file,
((int64_t)m_data->l2_offset * 512)
+ (m_data->l2_index * sizeof(m_data->offset)),
&offset, sizeof(offset)) < 0) {
return VMDK_ERROR;
&(m_data->offset), sizeof(m_data->offset)
) < 0) {
return -1;
}
}
if (m_data->l2_cache_entry) {
*m_data->l2_cache_entry = offset;
}
return VMDK_OK;
return 0;
}
static int get_cluster_offset(BlockDriverState *bs,
@@ -855,25 +830,24 @@ static int get_cluster_offset(BlockDriverState *bs,
{
unsigned int l1_index, l2_offset, l2_index;
int min_index, i, j;
uint32_t min_count, *l2_table;
bool zeroed = false;
uint32_t min_count, *l2_table, tmp = 0;
if (m_data) {
m_data->valid = 0;
}
if (extent->flat) {
*cluster_offset = extent->flat_start_offset;
return VMDK_OK;
return 0;
}
offset -= (extent->end_sector - extent->sectors) * SECTOR_SIZE;
l1_index = (offset >> 9) / extent->l1_entry_sectors;
if (l1_index >= extent->l1_size) {
return VMDK_ERROR;
return -1;
}
l2_offset = extent->l1_table[l1_index];
if (!l2_offset) {
return VMDK_UNALLOC;
return -1;
}
for (i = 0; i < L2_CACHE_SIZE; i++) {
if (l2_offset == extent->l2_cache_offsets[i]) {
@@ -903,7 +877,7 @@ static int get_cluster_offset(BlockDriverState *bs,
l2_table,
extent->l2_size * sizeof(uint32_t)
) != extent->l2_size * sizeof(uint32_t)) {
return VMDK_ERROR;
return -1;
}
extent->l2_cache_offsets[min_index] = l2_offset;
@@ -912,21 +886,9 @@ static int get_cluster_offset(BlockDriverState *bs,
l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size;
*cluster_offset = le32_to_cpu(l2_table[l2_index]);
if (m_data) {
m_data->valid = 1;
m_data->l1_index = l1_index;
m_data->l2_index = l2_index;
m_data->offset = *cluster_offset;
m_data->l2_offset = l2_offset;
m_data->l2_cache_entry = &l2_table[l2_index];
}
if (extent->has_zero_grain && *cluster_offset == VMDK_GTE_ZEROED) {
zeroed = true;
}
if (!*cluster_offset || zeroed) {
if (!*cluster_offset) {
if (!allocate) {
return zeroed ? VMDK_ZEROED : VMDK_UNALLOC;
return -1;
}
/* Avoid the L2 tables update for the images that have snapshots. */
@@ -939,7 +901,8 @@ static int get_cluster_offset(BlockDriverState *bs,
}
*cluster_offset >>= 9;
l2_table[l2_index] = cpu_to_le32(*cluster_offset);
tmp = cpu_to_le32(*cluster_offset);
l2_table[l2_index] = tmp;
/* First of all we write grain itself, to avoid race condition
* that may to corrupt the image.
@@ -948,15 +911,19 @@ static int get_cluster_offset(BlockDriverState *bs,
*/
if (get_whole_cluster(
bs, extent, *cluster_offset, offset, allocate) == -1) {
return VMDK_ERROR;
return -1;
}
if (m_data) {
m_data->offset = *cluster_offset;
m_data->offset = tmp;
m_data->l1_index = l1_index;
m_data->l2_index = l2_index;
m_data->l2_offset = l2_offset;
m_data->valid = 1;
}
}
*cluster_offset <<= 9;
return VMDK_OK;
return 0;
}
static VmdkExtent *find_extent(BDRVVmdkState *s,
@@ -992,8 +959,8 @@ static int coroutine_fn vmdk_co_is_allocated(BlockDriverState *bs,
ret = get_cluster_offset(bs, extent, NULL,
sector_num * 512, 0, &offset);
qemu_co_mutex_unlock(&s->lock);
ret = (ret == VMDK_OK || ret == VMDK_ZEROED);
/* get_cluster_offset returning 0 means success */
ret = !ret;
index_in_cluster = sector_num % extent->cluster_sectors;
n = extent->cluster_sectors - index_in_cluster;
@@ -1136,9 +1103,9 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
if (n > nb_sectors) {
n = nb_sectors;
}
if (ret != VMDK_OK) {
if (ret) {
/* if not allocated, try to read from parent image, if exist */
if (bs->backing_hd && ret != VMDK_ZEROED) {
if (bs->backing_hd) {
if (!vmdk_is_cid_valid(bs)) {
return -EINVAL;
}
@@ -1175,17 +1142,8 @@ static coroutine_fn int vmdk_co_read(BlockDriverState *bs, int64_t sector_num,
return ret;
}
/**
* vmdk_write:
* @zeroed: buf is ignored (data is zero), use zeroed_grain GTE feature
* if possible, otherwise return -ENOTSUP.
* @zero_dry_run: used for zeroed == true only, don't update L2 table, just
*
* Returns: error code with 0 for success.
*/
static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors,
bool zeroed, bool zero_dry_run)
const uint8_t *buf, int nb_sectors)
{
BDRVVmdkState *s = bs->opaque;
VmdkExtent *extent = NULL;
@@ -1215,7 +1173,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
sector_num << 9, !extent->compressed,
&cluster_offset);
if (extent->compressed) {
if (ret == VMDK_OK) {
if (ret == 0) {
/* Refuse write to allocated cluster for streamOptimized */
fprintf(stderr,
"VMDK: can't write to allocated cluster"
@@ -1231,7 +1189,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
&cluster_offset);
}
}
if (ret == VMDK_ERROR) {
if (ret) {
return -EINVAL;
}
extent_begin_sector = extent->end_sector - extent->sectors;
@@ -1241,23 +1199,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
if (n > nb_sectors) {
n = nb_sectors;
}
if (zeroed) {
/* Do zeroed write, buf is ignored */
if (extent->has_zero_grain &&
index_in_cluster == 0 &&
n >= extent->cluster_sectors) {
n = extent->cluster_sectors;
if (!zero_dry_run) {
m_data.offset = VMDK_GTE_ZEROED;
/* update L2 tables */
if (vmdk_L2update(extent, &m_data) != VMDK_OK) {
return -EIO;
}
}
} else {
return -ENOTSUP;
}
} else {
ret = vmdk_write_extent(extent,
cluster_offset, index_in_cluster * 512,
buf, n, sector_num);
@@ -1266,11 +1208,10 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
}
if (m_data.valid) {
/* update L2 tables */
if (vmdk_L2update(extent, &m_data) != VMDK_OK) {
if (vmdk_L2update(extent, &m_data) == -1) {
return -EIO;
}
}
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
@@ -1294,29 +1235,14 @@ static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num,
int ret;
BDRVVmdkState *s = bs->opaque;
qemu_co_mutex_lock(&s->lock);
ret = vmdk_write(bs, sector_num, buf, nb_sectors, false, false);
qemu_co_mutex_unlock(&s->lock);
return ret;
}
static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs,
int64_t sector_num,
int nb_sectors)
{
int ret;
BDRVVmdkState *s = bs->opaque;
qemu_co_mutex_lock(&s->lock);
ret = vmdk_write(bs, sector_num, NULL, nb_sectors, true, true);
if (!ret) {
ret = vmdk_write(bs, sector_num, NULL, nb_sectors, true, false);
}
ret = vmdk_write(bs, sector_num, buf, nb_sectors);
qemu_co_mutex_unlock(&s->lock);
return ret;
}
static int vmdk_create_extent(const char *filename, int64_t filesize,
bool flat, bool compress, bool zeroed_grain)
bool flat, bool compress)
{
int ret, i;
int fd = 0;
@@ -1338,10 +1264,9 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
}
magic = cpu_to_be32(VMDK4_MAGIC);
memset(&header, 0, sizeof(header));
header.version = zeroed_grain ? 2 : 1;
header.flags = VMDK4_FLAG_RGD | VMDK4_FLAG_NL_DETECT
| (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0)
| (zeroed_grain ? VMDK4_FLAG_ZERO_GRAIN : 0);
header.version = 1;
header.flags =
3 | (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0);
header.compressAlgorithm = compress ? VMDK4_COMPRESSION_DEFLATE : 0;
header.capacity = filesize / 512;
header.granularity = 128;
@@ -1432,7 +1357,7 @@ static int filename_decompose(const char *filename, char *path, char *prefix,
if (filename == NULL || !strlen(filename)) {
fprintf(stderr, "Vmdk: no filename provided.\n");
return VMDK_ERROR;
return -1;
}
p = strrchr(filename, '/');
if (p == NULL) {
@@ -1444,7 +1369,7 @@ static int filename_decompose(const char *filename, char *path, char *prefix,
if (p != NULL) {
p++;
if (p - filename >= buf_len) {
return VMDK_ERROR;
return -1;
}
pstrcpy(path, p - filename + 1, filename);
} else {
@@ -1457,12 +1382,12 @@ static int filename_decompose(const char *filename, char *path, char *prefix,
postfix[0] = '\0';
} else {
if (q - p >= buf_len) {
return VMDK_ERROR;
return -1;
}
pstrcpy(prefix, q - p + 1, p);
pstrcpy(postfix, buf_len, q);
}
return VMDK_OK;
return 0;
}
static int relative_path(char *dest, int dest_size,
@@ -1478,11 +1403,11 @@ static int relative_path(char *dest, int dest_size,
#endif
if (!(dest && base && target)) {
return VMDK_ERROR;
return -1;
}
if (path_is_absolute(target)) {
pstrcpy(dest, dest_size, target);
return VMDK_OK;
return 0;
}
while (base[i] == target[i]) {
i++;
@@ -1501,7 +1426,7 @@ static int relative_path(char *dest, int dest_size,
pstrcat(dest, dest_size, sep);
}
pstrcat(dest, dest_size, q);
return VMDK_OK;
return 0;
}
static int vmdk_create(const char *filename, QEMUOptionParameter *options)
@@ -1522,7 +1447,6 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
char parent_desc_line[BUF_SIZE] = "";
uint32_t parent_cid = 0xffffffff;
uint32_t number_heads = 16;
bool zeroed_grain = false;
const char desc_template[] =
"# Disk DescriptorFile\n"
"version=1\n"
@@ -1558,8 +1482,6 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
flags |= options->value.n ? BLOCK_FLAG_COMPAT6 : 0;
} else if (!strcmp(options->name, BLOCK_OPT_SUBFMT)) {
fmt = options->value.s;
} else if (!strcmp(options->name, BLOCK_OPT_ZEROED_GRAIN)) {
zeroed_grain |= options->value.n;
}
options++;
}
@@ -1605,7 +1527,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
if (backing_file) {
char parent_filename[PATH_MAX];
BlockDriverState *bs = bdrv_new("");
ret = bdrv_open(bs, backing_file, NULL, 0, NULL);
ret = bdrv_open(bs, backing_file, 0, NULL);
if (ret != 0) {
bdrv_delete(bs);
return ret;
@@ -1646,8 +1568,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
snprintf(ext_filename, sizeof(ext_filename), "%s%s",
path, desc_filename);
if (vmdk_create_extent(ext_filename, size,
flat, compress, zeroed_grain)) {
if (vmdk_create_extent(ext_filename, size, flat, compress)) {
return -EINVAL;
}
filesize -= size;
@@ -1773,11 +1694,6 @@ static QEMUOptionParameter vmdk_create_options[] = {
"VMDK flat extent format, can be one of "
"{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} "
},
{
.name = BLOCK_OPT_ZEROED_GRAIN,
.type = OPT_FLAG,
.help = "Enable efficient zero writes using the zeroed-grain GTE feature"
},
{ NULL }
};
@@ -1789,7 +1705,6 @@ static BlockDriver bdrv_vmdk = {
.bdrv_reopen_prepare = vmdk_reopen_prepare,
.bdrv_read = vmdk_co_read,
.bdrv_write = vmdk_co_write,
.bdrv_co_write_zeroes = vmdk_co_write_zeroes,
.bdrv_close = vmdk_close,
.bdrv_create = vmdk_create,
.bdrv_co_flush_to_disk = vmdk_co_flush,

View File

@@ -155,7 +155,7 @@ static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int vpc_open(BlockDriverState *bs, QDict *options, int flags)
static int vpc_open(BlockDriverState *bs, int flags)
{
BDRVVPCState *s = bs->opaque;
int i;

View File

@@ -1,4 +1,4 @@
/* vim:set shiftwidth=4 ts=4: */
/* vim:set shiftwidth=4 ts=8: */
/*
* QEMU Block driver for virtual VFAT (shadows a local directory)
*
@@ -28,8 +28,6 @@
#include "block/block_int.h"
#include "qemu/module.h"
#include "migration/migration.h"
#include "qapi/qmp/qint.h"
#include "qapi/qmp/qbool.h"
#ifndef S_IWGRP
#define S_IWGRP 0
@@ -990,90 +988,10 @@ static void vvfat_rebind(BlockDriverState *bs)
s->bs = bs;
}
static QemuOptsList runtime_opts = {
.name = "vvfat",
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
.desc = {
{
.name = "dir",
.type = QEMU_OPT_STRING,
.help = "Host directory to map to the vvfat device",
},
{
.name = "fat-type",
.type = QEMU_OPT_NUMBER,
.help = "FAT type (12, 16 or 32)",
},
{
.name = "floppy",
.type = QEMU_OPT_BOOL,
.help = "Create a floppy rather than a hard disk image",
},
{
.name = "rw",
.type = QEMU_OPT_BOOL,
.help = "Make the image writable",
},
{ /* end of list */ }
},
};
static void vvfat_parse_filename(const char *filename, QDict *options,
Error **errp)
{
int fat_type = 0;
bool floppy = false;
bool rw = false;
int i;
if (!strstart(filename, "fat:", NULL)) {
error_setg(errp, "File name string must start with 'fat:'");
return;
}
/* Parse options */
if (strstr(filename, ":32:")) {
fat_type = 32;
} else if (strstr(filename, ":16:")) {
fat_type = 16;
} else if (strstr(filename, ":12:")) {
fat_type = 12;
}
if (strstr(filename, ":floppy:")) {
floppy = true;
}
if (strstr(filename, ":rw:")) {
rw = true;
}
/* Get the directory name without options */
i = strrchr(filename, ':') - filename;
assert(i >= 3);
if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) {
/* workaround for DOS drive names */
filename += i - 1;
} else {
filename += i + 1;
}
/* Fill in the options QDict */
qdict_put(options, "dir", qstring_from_str(filename));
qdict_put(options, "fat-type", qint_from_int(fat_type));
qdict_put(options, "floppy", qbool_from_int(floppy));
qdict_put(options, "rw", qbool_from_int(rw));
}
static int vvfat_open(BlockDriverState *bs, QDict *options, int flags)
static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
{
BDRVVVFATState *s = bs->opaque;
int cyls, heads, secs;
bool floppy;
const char *dirname;
QemuOpts *opts;
Error *local_err = NULL;
int ret;
int i, cyls, heads, secs;
#ifdef DEBUG
vvv = s;
@@ -1084,65 +1002,6 @@ DLOG(if (stderr == NULL) {
setbuf(stderr, NULL);
})
opts = qemu_opts_create_nofail(&runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
ret = -EINVAL;
goto fail;
}
dirname = qemu_opt_get(opts, "dir");
if (!dirname) {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "vvfat block driver requires "
"a 'dir' option");
ret = -EINVAL;
goto fail;
}
s->fat_type = qemu_opt_get_number(opts, "fat-type", 0);
floppy = qemu_opt_get_bool(opts, "floppy", false);
if (floppy) {
/* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
if (!s->fat_type) {
s->fat_type = 12;
secs = 36;
s->sectors_per_cluster = 2;
} else {
secs = s->fat_type == 12 ? 18 : 36;
s->sectors_per_cluster = 1;
}
s->first_sectors_number = 1;
cyls = 80;
heads = 2;
} else {
/* 32MB or 504MB disk*/
if (!s->fat_type) {
s->fat_type = 16;
}
cyls = s->fat_type == 12 ? 64 : 1024;
heads = 16;
secs = 63;
}
switch (s->fat_type) {
case 32:
fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. "
"You are welcome to do so!\n");
break;
case 16:
case 12:
break;
default:
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Valid FAT types are only "
"12, 16 and 32");
ret = -EINVAL;
goto fail;
}
s->bs = bs;
/* LATER TODO: if FAT32, adjust */
@@ -1158,24 +1017,63 @@ DLOG(if (stderr == NULL) {
s->fat2 = NULL;
s->downcase_short_names = 1;
if (!strstart(dirname, "fat:", NULL))
return -1;
if (strstr(dirname, ":32:")) {
fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
s->fat_type = 32;
} else if (strstr(dirname, ":16:")) {
s->fat_type = 16;
} else if (strstr(dirname, ":12:")) {
s->fat_type = 12;
}
if (strstr(dirname, ":floppy:")) {
/* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
if (!s->fat_type) {
s->fat_type = 12;
secs = 36;
s->sectors_per_cluster=2;
} else {
secs = s->fat_type == 12 ? 18 : 36;
s->sectors_per_cluster=1;
}
s->first_sectors_number = 1;
cyls = 80;
heads = 2;
} else {
/* 32MB or 504MB disk*/
if (!s->fat_type) {
s->fat_type = 16;
}
cyls = s->fat_type == 12 ? 64 : 1024;
heads = 16;
secs = 63;
}
fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
dirname, cyls, heads, secs);
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
if (qemu_opt_get_bool(opts, "rw", false)) {
if (enable_write_target(s)) {
ret = -EIO;
goto fail;
}
if (strstr(dirname, ":rw:")) {
if (enable_write_target(s))
return -1;
bs->read_only = 0;
}
i = strrchr(dirname, ':') - dirname;
assert(i >= 3);
if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
/* workaround for DOS drive names */
dirname += i-1;
else
dirname += i+1;
bs->total_sectors = cyls * heads * secs;
if (init_directories(s, dirname, heads, secs)) {
ret = -EIO;
goto fail;
return -1;
}
s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
@@ -1195,10 +1093,7 @@ DLOG(if (stderr == NULL) {
migrate_add_blocker(s->migration_blocker);
}
ret = 0;
fail:
qemu_opts_del(opts);
return ret;
return 0;
}
static inline void vvfat_close_current_file(BDRVVVFATState *s)
@@ -2935,7 +2830,7 @@ static int enable_write_target(BDRVVVFATState *s)
return -1;
}
ret = bdrv_open(s->qcow, s->qcow_filename, NULL,
ret = bdrv_open(s->qcow, s->qcow_filename,
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow);
if (ret < 0) {
return ret;
@@ -2971,17 +2866,14 @@ static void vvfat_close(BlockDriverState *bs)
static BlockDriver bdrv_vvfat = {
.format_name = "vvfat",
.protocol_name = "fat",
.instance_size = sizeof(BDRVVVFATState),
.bdrv_parse_filename = vvfat_parse_filename,
.bdrv_file_open = vvfat_open,
.bdrv_close = vvfat_close,
.bdrv_rebind = vvfat_rebind,
.bdrv_read = vvfat_co_read,
.bdrv_write = vvfat_co_write,
.bdrv_close = vvfat_close,
.bdrv_co_is_allocated = vvfat_co_is_allocated,
.protocol_name = "fat",
};
static void bdrv_vvfat_init(void)

View File

@@ -10,7 +10,7 @@
*/
#include "sysemu/blockdev.h"
#include "hw/block/block.h"
#include "hw/block-common.h"
#include "monitor/monitor.h"
#include "qapi/qmp/qerror.h"
#include "sysemu/sysemu.h"

View File

@@ -5,33 +5,10 @@
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* later. See the COPYING file in the top-level directory.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "sysemu/blockdev.h"
#include "hw/block/block.h"
#include "hw/block-common.h"
#include "block/blockjob.h"
#include "monitor/monitor.h"
#include "qapi/qmp/qerror.h"
@@ -45,7 +22,6 @@
#include "sysemu/arch_init.h"
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
extern QemuOptsList qemu_common_drive_opts;
static const char *const if_name[IF_COUNT] = {
[IF_NONE] = "none",
@@ -215,7 +191,6 @@ static void drive_uninit(DriveInfo *dinfo)
bdrv_delete(dinfo->bdrv);
g_free(dinfo->id);
QTAILQ_REMOVE(&drives, dinfo, next);
g_free(dinfo->serial);
g_free(dinfo);
}
@@ -280,7 +255,7 @@ static int parse_block_error_action(const char *buf, bool is_read)
}
}
static bool do_check_io_limits(BlockIOLimit *io_limits, Error **errp)
static bool do_check_io_limits(BlockIOLimit *io_limits)
{
bool bps_flag;
bool iops_flag;
@@ -294,25 +269,13 @@ static bool do_check_io_limits(BlockIOLimit *io_limits, Error **errp)
&& ((io_limits->iops[BLOCK_IO_LIMIT_READ] != 0)
|| (io_limits->iops[BLOCK_IO_LIMIT_WRITE] != 0));
if (bps_flag || iops_flag) {
error_setg(errp, "bps(iops) and bps_rd/bps_wr(iops_rd/iops_wr) "
"cannot be used at the same time");
return false;
}
if (io_limits->bps[BLOCK_IO_LIMIT_TOTAL] < 0 ||
io_limits->bps[BLOCK_IO_LIMIT_WRITE] < 0 ||
io_limits->bps[BLOCK_IO_LIMIT_READ] < 0 ||
io_limits->iops[BLOCK_IO_LIMIT_TOTAL] < 0 ||
io_limits->iops[BLOCK_IO_LIMIT_WRITE] < 0 ||
io_limits->iops[BLOCK_IO_LIMIT_READ] < 0) {
error_setg(errp, "bps and iops values must be 0 or greater");
return false;
}
return true;
}
DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
{
const char *buf;
const char *file = NULL;
@@ -334,37 +297,10 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
int snapshot = 0;
bool copy_on_read;
int ret;
Error *error = NULL;
QemuOpts *opts;
QDict *bs_opts;
const char *id;
translation = BIOS_ATA_TRANSLATION_AUTO;
media = MEDIA_DISK;
/* Check common options by copying from all_opts to opts, all other options
* are stored in bs_opts. */
id = qemu_opts_id(all_opts);
opts = qemu_opts_create(&qemu_common_drive_opts, id, 1, &error);
if (error_is_set(&error)) {
qerror_report_err(error);
error_free(error);
return NULL;
}
bs_opts = qdict_new();
qemu_opts_to_qdict(all_opts, bs_opts);
qemu_opts_absorb_qdict(opts, bs_opts, &error);
if (error_is_set(&error)) {
qerror_report_err(error);
error_free(error);
return NULL;
}
if (id) {
qdict_del(bs_opts, "id");
}
/* extract parameters */
bus_id = qemu_opt_get_number(opts, "bus", 0);
unit_id = qemu_opt_get_number(opts, "unit", -1);
@@ -442,13 +378,6 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
}
}
if ((buf = qemu_opt_get(opts, "discard")) != NULL) {
if (bdrv_parse_discard_flags(buf, &bdrv_flags) != 0) {
error_report("invalid discard option");
return NULL;
}
}
bdrv_flags |= BDRV_O_CACHE_WB;
if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
if (bdrv_parse_cache_flags(buf, &bdrv_flags) != 0) {
@@ -498,9 +427,9 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
io_limits.iops[BLOCK_IO_LIMIT_WRITE] =
qemu_opt_get_number(opts, "iops_wr", 0);
if (!do_check_io_limits(&io_limits, &error)) {
error_report("%s", error_get_pretty(error));
error_free(error);
if (!do_check_io_limits(&io_limits)) {
error_report("bps(iops) and bps_rd/bps_wr(iops_rd/iops_wr) "
"cannot be used at the same time");
return NULL;
}
@@ -615,11 +544,9 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
dinfo->heads = heads;
dinfo->secs = secs;
dinfo->trans = translation;
dinfo->opts = all_opts;
dinfo->opts = opts;
dinfo->refcount = 1;
if (serial != NULL) {
dinfo->serial = g_strdup(serial);
}
dinfo->serial = serial;
QTAILQ_INSERT_TAIL(&drives, dinfo, next);
bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error);
@@ -640,30 +567,23 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
case IF_MTD:
break;
case IF_VIRTIO:
{
/* add virtio block device */
QemuOpts *devopts;
devopts = qemu_opts_create_nofail(qemu_find_opts("device"));
opts = qemu_opts_create_nofail(qemu_find_opts("device"));
if (arch_type == QEMU_ARCH_S390X) {
qemu_opt_set(devopts, "driver", "virtio-blk-s390");
qemu_opt_set(opts, "driver", "virtio-blk-s390");
} else {
qemu_opt_set(devopts, "driver", "virtio-blk-pci");
qemu_opt_set(opts, "driver", "virtio-blk-pci");
}
qemu_opt_set(devopts, "drive", dinfo->id);
qemu_opt_set(opts, "drive", dinfo->id);
if (devaddr)
qemu_opt_set(devopts, "addr", devaddr);
qemu_opt_set(opts, "addr", devaddr);
break;
}
default:
abort();
}
if (!file || !*file) {
if (qdict_size(bs_opts)) {
file = NULL;
} else {
return dinfo;
}
}
if (snapshot) {
/* always use cache=unsafe with snapshot */
bdrv_flags &= ~BDRV_O_CACHE_MASK;
@@ -695,30 +615,23 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
error_report("warning: disabling copy_on_read on readonly drive");
}
ret = bdrv_open(dinfo->bdrv, file, bs_opts, bdrv_flags, drv);
bs_opts = NULL;
ret = bdrv_open(dinfo->bdrv, file, bdrv_flags, drv);
if (ret < 0) {
if (ret == -EMEDIUMTYPE) {
error_report("could not open disk image %s: not in %s format",
file ?: dinfo->id, drv->format_name);
file, drv->format_name);
} else {
error_report("could not open disk image %s: %s",
file ?: dinfo->id, strerror(-ret));
file, strerror(-ret));
}
goto err;
}
if (bdrv_key_required(dinfo->bdrv))
autostart = 0;
qemu_opts_del(opts);
return dinfo;
err:
qemu_opts_del(opts);
QDECREF(bs_opts);
bdrv_delete(dinfo->bdrv);
g_free(dinfo->id);
QTAILQ_REMOVE(&drives, dinfo, next);
@@ -878,7 +791,7 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp)
bdrv_img_create(new_image_file, format,
states->old_bs->filename,
states->old_bs->drv->format_name,
NULL, -1, flags, &local_err, false);
NULL, -1, flags, &local_err);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
goto delete_and_fail;
@@ -887,9 +800,7 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp)
/* We will manually add the backing_hd field to the bs later */
states->new_bs = bdrv_new("");
/* TODO Inherit bs->options or only take explicit options with an
* extended QMP command? */
ret = bdrv_open(states->new_bs, new_image_file, NULL,
ret = bdrv_open(states->new_bs, new_image_file,
flags | BDRV_O_NO_BACKING, drv);
if (ret != 0) {
error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file);
@@ -990,7 +901,7 @@ static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
int bdrv_flags, BlockDriver *drv,
const char *password, Error **errp)
{
if (bdrv_open(bs, filename, NULL, bdrv_flags, drv) < 0) {
if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
error_set(errp, QERR_OPEN_FILE_FAILED, filename);
return;
}
@@ -1064,11 +975,13 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
io_limits.iops[BLOCK_IO_LIMIT_READ] = iops_rd;
io_limits.iops[BLOCK_IO_LIMIT_WRITE]= iops_wr;
if (!do_check_io_limits(&io_limits, errp)) {
if (!do_check_io_limits(&io_limits)) {
error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
return;
}
bs->io_limits = io_limits;
bs->slice_time = BLOCK_IO_SLICE_TIME;
if (!bs->io_limits_enabled && bdrv_io_limits_enabled(bs)) {
bdrv_io_limits_enable(bs);
@@ -1108,10 +1021,6 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
*/
if (bdrv_get_attached_dev(bs)) {
bdrv_make_anon(bs);
/* Further I/O must not pause the guest */
bdrv_set_on_error(bs, BLOCKDEV_ON_ERROR_REPORT,
BLOCKDEV_ON_ERROR_REPORT);
} else {
drive_uninit(drive_get_by_blockdev(bs));
}
@@ -1122,7 +1031,6 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
void qmp_block_resize(const char *device, int64_t size, Error **errp)
{
BlockDriverState *bs;
int ret;
bs = bdrv_find(device);
if (!bs) {
@@ -1138,8 +1046,7 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
/* complete all in-flight operations before resizing the device */
bdrv_drain_all();
ret = bdrv_truncate(bs, size);
switch (ret) {
switch (bdrv_truncate(bs, size)) {
case 0:
break;
case -ENOMEDIUM:
@@ -1155,7 +1062,7 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
error_set(errp, QERR_DEVICE_IN_USE, device);
break;
default:
error_setg_errno(errp, -ret, "Could not resize");
error_set(errp, QERR_UNDEFINED_ERROR);
break;
}
}
@@ -1380,7 +1287,7 @@ void qmp_drive_mirror(const char *device, const char *target,
/* create new image w/o backing file */
assert(format && drv);
bdrv_img_create(target, format,
NULL, NULL, NULL, size, flags, &local_err, false);
NULL, NULL, NULL, size, flags, &local_err);
} else {
switch (mode) {
case NEW_IMAGE_MODE_EXISTING:
@@ -1391,7 +1298,7 @@ void qmp_drive_mirror(const char *device, const char *target,
bdrv_img_create(target, format,
source->filename,
source->drv->format_name,
NULL, size, flags, &local_err, false);
NULL, size, flags, &local_err);
break;
default:
abort();
@@ -1407,7 +1314,7 @@ void qmp_drive_mirror(const char *device, const char *target,
* file.
*/
target_bs = bdrv_new("");
ret = bdrv_open(target_bs, target, NULL, flags | BDRV_O_NO_BACKING, drv);
ret = bdrv_open(target_bs, target, flags | BDRV_O_NO_BACKING, drv);
if (ret < 0) {
bdrv_delete(target_bs);
@@ -1536,128 +1443,6 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp)
return dummy.next;
}
QemuOptsList qemu_common_drive_opts = {
.name = "drive",
.head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),
.desc = {
{
.name = "bus",
.type = QEMU_OPT_NUMBER,
.help = "bus number",
},{
.name = "unit",
.type = QEMU_OPT_NUMBER,
.help = "unit number (i.e. lun for scsi)",
},{
.name = "if",
.type = QEMU_OPT_STRING,
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
},{
.name = "index",
.type = QEMU_OPT_NUMBER,
.help = "index number",
},{
.name = "cyls",
.type = QEMU_OPT_NUMBER,
.help = "number of cylinders (ide disk geometry)",
},{
.name = "heads",
.type = QEMU_OPT_NUMBER,
.help = "number of heads (ide disk geometry)",
},{
.name = "secs",
.type = QEMU_OPT_NUMBER,
.help = "number of sectors (ide disk geometry)",
},{
.name = "trans",
.type = QEMU_OPT_STRING,
.help = "chs translation (auto, lba. none)",
},{
.name = "media",
.type = QEMU_OPT_STRING,
.help = "media type (disk, cdrom)",
},{
.name = "snapshot",
.type = QEMU_OPT_BOOL,
.help = "enable/disable snapshot mode",
},{
.name = "file",
.type = QEMU_OPT_STRING,
.help = "disk image",
},{
.name = "discard",
.type = QEMU_OPT_STRING,
.help = "discard operation (ignore/off, unmap/on)",
},{
.name = "cache",
.type = QEMU_OPT_STRING,
.help = "host cache usage (none, writeback, writethrough, "
"directsync, unsafe)",
},{
.name = "aio",
.type = QEMU_OPT_STRING,
.help = "host AIO implementation (threads, native)",
},{
.name = "format",
.type = QEMU_OPT_STRING,
.help = "disk format (raw, qcow2, ...)",
},{
.name = "serial",
.type = QEMU_OPT_STRING,
.help = "disk serial number",
},{
.name = "rerror",
.type = QEMU_OPT_STRING,
.help = "read error action",
},{
.name = "werror",
.type = QEMU_OPT_STRING,
.help = "write error action",
},{
.name = "addr",
.type = QEMU_OPT_STRING,
.help = "pci address (virtio only)",
},{
.name = "readonly",
.type = QEMU_OPT_BOOL,
.help = "open drive file as read-only",
},{
.name = "iops",
.type = QEMU_OPT_NUMBER,
.help = "limit total I/O operations per second",
},{
.name = "iops_rd",
.type = QEMU_OPT_NUMBER,
.help = "limit read operations per second",
},{
.name = "iops_wr",
.type = QEMU_OPT_NUMBER,
.help = "limit write operations per second",
},{
.name = "bps",
.type = QEMU_OPT_NUMBER,
.help = "limit total bytes per second",
},{
.name = "bps_rd",
.type = QEMU_OPT_NUMBER,
.help = "limit read bytes per second",
},{
.name = "bps_wr",
.type = QEMU_OPT_NUMBER,
.help = "limit write bytes per second",
},{
.name = "copy-on-read",
.type = QEMU_OPT_BOOL,
.help = "copy read data from backing file into image file",
},{
.name = "boot",
.type = QEMU_OPT_BOOL,
.help = "(deprecated, ignored)",
},
{ /* end of list */ }
},
};
QemuOptsList qemu_drive_opts = {
.name = "drive",
.head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
@@ -1706,10 +1491,6 @@ QemuOptsList qemu_drive_opts = {
.name = "file",
.type = QEMU_OPT_STRING,
.help = "disk image",
},{
.name = "discard",
.type = QEMU_OPT_STRING,
.help = "discard operation (ignore/off, unmap/on)",
},{
.name = "cache",
.type = QEMU_OPT_STRING,

View File

@@ -110,7 +110,7 @@ static const char *get_elf_platform(void)
static uint32_t get_elf_hwcap(void)
{
return thread_env->features[FEAT_1_EDX];
return thread_env->cpuid_features;
}
#ifdef TARGET_X86_64

View File

@@ -34,6 +34,8 @@
#include "qemu/timer.h"
#include "qemu/envlist.h"
#define DEBUG_LOGFILE "/tmp/qemu.log"
int singlestep;
#if defined(CONFIG_USE_GUEST_BASE)
unsigned long mmap_min_addr;
@@ -689,9 +691,8 @@ static void usage(void)
"-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
"\n"
"Debug options:\n"
"-d item1[,...] enable logging of specified items\n"
" (use '-d help' for a list of log items)\n"
"-D logfile write logs to 'logfile' (default stderr)\n"
"-d options activate log (default logfile=%s)\n"
"-D logfile override default logfile location\n"
"-p pagesize set the host page size to 'pagesize'\n"
"-singlestep always run in singlestep mode\n"
"-strace log system calls\n"
@@ -708,7 +709,8 @@ static void usage(void)
,
TARGET_ARCH,
interp_prefix,
x86_stack_size);
x86_stack_size,
DEBUG_LOGFILE);
exit(1);
}
@@ -731,7 +733,7 @@ int main(int argc, char **argv)
{
const char *filename;
const char *cpu_model;
const char *log_file = NULL;
const char *log_file = DEBUG_LOGFILE;
const char *log_mask = NULL;
struct target_pt_regs regs1, *regs = &regs1;
struct image_info info1, *info = &info1;
@@ -859,16 +861,20 @@ int main(int argc, char **argv)
}
/* init debug */
qemu_set_log_filename(log_file);
cpu_set_log_filename(log_file);
if (log_mask) {
int mask;
const CPULogItem *item;
mask = qemu_str_to_log_mask(log_mask);
mask = cpu_str_to_log_mask(log_mask);
if (!mask) {
qemu_print_log_usage(stdout);
printf("Log items (comma separated):\n");
for (item = cpu_log_items; item->mask != 0; item++) {
printf("%-10s %s\n", item->name, item->help);
}
exit(1);
}
qemu_set_log(mask);
cpu_set_log(mask);
}
if (optind >= argc) {
@@ -1004,13 +1010,13 @@ int main(int argc, char **argv)
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
env->hflags |= HF_PE_MASK;
if (env->features[FEAT_1_EDX] & CPUID_SSE) {
if (env->cpuid_features & CPUID_SSE) {
env->cr[4] |= CR4_OSFXSR_MASK;
env->hflags |= HF_OSFXSR_MASK;
}
#ifndef TARGET_ABI32
/* enable 64 bit mode if possible */
if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) {
fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
exit(1);
}

View File

@@ -211,12 +211,7 @@ static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind)
*(uint64_t *)holdp = tswap64(*(unsigned long *)holdp);
break;
#endif
#ifdef CTLTYPE_U64
case CTLTYPE_S64:
case CTLTYPE_U64:
#else
case CTLTYPE_QUAD:
#endif
*(uint64_t *)holdp = tswap64(*(uint64_t *)holdp);
break;
case CTLTYPE_STRING:

View File

@@ -18,7 +18,7 @@
*/
#include "qemu-common.h"
#include "sysemu/bt.h"
#include "bt/bt.h"
#include "qemu/main-loop.h"
#ifndef _WIN32
@@ -171,7 +171,7 @@ struct HCIInfo *bt_host_hci(const char *id)
hci_filter_all_ptypes(&flt);
hci_filter_all_events(&flt);
if (qemu_setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
fprintf(stderr, "qemu: Can't set HCI filter on socket (%i)\n", errno);
return 0;
}

View File

@@ -18,7 +18,7 @@
*/
#include "qemu-common.h"
#include "sysemu/bt.h"
#include "bt/bt.h"
#include "hw/bt.h"
#include "qemu/main-loop.h"

836
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -33,10 +33,19 @@
#include "qemu-common.h"
#include "block/coroutine_int.h"
enum {
/* Maximum free pool size prevents holding too many freed coroutines */
POOL_MAX_SIZE = 64,
};
/** Free list to speed up creation */
static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool);
static unsigned int pool_size;
typedef struct {
Coroutine base;
void *stack;
sigjmp_buf env;
jmp_buf env;
} CoroutineUContext;
/**
@@ -50,7 +59,7 @@ typedef struct {
CoroutineUContext leader;
/** Information for the signal handler (trampoline) */
sigjmp_buf tr_reenter;
jmp_buf tr_reenter;
volatile sig_atomic_t tr_called;
void *tr_handler;
} CoroutineThreadState;
@@ -76,6 +85,17 @@ static void qemu_coroutine_thread_cleanup(void *opaque)
g_free(s);
}
static void __attribute__((destructor)) coroutine_cleanup(void)
{
Coroutine *co;
Coroutine *tmp;
QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
g_free(DO_UPCAST(CoroutineUContext, base, co)->stack);
g_free(co);
}
}
static void __attribute__((constructor)) coroutine_init(void)
{
int ret;
@@ -95,8 +115,8 @@ static void __attribute__((constructor)) coroutine_init(void)
static void coroutine_bootstrap(CoroutineUContext *self, Coroutine *co)
{
/* Initialize longjmp environment and switch back the caller */
if (!sigsetjmp(self->env, 0)) {
siglongjmp(*(sigjmp_buf *)co->entry_arg, 1);
if (!setjmp(self->env)) {
longjmp(*(jmp_buf *)co->entry_arg, 1);
}
while (true) {
@@ -125,14 +145,14 @@ static void coroutine_trampoline(int signal)
/*
* Here we have to do a bit of a ping pong between the caller, given that
* this is a signal handler and we have to do a return "soon". Then the
* caller can reestablish everything and do a siglongjmp here again.
* caller can reestablish everything and do a longjmp here again.
*/
if (!sigsetjmp(coTS->tr_reenter, 0)) {
if (!setjmp(coTS->tr_reenter)) {
return;
}
/*
* Ok, the caller has siglongjmp'ed back to us, so now prepare
* Ok, the caller has longjmp'ed back to us, so now prepare
* us for the real machine state switching. We have to jump
* into another function here to get a new stack context for
* the auto variables (which have to be auto-variables
@@ -144,7 +164,7 @@ static void coroutine_trampoline(int signal)
coroutine_bootstrap(self, co);
}
Coroutine *qemu_coroutine_new(void)
static Coroutine *coroutine_new(void)
{
const size_t stack_size = 1 << 20;
CoroutineUContext *co;
@@ -159,7 +179,7 @@ Coroutine *qemu_coroutine_new(void)
/* The way to manipulate stack is with the sigaltstack function. We
* prepare a stack, with it delivering a signal to ourselves and then
* put sigsetjmp/siglongjmp where needed.
* put setjmp/longjmp where needed.
* This has been done keeping coroutine-ucontext as a model and with the
* pth ideas (GNU Portable Threads). See coroutine-ucontext for the basics
* of the coroutines and see pth_mctx.c (from the pth project) for the
@@ -200,7 +220,7 @@ Coroutine *qemu_coroutine_new(void)
/*
* Now transfer control onto the signal stack and set it up.
* It will return immediately via "return" after the sigsetjmp()
* It will return immediately via "return" after the setjmp()
* was performed. Be careful here with race conditions. The
* signal can be delivered the first time sigsuspend() is
* called.
@@ -241,8 +261,8 @@ Coroutine *qemu_coroutine_new(void)
* type-conversion warnings related to the `volatile' qualifier and
* the fact that `jmp_buf' usually is an array type.
*/
if (!sigsetjmp(old_env, 0)) {
siglongjmp(coTS->tr_reenter, 1);
if (!setjmp(old_env)) {
longjmp(coTS->tr_reenter, 1);
}
/*
@@ -252,10 +272,31 @@ Coroutine *qemu_coroutine_new(void)
return &co->base;
}
Coroutine *qemu_coroutine_new(void)
{
Coroutine *co;
co = QSLIST_FIRST(&pool);
if (co) {
QSLIST_REMOVE_HEAD(&pool, pool_next);
pool_size--;
} else {
co = coroutine_new();
}
return co;
}
void qemu_coroutine_delete(Coroutine *co_)
{
CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
if (pool_size < POOL_MAX_SIZE) {
QSLIST_INSERT_HEAD(&pool, &co->base, pool_next);
co->base.caller = NULL;
pool_size++;
return;
}
g_free(co->stack);
g_free(co);
}
@@ -270,9 +311,9 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
s->current = to_;
ret = sigsetjmp(from->env, 0);
ret = setjmp(from->env);
if (ret == 0) {
siglongjmp(to->env, action);
longjmp(to->env, action);
}
return ret;
}

View File

@@ -34,10 +34,19 @@
#include <valgrind/valgrind.h>
#endif
enum {
/* Maximum free pool size prevents holding too many freed coroutines */
POOL_MAX_SIZE = 64,
};
/** Free list to speed up creation */
static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool);
static unsigned int pool_size;
typedef struct {
Coroutine base;
void *stack;
sigjmp_buf env;
jmp_buf env;
#ifdef CONFIG_VALGRIND_H
unsigned int valgrind_stack_id;
@@ -87,6 +96,17 @@ static void qemu_coroutine_thread_cleanup(void *opaque)
g_free(s);
}
static void __attribute__((destructor)) coroutine_cleanup(void)
{
Coroutine *co;
Coroutine *tmp;
QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
g_free(DO_UPCAST(CoroutineUContext, base, co)->stack);
g_free(co);
}
}
static void __attribute__((constructor)) coroutine_init(void)
{
int ret;
@@ -110,8 +130,8 @@ static void coroutine_trampoline(int i0, int i1)
co = &self->base;
/* Initialize longjmp environment and switch back the caller */
if (!sigsetjmp(self->env, 0)) {
siglongjmp(*(sigjmp_buf *)co->entry_arg, 1);
if (!setjmp(self->env)) {
longjmp(*(jmp_buf *)co->entry_arg, 1);
}
while (true) {
@@ -120,20 +140,19 @@ static void coroutine_trampoline(int i0, int i1)
}
}
Coroutine *qemu_coroutine_new(void)
static Coroutine *coroutine_new(void)
{
const size_t stack_size = 1 << 20;
CoroutineUContext *co;
ucontext_t old_uc, uc;
sigjmp_buf old_env;
jmp_buf old_env;
union cc_arg arg = {0};
/* The ucontext functions preserve signal masks which incurs a
* system call overhead. sigsetjmp(buf, 0)/siglongjmp() does not
* preserve signal masks but only works on the current stack.
* Since we need a way to create and switch to a new stack, use
* the ucontext functions for that but sigsetjmp()/siglongjmp() for
* everything else.
/* The ucontext functions preserve signal masks which incurs a system call
* overhead. setjmp()/longjmp() does not preserve signal masks but only
* works on the current stack. Since we need a way to create and switch to
* a new stack, use the ucontext functions for that but setjmp()/longjmp()
* for everything else.
*/
if (getcontext(&uc) == -1) {
@@ -159,17 +178,30 @@ Coroutine *qemu_coroutine_new(void)
makecontext(&uc, (void (*)(void))coroutine_trampoline,
2, arg.i[0], arg.i[1]);
/* swapcontext() in, siglongjmp() back out */
if (!sigsetjmp(old_env, 0)) {
/* swapcontext() in, longjmp() back out */
if (!setjmp(old_env)) {
swapcontext(&old_uc, &uc);
}
return &co->base;
}
Coroutine *qemu_coroutine_new(void)
{
Coroutine *co;
co = QSLIST_FIRST(&pool);
if (co) {
QSLIST_REMOVE_HEAD(&pool, pool_next);
pool_size--;
} else {
co = coroutine_new();
}
return co;
}
#ifdef CONFIG_VALGRIND_H
#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
/* Work around an unused variable in the valgrind.h macro... */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif
static inline void valgrind_stack_deregister(CoroutineUContext *co)
@@ -177,7 +209,7 @@ static inline void valgrind_stack_deregister(CoroutineUContext *co)
VALGRIND_STACK_DEREGISTER(co->valgrind_stack_id);
}
#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
#pragma GCC diagnostic pop
#pragma GCC diagnostic error "-Wunused-but-set-variable"
#endif
#endif
@@ -185,6 +217,13 @@ void qemu_coroutine_delete(Coroutine *co_)
{
CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
if (pool_size < POOL_MAX_SIZE) {
QSLIST_INSERT_HEAD(&pool, &co->base, pool_next);
co->base.caller = NULL;
pool_size++;
return;
}
#ifdef CONFIG_VALGRIND_H
valgrind_stack_deregister(co);
#endif
@@ -203,9 +242,9 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
s->current = to_;
ret = sigsetjmp(from->env, 0);
ret = setjmp(from->env);
if (ret == 0) {
siglongjmp(to->env, action);
longjmp(to->env, action);
}
return ret;
}

View File

@@ -23,6 +23,10 @@
#include "qemu/atomic.h"
#include "sysemu/qtest.h"
int tb_invalidated_flag;
//#define CONFIG_DEBUG_EXEC
bool qemu_cpu_has_work(CPUState *cpu)
{
return cpu_has_work(cpu);
@@ -30,10 +34,8 @@ bool qemu_cpu_has_work(CPUState *cpu)
void cpu_loop_exit(CPUArchState *env)
{
CPUState *cpu = ENV_GET_CPU(env);
cpu->current_tb = NULL;
siglongjmp(env->jmp_env, 1);
env->current_tb = NULL;
longjmp(env->jmp_env, 1);
}
/* exit the current TB from a signal handler. The host registers are
@@ -45,38 +47,16 @@ void cpu_resume_from_signal(CPUArchState *env, void *puc)
/* XXX: restore cpu registers saved in host registers */
env->exception_index = -1;
siglongjmp(env->jmp_env, 1);
longjmp(env->jmp_env, 1);
}
#endif
/* Execute a TB, and fix up the CPU state afterwards if necessary */
static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
{
CPUArchState *env = cpu->env_ptr;
tcg_target_ulong next_tb = tcg_qemu_tb_exec(env, tb_ptr);
if ((next_tb & TB_EXIT_MASK) > TB_EXIT_IDX1) {
/* We didn't start executing this TB (eg because the instruction
* counter hit zero); we must restore the guest PC to the address
* of the start of the TB.
*/
TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
cpu_pc_from_tb(env, tb);
}
if ((next_tb & TB_EXIT_MASK) == TB_EXIT_REQUESTED) {
/* We were asked to stop executing TBs (probably a pending
* interrupt. We've now stopped, so clear the flag.
*/
cpu->tcg_exit_req = 0;
}
return next_tb;
}
/* Execute the code without caching the generated code. An interpreter
could be used if available. */
static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
TranslationBlock *orig_tb)
{
CPUState *cpu = ENV_GET_CPU(env);
tcg_target_ulong next_tb;
TranslationBlock *tb;
/* Should never happen.
@@ -86,10 +66,16 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
max_cycles);
cpu->current_tb = tb;
env->current_tb = tb;
/* execute the generated code */
cpu_tb_exec(cpu, tb->tc_ptr);
cpu->current_tb = NULL;
next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr);
env->current_tb = NULL;
if ((next_tb & 3) == 2) {
/* Restore PC. This may happen if async event occurs before
the TB starts executing. */
cpu_pc_from_tb(env, tb);
}
tb_phys_invalidate(tb, -1);
tb_free(tb);
}
@@ -104,13 +90,13 @@ static TranslationBlock *tb_find_slow(CPUArchState *env,
tb_page_addr_t phys_pc, phys_page1;
target_ulong virt_page2;
tcg_ctx.tb_ctx.tb_invalidated_flag = 0;
tb_invalidated_flag = 0;
/* find translated block using physical mappings */
phys_pc = get_page_addr_code(env, pc);
phys_page1 = phys_pc & TARGET_PAGE_MASK;
h = tb_phys_hash_func(phys_pc);
ptb1 = &tcg_ctx.tb_ctx.tb_phys_hash[h];
ptb1 = &tb_phys_hash[h];
for(;;) {
tb = *ptb1;
if (!tb)
@@ -142,8 +128,8 @@ static TranslationBlock *tb_find_slow(CPUArchState *env,
/* Move the last found TB to the head of the list */
if (likely(*ptb1)) {
*ptb1 = tb->phys_hash_next;
tb->phys_hash_next = tcg_ctx.tb_ctx.tb_phys_hash[h];
tcg_ctx.tb_ctx.tb_phys_hash[h] = tb;
tb->phys_hash_next = tb_phys_hash[h];
tb_phys_hash[h] = tb;
}
/* we add the TB in the virtual pc hash table */
env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
@@ -196,35 +182,23 @@ volatile sig_atomic_t exit_request;
int cpu_exec(CPUArchState *env)
{
CPUState *cpu = ENV_GET_CPU(env);
#if !(defined(CONFIG_USER_ONLY) && \
(defined(TARGET_M68K) || defined(TARGET_PPC) || defined(TARGET_S390X)))
CPUClass *cc = CPU_GET_CLASS(cpu);
#endif
int ret, interrupt_request;
TranslationBlock *tb;
uint8_t *tc_ptr;
tcg_target_ulong next_tb;
if (cpu->halted) {
if (env->halted) {
if (!cpu_has_work(cpu)) {
return EXCP_HALTED;
}
cpu->halted = 0;
env->halted = 0;
}
cpu_single_env = env;
/* As long as cpu_single_env is null, up to the assignment just above,
* requests by other threads to exit the execution loop are expected to
* be issued using the exit_request global. We must make sure that our
* evaluation of the global value is performed past the cpu_single_env
* value transition point, which requires a memory barrier as well as
* an instruction scheduling constraint on modern architectures. */
smp_mb();
if (unlikely(exit_request)) {
cpu->exit_request = 1;
env->exit_request = 1;
}
#if defined(TARGET_I386)
@@ -246,7 +220,6 @@ int cpu_exec(CPUArchState *env)
#elif defined(TARGET_LM32)
#elif defined(TARGET_MICROBLAZE)
#elif defined(TARGET_MIPS)
#elif defined(TARGET_MOXIE)
#elif defined(TARGET_OPENRISC)
#elif defined(TARGET_SH4)
#elif defined(TARGET_CRIS)
@@ -260,7 +233,7 @@ int cpu_exec(CPUArchState *env)
/* prepare setjmp context for exception handling */
for(;;) {
if (sigsetjmp(env->jmp_env, 0) == 0) {
if (setjmp(env->jmp_env) == 0) {
/* if an exception is pending, we execute it here */
if (env->exception_index >= 0) {
if (env->exception_index >= EXCP_INTERRUPT) {
@@ -276,12 +249,12 @@ int cpu_exec(CPUArchState *env)
which will be handled outside the cpu execution
loop */
#if defined(TARGET_I386)
cc->do_interrupt(cpu);
do_interrupt(env);
#endif
ret = env->exception_index;
break;
#else
cc->do_interrupt(cpu);
do_interrupt(env);
env->exception_index = -1;
#endif
}
@@ -289,14 +262,14 @@ int cpu_exec(CPUArchState *env)
next_tb = 0; /* force lookup of first TB */
for(;;) {
interrupt_request = cpu->interrupt_request;
interrupt_request = env->interrupt_request;
if (unlikely(interrupt_request)) {
if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
/* Mask out external interrupts for this step. */
interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
}
if (interrupt_request & CPU_INTERRUPT_DEBUG) {
cpu->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
env->exception_index = EXCP_DEBUG;
cpu_loop_exit(env);
}
@@ -304,8 +277,8 @@ int cpu_exec(CPUArchState *env)
defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
if (interrupt_request & CPU_INTERRUPT_HALT) {
cpu->interrupt_request &= ~CPU_INTERRUPT_HALT;
cpu->halted = 1;
env->interrupt_request &= ~CPU_INTERRUPT_HALT;
env->halted = 1;
env->exception_index = EXCP_HLT;
cpu_loop_exit(env);
}
@@ -313,7 +286,7 @@ int cpu_exec(CPUArchState *env)
#if defined(TARGET_I386)
#if !defined(CONFIG_USER_ONLY)
if (interrupt_request & CPU_INTERRUPT_POLL) {
cpu->interrupt_request &= ~CPU_INTERRUPT_POLL;
env->interrupt_request &= ~CPU_INTERRUPT_POLL;
apic_poll_irq(env->apic_state);
}
#endif
@@ -330,17 +303,17 @@ int cpu_exec(CPUArchState *env)
!(env->hflags & HF_SMM_MASK)) {
cpu_svm_check_intercept_param(env, SVM_EXIT_SMI,
0);
cpu->interrupt_request &= ~CPU_INTERRUPT_SMI;
env->interrupt_request &= ~CPU_INTERRUPT_SMI;
do_smm_enter(env);
next_tb = 0;
} else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
!(env->hflags2 & HF2_NMI_MASK)) {
cpu->interrupt_request &= ~CPU_INTERRUPT_NMI;
env->interrupt_request &= ~CPU_INTERRUPT_NMI;
env->hflags2 |= HF2_NMI_MASK;
do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
next_tb = 0;
} else if (interrupt_request & CPU_INTERRUPT_MCE) {
cpu->interrupt_request &= ~CPU_INTERRUPT_MCE;
env->interrupt_request &= ~CPU_INTERRUPT_MCE;
do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
next_tb = 0;
} else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
@@ -352,8 +325,7 @@ int cpu_exec(CPUArchState *env)
int intno;
cpu_svm_check_intercept_param(env, SVM_EXIT_INTR,
0);
cpu->interrupt_request &= ~(CPU_INTERRUPT_HARD |
CPU_INTERRUPT_VIRQ);
env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
intno = cpu_get_pic_interrupt(env);
qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
do_interrupt_x86_hardirq(env, intno, 1);
@@ -371,7 +343,7 @@ int cpu_exec(CPUArchState *env)
intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
do_interrupt_x86_hardirq(env, intno, 1);
cpu->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
next_tb = 0;
#endif
}
@@ -382,16 +354,15 @@ int cpu_exec(CPUArchState *env)
}
if (interrupt_request & CPU_INTERRUPT_HARD) {
ppc_hw_interrupt(env);
if (env->pending_interrupts == 0) {
cpu->interrupt_request &= ~CPU_INTERRUPT_HARD;
}
if (env->pending_interrupts == 0)
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
next_tb = 0;
}
#elif defined(TARGET_LM32)
if ((interrupt_request & CPU_INTERRUPT_HARD)
&& (env->ie & IE_IE)) {
env->exception_index = EXCP_IRQ;
cc->do_interrupt(cpu);
do_interrupt(env);
next_tb = 0;
}
#elif defined(TARGET_MICROBLAZE)
@@ -400,7 +371,7 @@ int cpu_exec(CPUArchState *env)
&& !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
&& !(env->iflags & (D_FLAG | IMM_FLAG))) {
env->exception_index = EXCP_IRQ;
cc->do_interrupt(cpu);
do_interrupt(env);
next_tb = 0;
}
#elif defined(TARGET_MIPS)
@@ -409,7 +380,7 @@ int cpu_exec(CPUArchState *env)
/* Raise it */
env->exception_index = EXCP_EXT_INTERRUPT;
env->error_code = 0;
cc->do_interrupt(cpu);
do_interrupt(env);
next_tb = 0;
}
#elif defined(TARGET_OPENRISC)
@@ -425,7 +396,7 @@ int cpu_exec(CPUArchState *env)
}
if (idx >= 0) {
env->exception_index = idx;
cc->do_interrupt(cpu);
do_interrupt(env);
next_tb = 0;
}
}
@@ -440,7 +411,7 @@ int cpu_exec(CPUArchState *env)
cpu_pil_allowed(env, pil)) ||
type != TT_EXTINT) {
env->exception_index = env->interrupt_index;
cc->do_interrupt(cpu);
do_interrupt(env);
next_tb = 0;
}
}
@@ -449,7 +420,7 @@ int cpu_exec(CPUArchState *env)
if (interrupt_request & CPU_INTERRUPT_FIQ
&& !(env->uncached_cpsr & CPSR_F)) {
env->exception_index = EXCP_FIQ;
cc->do_interrupt(cpu);
do_interrupt(env);
next_tb = 0;
}
/* ARMv7-M interrupt return works by loading a magic value
@@ -465,19 +436,19 @@ int cpu_exec(CPUArchState *env)
&& ((IS_M(env) && env->regs[15] < 0xfffffff0)
|| !(env->uncached_cpsr & CPSR_I))) {
env->exception_index = EXCP_IRQ;
cc->do_interrupt(cpu);
do_interrupt(env);
next_tb = 0;
}
#elif defined(TARGET_UNICORE32)
if (interrupt_request & CPU_INTERRUPT_HARD
&& !(env->uncached_asr & ASR_I)) {
env->exception_index = UC32_EXCP_INTR;
cc->do_interrupt(cpu);
do_interrupt(env);
next_tb = 0;
}
#elif defined(TARGET_SH4)
if (interrupt_request & CPU_INTERRUPT_HARD) {
cc->do_interrupt(cpu);
do_interrupt(env);
next_tb = 0;
}
#elif defined(TARGET_ALPHA)
@@ -508,7 +479,7 @@ int cpu_exec(CPUArchState *env)
if (idx >= 0) {
env->exception_index = idx;
env->error_code = 0;
cc->do_interrupt(cpu);
do_interrupt(env);
next_tb = 0;
}
}
@@ -517,7 +488,7 @@ int cpu_exec(CPUArchState *env)
&& (env->pregs[PR_CCS] & I_FLAG)
&& !env->locked_irq) {
env->exception_index = EXCP_IRQ;
cc->do_interrupt(cpu);
do_interrupt(env);
next_tb = 0;
}
if (interrupt_request & CPU_INTERRUPT_NMI) {
@@ -529,7 +500,7 @@ int cpu_exec(CPUArchState *env)
}
if ((env->pregs[PR_CCS] & m_flag_archval)) {
env->exception_index = EXCP_NMI;
cc->do_interrupt(cpu);
do_interrupt(env);
next_tb = 0;
}
}
@@ -549,35 +520,38 @@ int cpu_exec(CPUArchState *env)
#elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(env->psw.mask & PSW_MASK_EXT)) {
cc->do_interrupt(cpu);
do_interrupt(env);
next_tb = 0;
}
#elif defined(TARGET_XTENSA)
if (interrupt_request & CPU_INTERRUPT_HARD) {
env->exception_index = EXC_IRQ;
cc->do_interrupt(cpu);
do_interrupt(env);
next_tb = 0;
}
#endif
/* Don't use the cached interrupt_request value,
do_interrupt may have updated the EXITTB flag. */
if (cpu->interrupt_request & CPU_INTERRUPT_EXITTB) {
cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
/* ensure that no TB jump will be modified as
the program flow was changed */
next_tb = 0;
}
}
if (unlikely(cpu->exit_request)) {
cpu->exit_request = 0;
if (unlikely(env->exit_request)) {
env->exit_request = 0;
env->exception_index = EXCP_INTERRUPT;
cpu_loop_exit(env);
}
#if defined(DEBUG_DISAS)
#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
/* restore flags in standard format */
#if defined(TARGET_I386)
env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
| (DF & DF_MASK);
log_cpu_state(env, CPU_DUMP_CCOP);
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
#elif defined(TARGET_M68K)
cpu_m68k_flush_flags(env, env->cc_op);
env->cc_op = CC_OP_FLAGS;
@@ -588,58 +562,47 @@ int cpu_exec(CPUArchState *env)
log_cpu_state(env, 0);
#endif
}
#endif /* DEBUG_DISAS */
spin_lock(&tcg_ctx.tb_ctx.tb_lock);
#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
spin_lock(&tb_lock);
tb = tb_find_fast(env);
/* Note: we do it here to avoid a gcc bug on Mac OS X when
doing it in tb_find_slow */
if (tcg_ctx.tb_ctx.tb_invalidated_flag) {
if (tb_invalidated_flag) {
/* as some TB could have been invalidated because
of memory exceptions while generating the code, we
must recompute the hash index here */
next_tb = 0;
tcg_ctx.tb_ctx.tb_invalidated_flag = 0;
}
if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
qemu_log("Trace %p [" TARGET_FMT_lx "] %s\n",
tb->tc_ptr, tb->pc, lookup_symbol(tb->pc));
tb_invalidated_flag = 0;
}
#ifdef CONFIG_DEBUG_EXEC
qemu_log_mask(CPU_LOG_EXEC, "Trace %p [" TARGET_FMT_lx "] %s\n",
tb->tc_ptr, tb->pc,
lookup_symbol(tb->pc));
#endif
/* see if we can patch the calling TB. When the TB
spans two pages, we cannot safely do a direct
jump. */
if (next_tb != 0 && tb->page_addr[1] == -1) {
tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK),
next_tb & TB_EXIT_MASK, tb);
tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
}
spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
spin_unlock(&tb_lock);
/* cpu_interrupt might be called while translating the
TB, but before it is linked into a potentially
infinite loop and becomes env->current_tb. Avoid
starting execution if there is a pending interrupt. */
cpu->current_tb = tb;
env->current_tb = tb;
barrier();
if (likely(!cpu->exit_request)) {
if (likely(!env->exit_request)) {
tc_ptr = tb->tc_ptr;
/* execute the generated code */
next_tb = cpu_tb_exec(cpu, tc_ptr);
switch (next_tb & TB_EXIT_MASK) {
case TB_EXIT_REQUESTED:
/* Something asked us to stop executing
* chained TBs; just continue round the main
* loop. Whatever requested the exit will also
* have set something else (eg exit_request or
* interrupt_request) which we will handle
* next time around the loop.
*/
tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
next_tb = 0;
break;
case TB_EXIT_ICOUNT_EXPIRED:
{
next_tb = tcg_qemu_tb_exec(env, tc_ptr);
if ((next_tb & 3) == 2) {
/* Instruction counter expired. */
int insns_left;
tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
tb = (TranslationBlock *)(next_tb & ~3);
/* Restore PC. */
cpu_pc_from_tb(env, tb);
insns_left = env->icount_decr.u32;
if (env->icount_extra && insns_left >= 0) {
/* Refill decrementer and continue execution. */
@@ -660,13 +623,9 @@ int cpu_exec(CPUArchState *env)
next_tb = 0;
cpu_loop_exit(env);
}
break;
}
default:
break;
}
}
cpu->current_tb = NULL;
env->current_tb = NULL;
/* reset soft MMU for next block (it can currently
only be set by a memory fault) */
} /* for(;;) */
@@ -695,7 +654,6 @@ int cpu_exec(CPUArchState *env)
| env->cc_dest | (env->cc_x << 4);
#elif defined(TARGET_MICROBLAZE)
#elif defined(TARGET_MIPS)
#elif defined(TARGET_MOXIE)
#elif defined(TARGET_OPENRISC)
#elif defined(TARGET_SH4)
#elif defined(TARGET_ALPHA)

93
cpus.c
View File

@@ -72,7 +72,7 @@ static bool cpu_thread_is_idle(CPUArchState *env)
if (cpu->stopped || !runstate_is_running()) {
return true;
}
if (!cpu->halted || qemu_cpu_has_work(cpu) ||
if (!env->halted || qemu_cpu_has_work(cpu) ||
kvm_async_interrupts_enabled()) {
return false;
}
@@ -419,7 +419,7 @@ void cpu_synchronize_all_post_reset(void)
CPUArchState *cpu;
for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
cpu_synchronize_post_reset(ENV_GET_CPU(cpu));
cpu_synchronize_post_reset(cpu);
}
}
@@ -428,7 +428,7 @@ void cpu_synchronize_all_post_init(void)
CPUArchState *cpu;
for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
cpu_synchronize_post_init(ENV_GET_CPU(cpu));
cpu_synchronize_post_init(cpu);
}
}
@@ -812,12 +812,6 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
static void tcg_exec_all(void);
static void tcg_signal_cpu_creation(CPUState *cpu, void *data)
{
cpu->thread_id = qemu_get_thread_id();
cpu->created = true;
}
static void *qemu_tcg_cpu_thread_fn(void *arg)
{
CPUState *cpu = arg;
@@ -826,8 +820,13 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
qemu_tcg_init_cpu_signals();
qemu_thread_get_self(cpu->thread);
/* signal CPU creation */
qemu_mutex_lock(&qemu_global_mutex);
qemu_for_each_cpu(tcg_signal_cpu_creation, NULL);
for (env = first_cpu; env != NULL; env = env->next_cpu) {
cpu = ENV_GET_CPU(env);
cpu->thread_id = qemu_get_thread_id();
cpu->created = true;
}
qemu_cond_signal(&qemu_cpu_cond);
/* wait for initial kick-off after machine start */
@@ -863,29 +862,9 @@ static void qemu_cpu_kick_thread(CPUState *cpu)
}
#else /* _WIN32 */
if (!qemu_cpu_is_self(cpu)) {
CONTEXT tcgContext;
if (SuspendThread(cpu->hThread) == (DWORD)-1) {
fprintf(stderr, "qemu:%s: GetLastError:%lu\n", __func__,
GetLastError());
exit(1);
}
/* On multi-core systems, we are not sure that the thread is actually
* suspended until we can get the context.
*/
tcgContext.ContextFlags = CONTEXT_CONTROL;
while (GetThreadContext(cpu->hThread, &tcgContext) != 0) {
continue;
}
SuspendThread(cpu->hThread);
cpu_signal(0);
if (ResumeThread(cpu->hThread) == (DWORD)-1) {
fprintf(stderr, "qemu:%s: GetLastError:%lu\n", __func__,
GetLastError());
exit(1);
}
ResumeThread(cpu->hThread);
}
#endif
}
@@ -974,10 +953,9 @@ void pause_all_vcpus(void)
if (qemu_in_vcpu_thread()) {
cpu_stop_current();
if (!kvm_enabled()) {
penv = first_cpu;
while (penv) {
CPUState *pcpu = ENV_GET_CPU(penv);
pcpu->stop = false;
pcpu->stop = 0;
pcpu->stopped = true;
penv = penv->next_cpu;
}
@@ -995,13 +973,6 @@ void pause_all_vcpus(void)
}
}
void cpu_resume(CPUState *cpu)
{
cpu->stop = false;
cpu->stopped = false;
qemu_cpu_kick(cpu);
}
void resume_all_vcpus(void)
{
CPUArchState *penv = first_cpu;
@@ -1009,7 +980,9 @@ void resume_all_vcpus(void)
qemu_clock_enable(vm_clock, true);
while (penv) {
CPUState *pcpu = ENV_GET_CPU(penv);
cpu_resume(pcpu);
pcpu->stop = false;
pcpu->stopped = false;
qemu_cpu_kick(pcpu);
penv = penv->next_cpu;
}
}
@@ -1202,6 +1175,27 @@ void set_numa_modes(void)
}
}
void set_cpu_log(const char *optarg)
{
int mask;
const CPULogItem *item;
mask = cpu_str_to_log_mask(optarg);
if (!mask) {
printf("Log items (comma separated):\n");
for (item = cpu_log_items; item->mask != 0; item++) {
printf("%-10s %s\n", item->name, item->help);
}
exit(1);
}
cpu_set_log(mask);
}
void set_cpu_log_filename(const char *optarg)
{
cpu_set_log_filename(optarg);
}
void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
{
/* XXX: implement xxx_cpu_list for targets that still miss it */
@@ -1225,7 +1219,7 @@ CpuInfoList *qmp_query_cpus(Error **errp)
info->value = g_malloc0(sizeof(*info->value));
info->value->CPU = cpu->cpu_index;
info->value->current = (env == first_cpu);
info->value->halted = cpu->halted;
info->value->halted = env->halted;
info->value->thread_id = cpu->thread_id;
#if defined(TARGET_I386)
info->value->has_pc = true;
@@ -1268,13 +1262,18 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename,
cpu_index = 0;
}
cpu = qemu_get_cpu(cpu_index);
if (cpu == NULL) {
for (env = first_cpu; env; env = env->next_cpu) {
cpu = ENV_GET_CPU(env);
if (cpu_index == cpu->cpu_index) {
break;
}
}
if (env == NULL) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
"a CPU number");
return;
}
env = cpu->env_ptr;
f = fopen(filename, "wb");
if (!f) {
@@ -1336,7 +1335,7 @@ void qmp_inject_nmi(Error **errp)
for (env = first_cpu; env != NULL; env = env->next_cpu) {
if (!env->apic_state) {
cpu_interrupt(CPU(x86_env_get_cpu(env)), CPU_INTERRUPT_NMI);
cpu_interrupt(env, CPU_INTERRUPT_NMI);
} else {
apic_deliver_nmi(env->apic_state);
}

View File

@@ -54,7 +54,6 @@ static const CPUTLBEntry s_cputlb_empty_entry = {
*/
void tlb_flush(CPUArchState *env, int flush_global)
{
CPUState *cpu = ENV_GET_CPU(env);
int i;
#if defined(DEBUG_TLB)
@@ -62,7 +61,7 @@ void tlb_flush(CPUArchState *env, int flush_global)
#endif
/* must reset current TB so that interrupts cannot modify the
links while we are modifying them */
cpu->current_tb = NULL;
env->current_tb = NULL;
for (i = 0; i < CPU_TLB_SIZE; i++) {
int mmu_idx;
@@ -93,7 +92,6 @@ static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
void tlb_flush_page(CPUArchState *env, target_ulong addr)
{
CPUState *cpu = ENV_GET_CPU(env);
int i;
int mmu_idx;
@@ -112,7 +110,7 @@ void tlb_flush_page(CPUArchState *env, target_ulong addr)
}
/* must reset current TB so that interrupts cannot modify the
links while we are modifying them */
cpu->current_tb = NULL;
env->current_tb = NULL;
addr &= TARGET_PAGE_MASK;
i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);

View File

@@ -1,7 +1,6 @@
# Default configuration for alpha-softmmu
include pci.mak
include usb.mak
CONFIG_SERIAL=y
CONFIG_I8254=y
CONFIG_PCKBD=y
@@ -13,4 +12,3 @@ CONFIG_IDE_QDEV=y
CONFIG_VMWARE_VGA=y
CONFIG_IDE_CMD646=y
CONFIG_I8259=y
CONFIG_MC146818RTC=y

View File

@@ -1,7 +1,6 @@
# Default configuration for arm-softmmu
include pci.mak
include usb.mak
CONFIG_GDBSTUB_XML=y
CONFIG_VGA=y
CONFIG_ISA_MMIO=y
@@ -16,9 +15,7 @@ CONFIG_TWL92230=y
CONFIG_TSC2005=y
CONFIG_LM832X=y
CONFIG_TMP105=y
CONFIG_STELLARIS=y
CONFIG_STELLARIS_INPUT=y
CONFIG_STELLARIS_ENET=y
CONFIG_SSD0303=y
CONFIG_SSD0323=y
CONFIG_ADS7846=y
@@ -31,17 +28,8 @@ CONFIG_SMC91C111=y
CONFIG_DS1338=y
CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y
CONFIG_MICRODRIVE=y
CONFIG_USB_MUSB=y
CONFIG_ARM9MPCORE=y
CONFIG_ARM11MPCORE=y
CONFIG_ARM15MPCORE=y
CONFIG_ARM_GIC=y
CONFIG_ARM_GIC_KVM=$(CONFIG_KVM)
CONFIG_ARM_TIMER=y
CONFIG_ARM_MPTIMER=y
CONFIG_PL011=y
CONFIG_PL022=y
CONFIG_PL031=y
@@ -53,30 +41,8 @@ CONFIG_PL110=y
CONFIG_PL181=y
CONFIG_PL190=y
CONFIG_PL310=y
CONFIG_PL330=y
CONFIG_CADENCE=y
CONFIG_XGMAC=y
CONFIG_EXYNOS4=y
CONFIG_PXA2XX=y
CONFIG_BITBANG_I2C=y
CONFIG_FRAMEBUFFER=y
CONFIG_XILINX_SPIPS=y
CONFIG_A9SCU=y
CONFIG_MARVELL_88W8618=y
CONFIG_OMAP=y
CONFIG_TSC210X=y
CONFIG_BLIZZARD=y
CONFIG_ONENAND=y
CONFIG_TUSB6010=y
CONFIG_IMX=y
CONFIG_MAINSTONE=y
CONFIG_NSERIES=y
CONFIG_REALVIEW=y
CONFIG_ZAURUS=y
CONFIG_ZYNQ=y
CONFIG_VERSATILE_PCI=y
CONFIG_VERSATILE_I2C=y
CONFIG_SDHCI=y

View File

@@ -1,6 +1,5 @@
# Default configuration for cris-softmmu
CONFIG_ETRAXFS=y
CONFIG_NAND=y
CONFIG_PTIMER=y
CONFIG_PFLASH_CFI02=y

View File

@@ -1,10 +1,7 @@
# Default configuration for i386-softmmu
include pci.mak
include sound.mak
include usb.mak
CONFIG_VGA=y
CONFIG_QXL=$(CONFIG_SPICE)
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_CIRRUS=y
@@ -18,31 +15,13 @@ CONFIG_PCKBD=y
CONFIG_FDC=y
CONFIG_ACPI=y
CONFIG_APM=y
CONFIG_I8257=y
CONFIG_DMA=y
CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y
CONFIG_PIIX_PCI=y
CONFIG_SOUND=y
CONFIG_HPET=y
CONFIG_APPLESMC=y
CONFIG_I8259=y
CONFIG_PFLASH_CFI01=y
CONFIG_TPM_TIS=$(CONFIG_TPM)
CONFIG_PCI_HOTPLUG=y
CONFIG_MC146818RTC=y
CONFIG_PAM=y
CONFIG_PCI_PIIX=y
CONFIG_PCI_HOTPLUG=y
CONFIG_WDT_IB700=y
CONFIG_PC_SYSFW=y
CONFIG_XEN_I386=$(CONFIG_XEN)
CONFIG_ISA_DEBUG=y
CONFIG_ISA_TESTDEV=y
CONFIG_VMPORT=y
CONFIG_SGA=y
CONFIG_LPC_ICH9=y
CONFIG_PCI_Q35=y
CONFIG_APIC=y
CONFIG_IOAPIC=y
CONFIG_ICC_BUS=y
CONFIG_PVPANIC=y

View File

@@ -1,9 +1,5 @@
# Default configuration for lm32-softmmu
CONFIG_LM32=y
CONFIG_MILKYMIST=y
CONFIG_MILKYMIST_TMU2=$(CONFIG_GLX)
CONFIG_FRAMEBUFFER=y
CONFIG_PTIMER=y
CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y

View File

@@ -1,7 +1,5 @@
# Default configuration for m68k-softmmu
include pci.mak
include usb.mak
CONFIG_COLDFIRE=y
CONFIG_GDBSTUB_XML=y
CONFIG_PTIMER=y

View File

@@ -5,7 +5,5 @@ CONFIG_PFLASH_CFI01=y
CONFIG_SERIAL=y
CONFIG_XILINX=y
CONFIG_XILINX_AXI=y
CONFIG_XILINX_SPI=y
CONFIG_XILINX_ETHLITE=y
CONFIG_SSI=y
CONFIG_SSI_M25P80=y

View File

@@ -5,7 +5,5 @@ CONFIG_PFLASH_CFI01=y
CONFIG_SERIAL=y
CONFIG_XILINX=y
CONFIG_XILINX_AXI=y
CONFIG_XILINX_SPI=y
CONFIG_XILINX_ETHLITE=y
CONFIG_SSI=y
CONFIG_SSI_M25P80=y

View File

@@ -1,8 +1,6 @@
# Default configuration for mips-softmmu
include pci.mak
include sound.mak
include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y
@@ -19,11 +17,12 @@ CONFIG_PCKBD=y
CONFIG_FDC=y
CONFIG_ACPI=y
CONFIG_APM=y
CONFIG_I8257=y
CONFIG_DMA=y
CONFIG_PIIX4=y
CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y
CONFIG_SOUND=y
CONFIG_RC4030=y
CONFIG_DP8393X=y
CONFIG_DS1225Y=y
@@ -32,5 +31,3 @@ CONFIG_PFLASH_CFI01=y
CONFIG_G364FB=y
CONFIG_I8259=y
CONFIG_JAZZ_LED=y
CONFIG_MC146818RTC=y
CONFIG_VT82C686=y

View File

@@ -1,8 +1,6 @@
# Default configuration for mips64-softmmu
include pci.mak
include sound.mak
include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y
@@ -19,11 +17,12 @@ CONFIG_PCKBD=y
CONFIG_FDC=y
CONFIG_ACPI=y
CONFIG_APM=y
CONFIG_I8257=y
CONFIG_DMA=y
CONFIG_PIIX4=y
CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y
CONFIG_SOUND=y
CONFIG_RC4030=y
CONFIG_DP8393X=y
CONFIG_DS1225Y=y
@@ -32,5 +31,3 @@ CONFIG_PFLASH_CFI01=y
CONFIG_G364FB=y
CONFIG_I8259=y
CONFIG_JAZZ_LED=y
CONFIG_MC146818RTC=y
CONFIG_VT82C686=y

View File

@@ -1,8 +1,6 @@
# Default configuration for mips64el-softmmu
include pci.mak
include sound.mak
include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y
@@ -19,12 +17,13 @@ CONFIG_PCKBD=y
CONFIG_FDC=y
CONFIG_ACPI=y
CONFIG_APM=y
CONFIG_I8257=y
CONFIG_DMA=y
CONFIG_PIIX4=y
CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y
CONFIG_IDE_VIA=y
CONFIG_NE2000_ISA=y
CONFIG_SOUND=y
CONFIG_RC4030=y
CONFIG_DP8393X=y
CONFIG_DS1225Y=y
@@ -34,5 +33,3 @@ CONFIG_FULONG=y
CONFIG_G364FB=y
CONFIG_I8259=y
CONFIG_JAZZ_LED=y
CONFIG_MC146818RTC=y
CONFIG_VT82C686=y

View File

@@ -1,8 +1,6 @@
# Default configuration for mipsel-softmmu
include pci.mak
include sound.mak
include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y
@@ -19,11 +17,12 @@ CONFIG_PCKBD=y
CONFIG_FDC=y
CONFIG_ACPI=y
CONFIG_APM=y
CONFIG_I8257=y
CONFIG_DMA=y
CONFIG_PIIX4=y
CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y
CONFIG_SOUND=y
CONFIG_RC4030=y
CONFIG_DP8393X=y
CONFIG_DS1225Y=y
@@ -32,5 +31,3 @@ CONFIG_PFLASH_CFI01=y
CONFIG_G364FB=y
CONFIG_I8259=y
CONFIG_JAZZ_LED=y
CONFIG_MC146818RTC=y
CONFIG_VT82C686=y

View File

@@ -1,5 +0,0 @@
# Default configuration for moxie-softmmu
CONFIG_MC146818RTC=y
CONFIG_SERIAL=y
CONFIG_VGA=y

View File

@@ -9,15 +9,10 @@ CONFIG_NE2000_PCI=y
CONFIG_EEPRO100_PCI=y
CONFIG_PCNET_PCI=y
CONFIG_PCNET_COMMON=y
CONFIG_AC97=y
CONFIG_HDA=y
CONFIG_ES1370=y
CONFIG_LSI_SCSI_PCI=y
CONFIG_VMW_PVSCSI_SCSI_PCI=y
CONFIG_MEGASAS_SCSI_PCI=y
CONFIG_RTL8139_PCI=y
CONFIG_E1000_PCI=y
CONFIG_VMXNET3_PCI=y
CONFIG_IDE_CORE=y
CONFIG_IDE_QDEV=y
CONFIG_IDE_PCI=y
@@ -27,5 +22,3 @@ CONFIG_ESP_PCI=y
CONFIG_SERIAL=y
CONFIG_SERIAL_PCI=y
CONFIG_IPACK=y
CONFIG_WDT_IB6300ESB=y
CONFIG_PCI_TESTDEV=y

View File

@@ -1,8 +1,6 @@
# Default configuration for ppc-softmmu
include pci.mak
include sound.mak
include usb.mak
CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
@@ -14,7 +12,7 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y
CONFIG_PCKBD=y
CONFIG_FDC=y
CONFIG_I8257=y
CONFIG_DMA=y
CONFIG_I82374=y
CONFIG_OPENPIC=y
CONFIG_PREP_PCI=y
@@ -35,13 +33,9 @@ CONFIG_IDE_ISA=y
CONFIG_IDE_CMD646=y
CONFIG_IDE_MACIO=y
CONFIG_NE2000_ISA=y
CONFIG_SOUND=y
CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y
CONFIG_PTIMER=y
CONFIG_I8259=y
CONFIG_XILINX=y
CONFIG_XILINX_ETHLITE=y
CONFIG_OPENPIC=y
CONFIG_E500=$(CONFIG_FDT)
# For PReP
CONFIG_MC146818RTC=y

View File

@@ -1,8 +1,6 @@
# Default configuration for ppc64-softmmu
include pci.mak
include sound.mak
include usb.mak
CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
@@ -14,7 +12,7 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y
CONFIG_PCKBD=y
CONFIG_FDC=y
CONFIG_I8257=y
CONFIG_DMA=y
CONFIG_I82374=y
CONFIG_OPENPIC=y
CONFIG_PREP_PCI=y
@@ -35,16 +33,9 @@ CONFIG_IDE_ISA=y
CONFIG_IDE_CMD646=y
CONFIG_IDE_MACIO=y
CONFIG_NE2000_ISA=y
CONFIG_SOUND=y
CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y
CONFIG_PTIMER=y
CONFIG_I8259=y
CONFIG_XILINX=y
CONFIG_XILINX_ETHLITE=y
CONFIG_OPENPIC=y
CONFIG_PSERIES=$(CONFIG_FDT)
CONFIG_E500=$(CONFIG_FDT)
# For pSeries
CONFIG_PCI_HOTPLUG=y
# For PReP
CONFIG_MC146818RTC=y

View File

@@ -1,8 +1,6 @@
# Default configuration for ppcemb-softmmu
include pci.mak
include sound.mak
include usb.mak
CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
@@ -13,7 +11,7 @@ CONFIG_SERIAL=y
CONFIG_I8254=y
CONFIG_PCKBD=y
CONFIG_FDC=y
CONFIG_I8257=y
CONFIG_DMA=y
CONFIG_OPENPIC=y
CONFIG_PREP_PCI=y
CONFIG_MACIO=y
@@ -30,13 +28,9 @@ CONFIG_IDE_ISA=y
CONFIG_IDE_CMD646=y
CONFIG_IDE_MACIO=y
CONFIG_NE2000_ISA=y
CONFIG_SOUND=y
CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y
CONFIG_PTIMER=y
CONFIG_I8259=y
CONFIG_XILINX=y
CONFIG_XILINX_ETHLITE=y
CONFIG_OPENPIC=y
CONFIG_E500=$(CONFIG_FDT)
# For PReP
CONFIG_MC146818RTC=y

View File

@@ -1,2 +1 @@
CONFIG_VIRTIO=y
CONFIG_SCLPCONSOLE=y

View File

@@ -1,11 +1,7 @@
# Default configuration for sh4-softmmu
include pci.mak
include usb.mak
CONFIG_SERIAL=y
CONFIG_PTIMER=y
CONFIG_PFLASH_CFI02=y
CONFIG_ISA_MMIO=y
CONFIG_SH4=y
CONFIG_IDE_MMIO=y
CONFIG_SM501=y

View File

@@ -1,11 +1,7 @@
# Default configuration for sh4eb-softmmu
include pci.mak
include usb.mak
CONFIG_SERIAL=y
CONFIG_PTIMER=y
CONFIG_PFLASH_CFI02=y
CONFIG_ISA_MMIO=y
CONFIG_SH4=y
CONFIG_IDE_MMIO=y
CONFIG_SM501=y

View File

@@ -1,4 +0,0 @@
CONFIG_SB16=y
CONFIG_ADLIB=y
CONFIG_GUS=y
CONFIG_CS4231A=y

View File

@@ -8,11 +8,3 @@ CONFIG_PTIMER=y
CONFIG_FDC=y
CONFIG_EMPTY_SLOT=y
CONFIG_PCNET_COMMON=y
CONFIG_LANCE=y
CONFIG_TCX=y
CONFIG_SLAVIO=y
CONFIG_CS4231=y
CONFIG_GRLIB=y
CONFIG_STP2000=y
CONFIG_ECCMEMCTL=y
CONFIG_SUN4M=y

View File

@@ -1,7 +1,6 @@
# Default configuration for sparc64-softmmu
include pci.mak
include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_M48T59=y
CONFIG_PTIMER=y
@@ -13,5 +12,3 @@ CONFIG_PCKBD=y
CONFIG_FDC=y
CONFIG_IDE_ISA=y
CONFIG_IDE_CMD646=y
CONFIG_PCI_APB=y
CONFIG_MC146818RTC=y

View File

@@ -1,8 +0,0 @@
CONFIG_USB_TABLET_WACOM=y
CONFIG_USB_STORAGE_BOT=y
CONFIG_USB_STORAGE_UAS=y
CONFIG_USB_SMARTCARD=y
CONFIG_USB_AUDIO=y
CONFIG_USB_SERIAL=y
CONFIG_USB_NETWORK=y
CONFIG_USB_BLUETOOTH=y

View File

@@ -1,10 +1,7 @@
# Default configuration for x86_64-softmmu
include pci.mak
include sound.mak
include usb.mak
CONFIG_VGA=y
CONFIG_QXL=$(CONFIG_SPICE)
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_CIRRUS=y
@@ -18,31 +15,13 @@ CONFIG_PCKBD=y
CONFIG_FDC=y
CONFIG_ACPI=y
CONFIG_APM=y
CONFIG_I8257=y
CONFIG_DMA=y
CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y
CONFIG_PIIX_PCI=y
CONFIG_SOUND=y
CONFIG_HPET=y
CONFIG_APPLESMC=y
CONFIG_I8259=y
CONFIG_PFLASH_CFI01=y
CONFIG_TPM_TIS=$(CONFIG_TPM)
CONFIG_PCI_HOTPLUG=y
CONFIG_MC146818RTC=y
CONFIG_PAM=y
CONFIG_PCI_PIIX=y
CONFIG_PCI_HOTPLUG=y
CONFIG_WDT_IB700=y
CONFIG_PC_SYSFW=y
CONFIG_XEN_I386=$(CONFIG_XEN)
CONFIG_ISA_DEBUG=y
CONFIG_ISA_TESTDEV=y
CONFIG_VMPORT=y
CONFIG_SGA=y
CONFIG_LPC_ICH9=y
CONFIG_PCI_Q35=y
CONFIG_APIC=y
CONFIG_IOAPIC=y
CONFIG_ICC_BUS=y
CONFIG_PVPANIC=y

View File

@@ -227,7 +227,6 @@ void target_disas(FILE *out, CPUArchState *env, target_ulong code,
s.info.mach = bfd_mach_ppc;
#endif
}
s.info.disassembler_options = (char *)"any";
print_insn = print_insn_ppc;
#elif defined(TARGET_M68K)
print_insn = print_insn_m68k;
@@ -257,9 +256,6 @@ void target_disas(FILE *out, CPUArchState *env, target_ulong code,
#elif defined(TARGET_MICROBLAZE)
s.info.mach = bfd_arch_microblaze;
print_insn = print_insn_microblaze;
#elif defined(TARGET_MOXIE)
s.info.mach = bfd_arch_moxie;
print_insn = print_insn_moxie;
#elif defined(TARGET_LM32)
s.info.mach = bfd_mach_lm32;
print_insn = print_insn_lm32;
@@ -326,7 +322,6 @@ void disas(FILE *out, void *code, unsigned long size)
s.info.mach = bfd_mach_x86_64;
print_insn = print_insn_i386;
#elif defined(_ARCH_PPC)
s.info.disassembler_options = (char *)"any";
print_insn = print_insn_ppc;
#elif defined(__alpha__)
print_insn = print_insn_alpha;
@@ -467,9 +462,6 @@ void monitor_disas(Monitor *mon, CPUArchState *env,
#elif defined(TARGET_S390X)
s.info.mach = bfd_mach_s390_64;
print_insn = print_insn_s390;
#elif defined(TARGET_MOXIE)
s.info.mach = bfd_arch_moxie;
print_insn = print_insn_moxie;
#elif defined(TARGET_LM32)
s.info.mach = bfd_mach_lm32;
print_insn = print_insn_lm32;

View File

@@ -7,7 +7,6 @@ common-obj-$(CONFIG_IA64_DIS) += ia64.o
common-obj-$(CONFIG_M68K_DIS) += m68k.o
common-obj-$(CONFIG_MICROBLAZE_DIS) += microblaze.o
common-obj-$(CONFIG_MIPS_DIS) += mips.o
common-obj-$(CONFIG_MOXIE_DIS) += moxie.o
common-obj-$(CONFIG_PPC_DIS) += ppc.o
common-obj-$(CONFIG_S390_DIS) += s390.o
common-obj-$(CONFIG_SH4_DIS) += sh4.o

View File

@@ -819,10 +819,6 @@ static const struct opcode32 arm_opcodes[] =
{ARM_EXT_V3M, 0x00800090, 0x0fa000f0, "%22?sumull%20's%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
{ARM_EXT_V3M, 0x00a00090, 0x0fa000f0, "%22?sumlal%20's%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
/* IDIV instructions. */
{ARM_EXT_DIV, 0x0710f010, 0x0ff0f0f0, "sdiv%c\t%16-19r, %0-3r, %8-11r"},
{ARM_EXT_DIV, 0x0730f010, 0x0ff0f0f0, "udiv%c\t%16-19r, %0-3r, %8-11r"},
/* V7 instructions. */
{ARM_EXT_V7, 0xf450f000, 0xfd70f000, "pli\t%P"},
{ARM_EXT_V7, 0x0320f0f0, 0x0ffffff0, "dbg%c\t#%0-3d"},

View File

@@ -226,7 +226,7 @@ struct dis_private {
bfd_byte the_buffer[MAX_MNEM_SIZE];
bfd_vma insn_start;
int orig_sizeflag;
sigjmp_buf bailout;
jmp_buf bailout;
};
enum address_mode
@@ -303,7 +303,7 @@ fetch_data2(struct disassemble_info *info, bfd_byte *addr)
STATUS. */
if (priv->max_fetched == priv->the_buffer)
(*info->memory_error_func) (status, start, info);
siglongjmp(priv->bailout, 1);
longjmp (priv->bailout, 1);
}
else
priv->max_fetched = addr;
@@ -664,13 +664,6 @@ fetch_data(struct disassemble_info *info, bfd_byte *addr)
#define PREGRP95 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 95 } }
#define PREGRP96 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 96 } }
#define PREGRP97 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 97 } }
#define PREGRP98 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 98 } }
#define PREGRP99 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 99 } }
#define PREGRP100 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 100 } }
#define PREGRP101 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 101 } }
#define PREGRP102 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 102 } }
#define PREGRP103 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 103 } }
#define PREGRP104 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 104 } }
#define X86_64_0 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 0 } }
@@ -1447,7 +1440,7 @@ static const unsigned char threebyte_0x38_uses_DATA_prefix[256] = {
/* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
/* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
/* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
/* d0 */ 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1, /* df */
/* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
/* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
/* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
/* ------------------------------- */
@@ -1510,7 +1503,7 @@ static const unsigned char threebyte_0x3a_uses_DATA_prefix[256] = {
/* 10 */ 0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 1f */
/* 20 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */
/* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
/* 40 */ 1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
/* 40 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
/* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
/* 60 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
/* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */
@@ -1519,7 +1512,7 @@ static const unsigned char threebyte_0x3a_uses_DATA_prefix[256] = {
/* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
/* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
/* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
/* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* df */
/* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
/* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
/* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
/* ------------------------------- */
@@ -2717,63 +2710,6 @@ static const struct dis386 prefix_user_table[][4] = {
{ "punpckldq",{ MX, EMq } },
{ "(bad)", { XX } },
},
/* PREGRP98 */
{
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ "pclmulqdq", { XM, EXx, Ib } },
{ "(bad)", { XX } },
},
/* PREGRP99 */
{
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ "aesimc", { XM, EXx } },
{ "(bad)", { XX } },
},
/* PREGRP100 */
{
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ "aesenc", { XM, EXx } },
{ "(bad)", { XX } },
},
/* PREGRP101 */
{
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ "aesenclast", { XM, EXx } },
{ "(bad)", { XX } },
},
/* PREGRP102 */
{
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ "aesdec", { XM, EXx } },
{ "(bad)", { XX } },
},
/* PREGRP103 */
{
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ "aesdeclast", { XM, EXx } },
{ "(bad)", { XX } },
},
/* PREGRP104 */
{
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ "aeskeygenassist", { XM, EXx, Ib } },
{ "(bad)", { XX } },
},
};
static const struct dis386 x86_64_table[][2] = {
@@ -3045,11 +2981,11 @@ static const struct dis386 three_byte_table[][256] = {
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ PREGRP99 },
{ PREGRP100 },
{ PREGRP101 },
{ PREGRP102 },
{ PREGRP103 },
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ "(bad)", { XX } },
/* e0 */
{ "(bad)", { XX } },
{ "(bad)", { XX } },
@@ -3166,7 +3102,7 @@ static const struct dis386 three_byte_table[][256] = {
{ PREGRP84 },
{ PREGRP85 },
{ "(bad)", { XX } },
{ PREGRP98 },
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ "(bad)", { XX } },
@@ -3340,7 +3276,7 @@ static const struct dis386 three_byte_table[][256] = {
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ "(bad)", { XX } },
{ PREGRP104 },
{ "(bad)", { XX } },
/* e0 */
{ "(bad)", { XX } },
{ "(bad)", { XX } },
@@ -3725,7 +3661,7 @@ print_insn (bfd_vma pc, disassemble_info *info)
start_codep = priv.the_buffer;
codep = priv.the_buffer;
if (sigsetjmp(priv.bailout, 0) != 0)
if (setjmp (priv.bailout) != 0)
{
const char *name;
@@ -4784,8 +4720,7 @@ print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp)
buf[0] = '0';
buf[1] = 'x';
snprintf_vma (tmp, sizeof(tmp), disp);
for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++) {
}
for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++);
pstrcpy (buf + 2, bufsize - 2, tmp + i);
}
else

View File

@@ -303,11 +303,11 @@ int print_insn_lm32(bfd_vma memaddr, struct disassemble_info *info)
}
case 'c': {
uint8_t csr;
const Lm32CsrInfo *info;
const char *csr_name;
csr = (op >> 21) & 0x1f;
info = find_csr_info(csr);
if (info) {
fprintf_fn(stream, "%s", info->name);
csr_name = find_csr_info(csr)->name;
if (csr_name) {
fprintf_fn(stream, "%s", csr_name);
} else {
fprintf_fn(stream, "0x%x", csr);
}

View File

@@ -624,7 +624,7 @@ struct private
bfd_byte *max_fetched;
bfd_byte the_buffer[MAXLEN];
bfd_vma insn_start;
sigjmp_buf bailout;
jmp_buf bailout;
};
/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
@@ -644,7 +644,7 @@ fetch_data2(struct disassemble_info *info, bfd_byte *addr)
if (status != 0)
{
(*info->memory_error_func) (status, start, info);
siglongjmp(priv->bailout, 1);
longjmp (priv->bailout, 1);
}
else
priv->max_fetched = addr;
@@ -1912,10 +1912,9 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
priv.max_fetched = priv.the_buffer;
priv.insn_start = memaddr;
if (sigsetjmp(priv.bailout, 0) != 0) {
if (setjmp (priv.bailout) != 0)
/* Error return. */
return -1;
}
switch (info->mach)
{

View File

@@ -1,360 +0,0 @@
/* Disassemble moxie instructions.
Copyright (c) 2009 Free Software Foundation, 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/>. */
#include <stdio.h>
#define STATIC_TABLE
#define DEFINE_TABLE
#include "disas/bfd.h"
static void *stream;
/* Form 1 instructions come in different flavors:
Some have no arguments (MOXIE_F1_NARG)
Some only use the A operand (MOXIE_F1_A)
Some use A and B registers (MOXIE_F1_AB)
Some use A and consume a 4 byte immediate value (MOXIE_F1_A4)
Some use just a 4 byte immediate value (MOXIE_F1_4)
Some use just a 4 byte memory address (MOXIE_F1_M)
Some use B and an indirect A (MOXIE_F1_AiB)
Some use A and an indirect B (MOXIE_F1_ABi)
Some consume a 4 byte immediate value and use X (MOXIE_F1_4A)
Some use B and an indirect A plus 4 bytes (MOXIE_F1_AiB4)
Some use A and an indirect B plus 4 bytes (MOXIE_F1_ABi4)
Form 2 instructions also come in different flavors:
Some have no arguments (MOXIE_F2_NARG)
Some use the A register and an 8-bit value (MOXIE_F2_A8V)
Form 3 instructions also come in different flavors:
Some have no arguments (MOXIE_F3_NARG)
Some have a 10-bit PC relative operand (MOXIE_F3_PCREL). */
#define MOXIE_F1_NARG 0x100
#define MOXIE_F1_A 0x101
#define MOXIE_F1_AB 0x102
/* #define MOXIE_F1_ABC 0x103 */
#define MOXIE_F1_A4 0x104
#define MOXIE_F1_4 0x105
#define MOXIE_F1_AiB 0x106
#define MOXIE_F1_ABi 0x107
#define MOXIE_F1_4A 0x108
#define MOXIE_F1_AiB4 0x109
#define MOXIE_F1_ABi4 0x10a
#define MOXIE_F1_M 0x10b
#define MOXIE_F2_NARG 0x200
#define MOXIE_F2_A8V 0x201
#define MOXIE_F3_NARG 0x300
#define MOXIE_F3_PCREL 0x301
typedef struct moxie_opc_info_t {
short opcode;
unsigned itype;
const char * name;
} moxie_opc_info_t;
extern const moxie_opc_info_t moxie_form1_opc_info[64];
extern const moxie_opc_info_t moxie_form2_opc_info[4];
extern const moxie_opc_info_t moxie_form3_opc_info[16];
/* The moxie processor's 16-bit instructions come in two forms:
FORM 1 instructions start with a 0 bit...
0oooooooaaaabbbb
0 F
ooooooo - form 1 opcode number
aaaa - operand A
bbbb - operand B
FORM 2 instructions start with bits "10"...
10ooaaaavvvvvvvv
0 F
oo - form 2 opcode number
aaaa - operand A
vvvvvvvv - 8-bit immediate value
FORM 3 instructions start with a bits "11"...
11oooovvvvvvvvvv
0 F
oooo - form 3 opcode number
vvvvvvvvvv - 10-bit immediate value. */
const moxie_opc_info_t moxie_form1_opc_info[64] =
{
{ 0x00, MOXIE_F1_NARG, "nop" },
{ 0x01, MOXIE_F1_A4, "ldi.l" },
{ 0x02, MOXIE_F1_AB, "mov" },
{ 0x03, MOXIE_F1_M, "jsra" },
{ 0x04, MOXIE_F1_NARG, "ret" },
{ 0x05, MOXIE_F1_AB, "add.l" },
{ 0x06, MOXIE_F1_AB, "push" },
{ 0x07, MOXIE_F1_AB, "pop" },
{ 0x08, MOXIE_F1_A4, "lda.l" },
{ 0x09, MOXIE_F1_4A, "sta.l" },
{ 0x0a, MOXIE_F1_ABi, "ld.l" },
{ 0x0b, MOXIE_F1_AiB, "st.l" },
{ 0x0c, MOXIE_F1_ABi4, "ldo.l" },
{ 0x0d, MOXIE_F1_AiB4, "sto.l" },
{ 0x0e, MOXIE_F1_AB, "cmp" },
{ 0x0f, MOXIE_F1_NARG, "bad" },
{ 0x10, MOXIE_F1_NARG, "bad" },
{ 0x11, MOXIE_F1_NARG, "bad" },
{ 0x12, MOXIE_F1_NARG, "bad" },
{ 0x13, MOXIE_F1_NARG, "bad" },
{ 0x14, MOXIE_F1_NARG, "bad" },
{ 0x15, MOXIE_F1_NARG, "bad" },
{ 0x16, MOXIE_F1_NARG, "bad" },
{ 0x17, MOXIE_F1_NARG, "bad" },
{ 0x18, MOXIE_F1_NARG, "bad" },
{ 0x19, MOXIE_F1_A, "jsr" },
{ 0x1a, MOXIE_F1_M, "jmpa" },
{ 0x1b, MOXIE_F1_A4, "ldi.b" },
{ 0x1c, MOXIE_F1_ABi, "ld.b" },
{ 0x1d, MOXIE_F1_A4, "lda.b" },
{ 0x1e, MOXIE_F1_AiB, "st.b" },
{ 0x1f, MOXIE_F1_4A, "sta.b" },
{ 0x20, MOXIE_F1_A4, "ldi.s" },
{ 0x21, MOXIE_F1_ABi, "ld.s" },
{ 0x22, MOXIE_F1_A4, "lda.s" },
{ 0x23, MOXIE_F1_AiB, "st.s" },
{ 0x24, MOXIE_F1_4A, "sta.s" },
{ 0x25, MOXIE_F1_A, "jmp" },
{ 0x26, MOXIE_F1_AB, "and" },
{ 0x27, MOXIE_F1_AB, "lshr" },
{ 0x28, MOXIE_F1_AB, "ashl" },
{ 0x29, MOXIE_F1_AB, "sub.l" },
{ 0x2a, MOXIE_F1_AB, "neg" },
{ 0x2b, MOXIE_F1_AB, "or" },
{ 0x2c, MOXIE_F1_AB, "not" },
{ 0x2d, MOXIE_F1_AB, "ashr" },
{ 0x2e, MOXIE_F1_AB, "xor" },
{ 0x2f, MOXIE_F1_AB, "mul.l" },
{ 0x30, MOXIE_F1_4, "swi" },
{ 0x31, MOXIE_F1_AB, "div.l" },
{ 0x32, MOXIE_F1_AB, "udiv.l" },
{ 0x33, MOXIE_F1_AB, "mod.l" },
{ 0x34, MOXIE_F1_AB, "umod.l" },
{ 0x35, MOXIE_F1_NARG, "brk" },
{ 0x36, MOXIE_F1_ABi4, "ldo.b" },
{ 0x37, MOXIE_F1_AiB4, "sto.b" },
{ 0x38, MOXIE_F1_ABi4, "ldo.s" },
{ 0x39, MOXIE_F1_AiB4, "sto.s" },
{ 0x3a, MOXIE_F1_NARG, "bad" },
{ 0x3b, MOXIE_F1_NARG, "bad" },
{ 0x3c, MOXIE_F1_NARG, "bad" },
{ 0x3d, MOXIE_F1_NARG, "bad" },
{ 0x3e, MOXIE_F1_NARG, "bad" },
{ 0x3f, MOXIE_F1_NARG, "bad" }
};
const moxie_opc_info_t moxie_form2_opc_info[4] =
{
{ 0x00, MOXIE_F2_A8V, "inc" },
{ 0x01, MOXIE_F2_A8V, "dec" },
{ 0x02, MOXIE_F2_A8V, "gsr" },
{ 0x03, MOXIE_F2_A8V, "ssr" }
};
const moxie_opc_info_t moxie_form3_opc_info[16] =
{
{ 0x00, MOXIE_F3_PCREL,"beq" },
{ 0x01, MOXIE_F3_PCREL,"bne" },
{ 0x02, MOXIE_F3_PCREL,"blt" },
{ 0x03, MOXIE_F3_PCREL,"bgt" },
{ 0x04, MOXIE_F3_PCREL,"bltu" },
{ 0x05, MOXIE_F3_PCREL,"bgtu" },
{ 0x06, MOXIE_F3_PCREL,"bge" },
{ 0x07, MOXIE_F3_PCREL,"ble" },
{ 0x08, MOXIE_F3_PCREL,"bgeu" },
{ 0x09, MOXIE_F3_PCREL,"bleu" },
{ 0x0a, MOXIE_F3_NARG, "bad" },
{ 0x0b, MOXIE_F3_NARG, "bad" },
{ 0x0c, MOXIE_F3_NARG, "bad" },
{ 0x0d, MOXIE_F3_NARG, "bad" },
{ 0x0e, MOXIE_F3_NARG, "bad" },
{ 0x0f, MOXIE_F3_NARG, "bad" }
};
/* Macros to extract operands from the instruction word. */
#define OP_A(i) ((i >> 4) & 0xf)
#define OP_B(i) (i & 0xf)
#define INST2OFFSET(o) ((((signed short)((o & ((1<<10)-1))<<6))>>6)<<1)
static const char * reg_names[16] =
{ "$fp", "$sp", "$r0", "$r1", "$r2", "$r3", "$r4", "$r5",
"$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13" };
int
print_insn_moxie(bfd_vma addr, struct disassemble_info * info)
{
int length = 2;
int status;
stream = info->stream;
const moxie_opc_info_t * opcode;
bfd_byte buffer[4];
unsigned short iword;
fprintf_function fpr = info->fprintf_func;
if ((status = info->read_memory_func(addr, buffer, 2, info)))
goto fail;
iword = (bfd_getb16(buffer) >> 16);
/* Form 1 instructions have the high bit set to 0. */
if ((iword & (1<<15)) == 0) {
/* Extract the Form 1 opcode. */
opcode = &moxie_form1_opc_info[iword >> 8];
switch (opcode->itype) {
case MOXIE_F1_NARG:
fpr(stream, "%s", opcode->name);
break;
case MOXIE_F1_A:
fpr(stream, "%s\t%s", opcode->name,
reg_names[OP_A(iword)]);
break;
case MOXIE_F1_AB:
fpr(stream, "%s\t%s, %s", opcode->name,
reg_names[OP_A(iword)],
reg_names[OP_B(iword)]);
break;
case MOXIE_F1_A4:
{
unsigned imm;
if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
goto fail;
imm = bfd_getb32(buffer);
fpr(stream, "%s\t%s, 0x%x", opcode->name,
reg_names[OP_A(iword)], imm);
length = 6;
}
break;
case MOXIE_F1_4:
{
unsigned imm;
if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
goto fail;
imm = bfd_getb32(buffer);
fpr(stream, "%s\t0x%x", opcode->name, imm);
length = 6;
}
break;
case MOXIE_F1_M:
{
unsigned imm;
if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
goto fail;
imm = bfd_getb32(buffer);
fpr(stream, "%s\t", opcode->name);
info->print_address_func((bfd_vma) imm, info);
length = 6;
}
break;
case MOXIE_F1_AiB:
fpr (stream, "%s\t(%s), %s", opcode->name,
reg_names[OP_A(iword)], reg_names[OP_B(iword)]);
break;
case MOXIE_F1_ABi:
fpr(stream, "%s\t%s, (%s)", opcode->name,
reg_names[OP_A(iword)], reg_names[OP_B(iword)]);
break;
case MOXIE_F1_4A:
{
unsigned imm;
if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
goto fail;
imm = bfd_getb32(buffer);
fpr(stream, "%s\t0x%x, %s",
opcode->name, imm, reg_names[OP_A(iword)]);
length = 6;
}
break;
case MOXIE_F1_AiB4:
{
unsigned imm;
if ((status = info->read_memory_func(addr+2, buffer, 4, info)))
goto fail;
imm = bfd_getb32(buffer);
fpr(stream, "%s\t0x%x(%s), %s", opcode->name,
imm,
reg_names[OP_A(iword)],
reg_names[OP_B(iword)]);
length = 6;
}
break;
case MOXIE_F1_ABi4:
{
unsigned imm;
if ((status = info->read_memory_func(addr+2, buffer, 4, info)))
goto fail;
imm = bfd_getb32(buffer);
fpr(stream, "%s\t%s, 0x%x(%s)",
opcode->name,
reg_names[OP_A(iword)],
imm,
reg_names[OP_B(iword)]);
length = 6;
}
break;
default:
abort();
}
}
else if ((iword & (1<<14)) == 0) {
/* Extract the Form 2 opcode. */
opcode = &moxie_form2_opc_info[(iword >> 12) & 3];
switch (opcode->itype) {
case MOXIE_F2_A8V:
fpr(stream, "%s\t%s, 0x%x",
opcode->name,
reg_names[(iword >> 8) & 0xf],
iword & ((1 << 8) - 1));
break;
case MOXIE_F2_NARG:
fpr(stream, "%s", opcode->name);
break;
default:
abort();
}
} else {
/* Extract the Form 3 opcode. */
opcode = &moxie_form3_opc_info[(iword >> 10) & 15];
switch (opcode->itype) {
case MOXIE_F3_PCREL:
fpr(stream, "%s\t", opcode->name);
info->print_address_func((bfd_vma) (addr + INST2OFFSET(iword) + 2),
info);
break;
default:
abort();
}
}
return length;
fail:
info->memory_error_func(status, addr, info);
return -1;
}

View File

@@ -9,7 +9,7 @@ still be bootable.
== Example ==
Let's assume we have a QEMU machine with two NICs (virtio, e1000) and two
Lets assume we have QEMU machine with two NICs (virtio, e1000) and two
disks (IDE, virtio):
qemu -drive file=disk1.img,if=none,id=disk1
@@ -20,7 +20,7 @@ qemu -drive file=disk1.img,if=none,id=disk1
-netdev type=user,id=net1 -device e1000,netdev=net1,bootindex=1
Given the command above, firmware should try to boot from the e1000 NIC
first. If this fails, it should try the virtio NIC next; if this fails
first. If this fails, it should try the virtio NIC next, if this fails
too, it should try the virtio disk, and then the IDE disk.
== Limitations ==
@@ -28,7 +28,7 @@ too, it should try the virtio disk, and then the IDE disk.
1. Some firmware has limitations on which devices can be considered for
booting. For instance, the PC BIOS boot specification allows only one
disk to be bootable. If boot from disk fails for some reason, the BIOS
won't retry booting from other disk. It can still try to boot from
won't retry booting from other disk. It still can try to boot from
floppy or net, though.
2. Sometimes, firmware cannot map the device path QEMU wants firmware to
@@ -36,8 +36,8 @@ boot from to a boot method. It doesn't happen for devices the firmware
can natively boot from, but if firmware relies on an option ROM for
booting, and the same option ROM is used for booting from more then one
device, the firmware may not be able to ask the option ROM to boot from
a particular device reliably. For instance with the PC BIOS, if a SCSI HBA
a particular device reliably. For instance with PC BIOS, if a SCSI HBA
has three bootable devices target1, target3, target5 connected to it,
the option ROM will have a boot method for each of them, but it is not
possible to map from boot method back to a specific target. This is a
shortcoming of the PC BIOS boot specification.
shortcoming of PC BIOS boot specification.

Some files were not shown because too many files have changed in this diff Show More