Compare commits

..

286 Commits

Author SHA1 Message Date
Michael Roth
ff0245dea2 update VERSION for v1.2.2
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-11 15:09:44 -06:00
Michael Contreras
e1a0ffb957 e1000: Discard packets that are too long if !SBP and !LPE
The e1000_receive function for the e1000 needs to discard packets longer than
1522 bytes if the SBP and LPE flags are disabled. The linux driver assumes
this behavior and allocates memory based on this assumption.

Signed-off-by: Michael Contreras <michael@inetric.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit b0d9ffcd02)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 15:02:28 -06:00
Dietmar Maurer
178ef3a43a stream: fix ratelimit_set_speed
The formula to compute slice_quota was wrong since commit 6ef228fc.

Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit e3980e28bb)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 15:02:28 -06:00
Stefan Hajnoczi
cd00334f1a usb: fail usbdevice_create() when there is no USB bus
Report an error instead of segfaulting when attaching a USB device to a
machine with no USB busses:

  $ qemu-system-arm -machine vexpress-a9 \
      -sd Fedora-17-armhfp-vexpress-mmcblk0.img \
      -kernel vmlinuz-3.4.2-3.fc17.armv7hl \
      -initrd initramfs-3.4.2-3.fc17.armv7hl.img \
      -usbdevice disk:format=raw:test.img

Note that the vexpress-a9 machine does not have a USB host controller.

Reported-by: David Abdurachmanov <David.Abdurachmanov@cern.ch>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit c128d6a6d7)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 15:02:28 -06:00
Yonit Halperin
8c9283c82a qxl: reload memslots after migration, when qxl is in UNDEFINED mode
The devram memslot stays active when qxl enters UNDEFINED mode (i.e, no
primary surface). If migration has occurred while the device is in
UNDEFINED stae, the memslots have to be reloaded at the destination.

Fixes rhbz#874574

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 15:02:28 -06:00
David Gibson
bf47da47db virtio-scsi: Fix subtle (guest) endian bug
The virtio-scsi config space is, by specification, in guest endian (which
is ill-defined, but there you go).  In virtio_scsi_get_config() we set up
all the fields in there, using stl_raw().  Which is a problem for the
max_channel and max_target fields, which are 16-bit, not 32-bit.  For
little-endian targets we get away with it by accident, since the first
two bytes will still be correct, and the extra two bytes written (with
zeroes) will be overwritten correctly by the next store.

But for big-endian guests, this means the max_target field ends up as zero,
which means the guest will only recognize a single disk on the virtio-scsi
bus.  This patch fixes the problem.

Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Paul 'Rusty' Russell <rusty@rustcorp.com.au>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 863d1050c9)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 15:02:28 -06:00
David Gibson
ea08f3a4e2 virtio-scsi: Fix some endian bugs with virtio-scsi
The virtio-scsi specification does not specify the correct endianness for
fields in the request structure.  It's therefore best to assume that it is
"guest native" endian since that's the (stupid and poorly defined) norm in
virtio.

However, the qemu device for virtio-scsi has no byteswaps at all, and so
will break if the guest has different endianness from the host.  This patch
fixes it by adding tswap() calls for the sense_len and resid fields in
the request structure.  In theory status_qualifier needs swaps as well,
but that field is never actually touched.  The tag field is a uint64_t, but
since its value is completely arbitrary, it might as well be uint8_t[8]
and so it does not need swapping.

Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Paul 'Rusty' Russell <rusty@rustcorp.com.au>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 474ee55a18)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 15:02:28 -06:00
Peter Lieven
cef2566953 iscsi: do not assume device is zero initialized
Without any complex checks we can't assume that an
iscsi target is initialized to zero.

Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit f807ecd574)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 15:02:28 -06:00
Peter Lieven
707f2b69ff iscsi: fix deadlock during login
If the connection is interrupted before the first login is successfully
completed qemu-kvm is waiting forever in qemu_aio_wait().

This is fixed by performing an sync login to the target. If the
connection breaks after the first successful login errors are
handled internally by libiscsi.

Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit e829b0bb05)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 15:02:28 -06:00
Peter Lieven
972a2bf072 iscsi: fix segfault in url parsing
If an invalid URL is specified iscsi_get_error(iscsi) is called
with iscsi == NULL.

Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 8da1e18b0c)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 15:02:28 -06:00
Bruce Rogers
ffffff0146 qapi: fix qapi_dealloc_type_size parameter type
The second parameter to qapi_dealloc_type_size should be a uint64_t *,
not a size_t *. This was causing our 32 bit x86 build to fail, since
warnings are treated as errors.

Signed-off-by: Bruce Rogers <brogers@suse.com>
Reviewed-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Reviewed-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
(cherry picked from commit 1d16252652)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 15:02:28 -06:00
Stefan Hajnoczi
54c6c5a35d qapi: handle visitor->type_size() in QapiDeallocVisitor
visit_type_size() requires either visitor->type_size() or
visitor_uint64() to be implemented, otherwise a NULL function pointer is
invoked.

It is possible to trigger this crash as follows:

  $ qemu-system-x86_64 -netdev tap,sndbuf=0,id=netdev0 \
                       -device virtio-blk-pci,netdev=netdev0

The 'sndbuf' option has type "size".

Reviewed-by: Andreas Färber <afaerber@suse.de>
Reviewed-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 0c26f2eca4)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 15:02:28 -06:00
Paolo Bonzini
f05a3da4e0 qom: fix refcount of non-heap-allocated objects
The reference count for embedded objects is always one too low, because
object_initialize_with_type returns with zero references to the object.
This causes premature finalization of the object (or an assertion failure)
after calling object_ref to add an extra reference and object_unref to
remove it.

The fix is to move the initial object_ref call from object_new_with_type
to object_initialize_with_type.

Acked-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 764b63125a)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 15:02:28 -06:00
Julio Guerra
0aad8f1a49 PPC: Fix missing TRACE exception
This patch fixes bug 1031698 :
https://bugs.launchpad.net/qemu/+bug/1031698

If we look at the (truncated) translation of the conditional branch
instruction in the test submitted in the bug post, the call to the
exception helper is missing in the "bne-false" chunk of translated
code :

IN:
bne-    0x1800278

OUT:
0xb544236d:  jne    0xb5442396

0xb5442373:  mov    %ebp,(%esp)
0xb5442376:  mov    $0x44,%ebx
0xb544237b:  mov    %ebx,0x4(%esp)
0xb544237f:  mov    $0x1800278,%ebx
0xb5442384:  mov    %ebx,0x25c(%ebp)
0xb544238a:  call   0x827475a
                     ^^^^^^^^^^^^^^^^^^

0xb5442396:  mov    %ebp,(%esp)
0xb5442399:  mov    $0x44,%ebx
0xb544239e:  mov    %ebx,0x4(%esp)
0xb54423a2:  mov    $0x1800270,%ebx
0xb54423a7:  mov    %ebx,0x25c(%ebp)

Indeed, gen_exception(ctx, excp) called by gen_goto_tb (called by
gen_bcond) changes ctx->exception's value to excp's :

gen_bcond()
{
  gen_goto_tb(ctx, 0, ctx->nip + li - 4);
  /* ctx->exception value is POWERPC_EXCP_BRANCH */

  gen_goto_tb(ctx, 1, ctx->nip);
  /* ctx->exception now value is POWERPC_EXCP_TRACE */
}

Making the following gen_goto_tb()'s test false during the second call :

if ((ctx->singlestep_enabled &
    (CPU_BRANCH_STEP | CPU_SINGLE_STEP)) &&
    ctx->exception == POWERPC_EXCP_BRANCH /* false...*/) {
         target_ulong tmp = ctx->nip;
         ctx->nip = dest;
         /* ... and this is the missing call */
         gen_exception(ctx, POWERPC_EXCP_TRACE);
         ctx->nip = tmp;
}

So the patch simply adds the missing matching case, fixing our problem.

Signed-off-by: Julio Guerra <guerr@julio.in>
Signed-off-by: Alexander Graf <agraf@suse.de>
(cherry picked from commit f0cc4aa845)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 15:02:28 -06:00
Paolo Bonzini
a99cb0d20a hmp: do not crash on invalid SCSI hotplug
Commit 0d93692 (qdev: Convert busses to QEMU Object Model, 2012-05-02)
removed a check on the type of the bus where a SCSI disk is hotplugged.
However, hot-plugging to the wrong kind of device now causes a crash
due to either a NULL pointer dereference (avoided by the previous patch)
or a failed QOM cast.

Instead, in this case we need to use object_dynamic_cast and check for
the result, similar to what was done before that commit.

Reported-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit b5007bcc97)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 14:27:39 -06:00
Paolo Bonzini
5e19e498b4 qom: dynamic_cast of NULL is always NULL
Trying to cast a NULL value will cause a crash.  Returning
NULL is also sensible, and it is also what the type-unsafe
DO_UPCAST macro does.

Reported-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit b7f43fe460)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 14:26:56 -06:00
Stefan Weil
4fb9656b9d block: Fix regression for MinGW (assertion caused by short string)
The local string tmp_filename is passed to function get_tmp_filename
which expects a string with minimum size MAX_PATH for w32 hosts.

MAX_PATH is 260 and PATH_MAX is 259, so tmp_filename was too short.

Commit eba25057b9 introduced this
regression.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
(cherry picked from commit 89c9bc3d14)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 14:22:57 -06:00
Richard Henderson
38c6d17e75 tci: Fix type of tci_read_label
Fixes the pointer truncation that was occurring for branches.

Cc: Stefan Weil <sw@weilnetz.de>
Cc: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Richard Henderson <rth@twiddle.net>
Reviewed-by: Stefan Weil <sw@weilnetz.de>
Tested-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
(cherry picked from commit c6c5063c7a)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 14:04:34 -06:00
Kevin Wolf
600a9efdb1 qcow2: Fix refcount table size calculation
A missing factor for the refcount table entry size in the calculation
could mean that too little memory was allocated for the in-memory
representation of the table, resulting in a buffer overflow.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
Tested-by: Michael Tokarev <mjt@tls.msk.ru>
(cherry picked from commit a354807706)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 13:32:32 -06:00
Bruce Rogers
ea79e157c6 configure: avoid compiler warning in pipe2 detection
When building qemu-kvm for openSUSE:Factory, I am getting a
warning in the pipe2 detection performed by configure, which
prevents using --enable-werror.

Change detection code to use return value of pipe2.

Signed-off-by: Bruce Rogers <brogers@suse.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
(cherry picked from commit 9bca81624e)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 13:24:20 -06:00
Aurelien Jarno
4a8e490cbc target-openrisc: remove conflicting definitions from cpu.h
On an ARM host, the registers definitions from cpu.h clash
with /usr/include/sys/ucontext.h. As there are unused, just remove
them.

Cc: Jia Liu <proljc@gmail.com>
Cc: qemu-stable@nongnu.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 44e04d3b94)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 13:23:11 -06:00
Aurelien Jarno
ede76edace tcg/arm: fix cross-endian qemu_st16
The bswap16 TCG opcode assumes that the high bytes of the temp equal
to 0 before calling it. The ARM backend implementation takes this
assumption to slightly optimize the generated code.

The same implementation is called for implementing the cross-endian
qemu_st16 opcode, where this assumption is not true anymore. One way to
fix that would be to zero the high bytes before calling it. Given the
store instruction just ignore them, it is possible to provide a slightly
more optimized version. With ARMv6+ the rev16 instruction does the work
correctly. For lower ARM versions the patch provides a version which
behaves correctly with non-zero high bytes, but fill them with junk.

Cc: Andrzej Zaborowski <balrogg@gmail.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: qemu-stable@nongnu.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 7aab08aa78)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 13:22:56 -06:00
Aurelien Jarno
ac914c1fc2 tcg/arm: fix TLB access in qemu-ld/st ops
The TCG arm backend considers likely that the offset to the TLB
entries does not exceed 12 bits for mem_index = 0. In practice this is
not true for at least the MIPS target.

The current patch fixes that by loading the bits 23-12 with a separate
instruction, and using loads with address writeback, independently of
the value of mem_idx. In total this allow a 24-bit offset, which is a
lot more than needed.

Cc: Andrzej Zaborowski <balrogg@gmail.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: qemu-stable@nongnu.org
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit d17bd1d8cc)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-12-03 13:21:47 -06:00
陳韋任 (Wei-Ren Chen)
357414daa4 target-mips: fix wrong microMIPS opcode encoding
While reading microMIPS decoding, I found a possible wrong opcode
encoding. According to [1] page 166, the bits 13..12 for MULTU is
0x01 rather than 0x00. Please review, thanks.

[1] MIPS Architecture for Programmers VolumeIV-e: The MIPS DSP
    Application-Specific Extension to the microMIPS32 Architecture

Signed-off-by: Chen Wei-Ren <chenwj@iis.sinica.edu.tw>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 6801038bc5)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 16:07:16 -06:00
Aurelien Jarno
f6b803df74 mips/malta: fix CBUS UART interrupt pin
According to the MIPS Malta Developement Platform User's Manual, the
i8259 interrupt controller is supposed to be connected to the hardware
IRQ0, and the CBUS UART to the hardware interrupt 2.

In QEMU they are both connected to hardware interrupt 0, the CBUS UART
interrupt being wrong. This patch fixes that. It should be noted that
the irq array in QEMU includes the software interrupts, hence
env->irq[2] is the first hardware interrupt.

Cc: Ralf Baechle <ralf@linux-mips.org>
Reviewed-by: Eric Johnson <ericj@mips.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 68d001928b)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 16:05:41 -06:00
Paolo Bonzini
879c264803 nbd: fixes to read-only handling
We do not need BLKROSET if the kernel supports setting flags.
Also, always do BLKROSET even for a read-write export, otherwise
the read-only state remains "sticky" after the invocation of
"qemu-nbd -r".

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit c8969eded2)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 16:02:14 -06:00
Meador Inge
382a582c1f m68k: Return semihosting errno values correctly
Fixing a simple typo, s/errno/err/, that caused
the error status from GDB semihosted system calls
to be returned incorrectly.

Signed-off-by: Meador Inge <meadori@codesourcery.com>
Reviewed-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
(cherry picked from commit aed91c1bff)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 16:01:29 -06:00
Paolo Bonzini
5c0d5aebd5 tools: initialize main loop before block layer
Tools were broken because they initialized the block layer while
qemu_aio_context was still NULL.

Reported-by: malc <av1474@comtv.ru>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: malc <av1474@comtv.ru>
(cherry picked from commit 2592c59a66)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:59:27 -06:00
Gerd Hoffmann
3dd59b4dc7 xhci: fix usb name in caps
Used to be "UTB" not "USB".

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:57:51 -06:00
Aurelien Jarno
03e044136a target-sparc64: disable VGA cirrus
OpenBIOS on sparc64 only support Standard VGA and not Cirrus VGA. Don't
build Cirrus VGA support so that it can't be selected.

This fixes the breakage introduced by commit f2898771.

Reported-by: Richard Henderson <rth@twiddle.net>
Cc: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Tested-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
(cherry picked from commit 0356404b0f)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:56:47 -06:00
Alexander Graf
db6e5ab78e PPC: Bamboo: Fix memory size DT property
Device tree properties need to be specified in big endian. Fix the
bamboo memory size property accordingly.

Signed-off-by: Alexander Graf <agraf@suse.de>
CC: qemu-stable@nongnu.org
(cherry picked from commit 5232fa59b1)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:56:10 -06:00
Alexander Graf
7817b8d858 s390x: fix -initrd in virtio machine
When using -initrd in the virtio machine, we need to indicate the initrd
start and size inside the kernel image. These parameters need to be stored
in native endianness.

Signed-off-by: Alexander Graf <agraf@suse.de>
Acked-by: Richard Henderson <rth@twiddle.net>
Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
(cherry picked from commit 235a3f0bed)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:55:22 -06:00
Avi Kivity
0dfd8215c2 memory: fix rendering of a region obscured by another
The memory core drops regions that are hidden by another region (for example,
during BAR sizing), but it doesn't do so correctly if the lower address of the
existing range is below the lower address of the new range.

Example (qemu-system-mips -M malta -kernel vmlinux-2.6.32-5-4kc-malta
         -append "console=ttyS0"  -nographic -vga cirrus):

Existing range: 10000000-107fffff
New range:      100a0000-100bffff

Correct behaviour: drop new range
Incorrect behaviour: add new range

Fix by taking this case into account (previously we only considered
equal lower boundaries).

Tested-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit d26a8caea3)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:54:07 -06:00
Dmitry Fleytman
e16d81df85 e1000: drop check_rxov, always treat RX ring with RDH == RDT as empty
Real HW always treats RX ring with RDH == RDT as empty.
Emulation is supposed to behave the same.

Reported-by: Chris Webb <chris.webb@elastichosts.com>
Reported-by: Richard Davies <richard.davies@elastichosts.com>
Signed-off-by: Dmitry Fleytman <dmitry@daynix.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit e5b8b0d4ba)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:53:11 -06:00
Don Slutz
3dfbc51e78 target-i386: Allow tsc-frequency to be larger then 2.147G
The check using INT_MAX (2147483647) is wrong in this case.

Signed-off-by: Fred Oliveira <foliveira@cloudswitch.com>
Signed-off-by: Don Slutz <Don@CloudSwitch.com>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit 2e84849aa2)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:44:14 -06:00
Stefan Weil
eb63b0c2da hw: Fix return value check for bdrv_read, bdrv_write
Those functions return -errno in case of an error.
The old code would typically only detect EPERM (1) errors.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit 7a608f562e)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:42:17 -06:00
Paolo Bonzini
4843c928f9 rtc: fix overflow in mktimegm
When setting a date in 1980, Linux is actually disregarding the century
byte and setting the year to 2080.  This causes a year-2038 overflow
in mktimegm.  Fix this by doing the days-to-seconds computation in
64-bit math.

Reported-by: Lucas Meneghel Rodrigues <lookkas@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit b6db4aca20)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:41:52 -06:00
Gerd Hoffmann
a106eaa3a6 qxl: always update displaysurface on resize
Don't try to be clever and skip displaysurface reinitialization in case
the size hasn't changed.  Other parameters might have changed
nevertheless, for example depth or stride, resulting in rendering being
broken then.

Trigger: boot linux guest with vesafb, start X11, make sure both vesafb
and X11 use the display same resolution.  Then watch X11 screen being
upside down.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:41:11 -06:00
Alon Levy
472da83043 hw/qxl: qxl_dirty_surfaces: use uintptr_t
As suggested by Paolo Bonzini, to avoid possible integer overflow issues.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:39:56 -06:00
Hans de Goede
85c91ea7e2 uhci: Raise interrupt when requested even for non active tds
According to the spec we must raise an interrupt when one is requested
even for non active tds.

Linux depends on this, for bulk transfers it runs an inactivity timer
to work around a bug in early uhci revisions, when we take longer then
200 ms to process a packet, this timer goes of, and as part of the
handling Linux then unlinks the qh, and relinks it after the frindex
has increased by atleast 1, the problem is Linux only checks for the
frindex increases on an interrupt, and we don't send that, causing
the qh to go inactive for more then 32 frames, at which point we
consider the packet cancelled.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:39:28 -06:00
Paolo Bonzini
5af7caaadd vnc: fix "info vnc" with "-vnc ..., reverse=on"
When reverse connection is in use, there is no active VNC server
socket.  Because of this, getsockopt(-1, ...) is attempted and
the following error is emitted:

    $ socat TCP-LISTEN:5900,reuseaddr TCP-LISTEN:5901,reuseaddr &
    $ x86_64-softmmu/qemu-system-x86_64 -vnc localhost:5900,reverse -monitor stdio
    QEMU 1.2.50 monitor - type 'help' for more information
    (qemu) info vnc
    An undefined error has occurred

Because however the host, family, service and auth fields are
optional, we can just exit if there is no active server socket.

    $ x86_64-softmmu/qemu-system-x86_64 -vnc localhost:5900,reverse -monitor stdio
    QEMU 1.2.50 monitor - type 'help' for more information
    (qemu) info vnc
    Server:
    Client:
         address: 127.0.0.1:5900
      x509_dname: none
        username: none

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 417b0b8890)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:38:14 -06:00
Joel Martin
0ae18b369c ui/vnc: Only report/use TIGHT_PNG encoding if enabled.
If TIGHT_PNG is not enabled by the --enable-vnc-png configure flag
then do not report to the client that it is supported.

Also, since TIGHT_PNG is the same as the TIGHT encoding but with the
filter/copy replaced with PNG data, adding it to the supported
encodings list when it is disabled will cause the TIGHT encoding to be
used even though the client requested TIGHT_PNG.

Signed-off-by: Joel Martin <github@martintribe.org>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit fe3e7f2dc0)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:36:13 -06:00
Michael Tokarev
5a99c8ca01 fix CONFIG_QEMU_HELPERDIR generation again
commit 38f419f352 fixed a breakage with CONFIG_QEMU_HELPERDIR
which has been introduced by 8bf188aa18.  But while techinically
that fix has been correct, all other similar variables are handled
differently.  Make it consistent, and let scripts/create_config
expand and capitalize the variable properly like for all other
qemu_*dir variables.

Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
(cherry picked from commit f354b1a1ee)

Conflicts:

	configure

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:27:54 -06:00
Jan Kiszka
029eae1a75 configure: Fix CONFIG_QEMU_HELPERDIR generation
We need to evaluate $libexecdir in configure, otherwise we literally end
up with "${prefix}/libexec" instead of the absolute path as
CONFIG_QEMU_HELPERDIR.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 38f419f352)

Conflicts:

	configure

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-11-30 15:21:15 -06:00
Michael Roth
f4c53d94d2 update VERSION for v1.2.1
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:47:44 -05:00
David Gibson
159fe82dea pseries: Don't test for MSR_PR for hypercalls under KVM
PAPR hypercalls should only be invoked from the guest kernel, not guest
user programs, that is, with MSR[PR]=0.  Currently we check this in
spapr_hypercall, returning H_PRIVILEGE if MSR[PR]=1.

However, under KVM the state of MSR[PR] is already checked by the host
kernel before passing the hypercall to qemu, making this check redundant.
Worse, however, we don't generally synchronize KVM and qemu state on the
hypercall path, meaning that qemu could incorrectly reject a hypercall
because it has a stale MSR value.

This patch fixes the problem by moving the privilege test exclusively to
the TCG hypercall path.

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 efcb9383b9)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:21 -05:00
Peter Maydell
a8f2299d1b fpu/softfloat.c: Return correctly signed values from uint64_to_float32
The uint64_to_float32() conversion function was incorrectly always
returning numbers with the sign bit set (ie negative numbers). Correct
this so we return positive numbers instead.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit e744c06fca)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:21 -05:00
Eduardo Habkost
68fc5d1d27 i386: kvm: bit 10 of CPUID[8000_0001].EDX is reserved
Bit 10 of CPUID[8000_0001].EDX is not defined as an alias of
CPUID[1].EDX[10], so do not duplicate it on
kvm_arch_get_supported_cpuid().

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-By: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Don Slutz <Don@CloudSwitch.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
(cherry picked from commit b1f4679392)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:21 -05:00
Francesco Lavra
3e1954cb4a Versatile Express: Fix NOR flash 0 address and remove flash alias
In the A series memory map (implemented in the Cortex A15 CoreTile), the
first NOR flash bank (flash 0) is mapped to address 0x08000000, while
address 0x00000000 can be configured as alias to either the first or the
second flash bank. This patch fixes the definition of flash 0 address,
and for simplicity removes the alias definition.

Signed-off-by: Francesco Lavra <francescolavra.fl@gmail.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 661bafb3e1)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:21 -05:00
Meador Inge
14bdf978ef hw/armv7m_nvic: Correctly register GIC region when setting up NVIC
When setting up the NVIC memory regions the memory range
0x100..0xcff is aliased to an IO memory region that belongs
to the ARM GIC.  This aliased region should be added to the
NVIC memory container, but the actual GIC IO memory region
was being added instead.  This mixup was causing the wrong
IO memory access functions to be called when accessing parts
of the NVIC memory.

Signed-off-by: Meador Inge <meadori@codesourcery.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 9892cae395)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:21 -05:00
Brendan Fennell
806d996789 pl190: fix read of VECTADDR
Reading VECTADDR was causing us to set the current priority to
the wrong value, the most obvious effect of which was that we
would return the vector for the wrong interrupt as the result
of the read.

Signed-off-by: Brendan Fennell <bfennell@skynet.ie>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 14c126baf1)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:21 -05:00
Orit Wasserman
d893e56f72 Clear handler only for valid fd
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 3202becaa2)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:21 -05:00
Orit Wasserman
240f68ce5b Fix address handling in inet_nonblocking_connect
getaddrinfo can give us a list of addresses, but we only try to
connect to the first one. If that fails we never proceed to
the next one.  This is common on desktop setups that often have ipv6
configured but not actually working.

To fix this make inet_connect_nonblocking retry connection with a different
address.
callers on inet_nonblocking_connect register a callback function that will
be called when connect opertion completes, in case of failure the fd will have
a negative value

Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 233aa5c2d1)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:21 -05:00
Orit Wasserman
ee0999b16a Separate inet_connect into inet_connect (blocking) and inet_nonblocking_connect
No need to add non blocking parameters to the blocking inet_connect
add block parameter for inet_connect_opts instead of using QemuOpt "block".

Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 5db5f44cb4)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:21 -05:00
Michael S. Tsirkin
57f8a4c507 Refactor inet_connect_opts function
refactor address resolution code to fix nonblocking connect
remove getnameinfo call

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Amos Kong <akong@redhat.com>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 05bc1d8a4b)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:21 -05:00
Stefan Weil
b83465006d configure: Allow builds without any system or user emulation
The old code aborted configure when no emulation target was selected.
Even after removing the 'exit 1', it tried to read from STDIN
when QEMU was configured with

    configure' '--disable-user' '--disable-system'

This is fixed here.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 8bdd3d499f)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:21 -05:00
Jeff Cody
d80210efbc block: correctly set the keep_read_only flag
I believe the bs->keep_read_only flag is supposed to reflect
the initial open state of the device. If the device is initially
opened R/O, then commit operations, or reopen operations changing
to R/W, are prohibited.

Currently, the keep_read_only flag is only accurate for the active
layer, and its backing file. Subsequent images end up always having
the keep_read_only flag set.

For instance, what happens now:

[  base  ]  kro = 1, ro = 1
    |
    v
[ snap-1 ]  kro = 1, ro = 1
    |
    v
[ snap-2 ]  kro = 0, ro = 1
    |
    v
[ active ]  kro = 0, ro = 0

What we want:

[  base  ]  kro = 0, ro = 1
    |
    v
[ snap-1 ]  kro = 0, ro = 1
    |
    v
[ snap-2 ]  kro = 0, ro = 1
    |
    v
[ active ]  kro = 0, ro = 0

Signed-off-by: Jeff Cody <jcody@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit be028adced)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Kevin Shanahan
513cdda198 blockdev: preserve readonly and snapshot states across media changes
If readonly=on is given at device creation time, the ->readonly flag
needs to be set in the block driver state for this device so that
readonly-ness is preserved across media changes (qmp change command).
Similarly, to preserve the snapshot property requires ->open_flags to
be correct.

Signed-off-by: Kevin Shanahan <kmshanah@disenchant.net>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 80dd1aae36)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Stefan Weil
eea54caab0 w32: Add implementation of gmtime_r, localtime_r
Those functions are missing in MinGW.

Some versions of MinGW-w64 include defines for gmtime_r and localtime_r.
Older versions of these macros are buggy (they return a pointer to a
static variable), therefore we don't want them. Newer versions are
similar to the code used here, but without the memset.

The implementation which is used here is not strictly reentrant,
but sufficiently good for QEMU on w32 or w64.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
[blauwirbel@gmail.com: added comment about locking]
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
(cherry picked from commit d3e8f95753)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Stefan Weil
78fd27b3b6 w32: Always use standard instead of native format strings
GLib 2.0 include files use __printf__ for the format attribute
which resolves to native format strings on w32 hosts.

QEMU wants standard format strings instead of native format
strings, so we simply change any declaration with __printf__
to use __gnu_printf__.

This works because all basic printf functions support both
kinds of format strings.

This fixes a compiler warning:

qapi/string-output-visitor.c: In function ‘print_type_int’:
qapi/string-output-visitor.c:34:5: warning: unknown conversion type character ‘l’ in format [-Wformat]
qapi/string-output-visitor.c:34:5: warning: too many arguments for format [-Wformat-extra-args]

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit 95df51a4a0)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Stefan Weil
d4413913e1 net/socket: Fix compiler warning (regression for MinGW)
Commit 213fd5087e removed a type cast
which is needed for MinGW:

net/socket.c:136: warning:
 pointer targets in passing argument 2 of ‘sendto’ differ in signedness
/usr/lib/gcc/amd64-mingw32msvc/4.4.4/../../../../amd64-mingw32msvc/include/winsock2.h:1313: note:
 expected ‘const char *’ but argument is of type ‘const uint8_t *’

Add a 'qemu_sendto' macro which provides that type cast where needed
and use the new macro instead of 'sendto'.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit 73062dfe6b)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Stefan Weil
61dea8e914 linux-user: Remove redundant null check and replace free by g_free
Report from smatch:

linux-user/syscall.c:3632 do_ioctl_dm(220) info:
 redundant null check on big_buf calling free()

'big_buf' was allocated by g_malloc0, therefore free was also
replaced by g_free.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit ad11ad7774)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Laszlo Ersek
a2aad5fdc4 TextConsole: saturate escape parameter in TTY_STATE_CSI
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit c10600af60)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Hitoshi Mitake
5730401442 curses: don't initialize curses when qemu is daemonized
Current qemu initializes curses even if -daemonize option is
passed. This cause problem because shell prompt appears without
calling endwin().

This patch adds new function, is_daemonized(), to OS dependent
code. With this function, curses_display_init() can check that qemu is
daemonized or not. If daemonized, curses_display_init() isn't called
and the problem is avoided.

Of course, -daemonize && -curses doesn't make sense. Users shouldn't
pass the arguments at the same time. But the problem is very painful
because Ctrl-C cannot be delivered to the terminal.

Cc: Andrzej Zaborowski  <balrog@zabor.org>
Cc: Stefan Hajnoczi <stefanha@gmail.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>
Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
Signed-off-by: Hitoshi Mitake <h.mitake@gmail.com>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit 995ee2bf46)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Stefan Weil
f3e9893078 pflash_cfi01: Fix warning caused by unreachable code
Report from smatch:
hw/pflash_cfi01.c:431 pflash_write(180) info: ignoring unreachable code.

Instead of removing the return statement after the switch statement,
the patch replaces the return statements in the switch statement by
break statements. Other switch statements in the same code do it also
like that.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit 12dabc79f9)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Stefan Weil
4d0fcc1968 ioh3420: Remove unreachable code
Report from smatch:
hw/ioh3420.c:128 ioh3420_initfn(35) info: ignoring unreachable code.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit 997f15672a)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Stefan Weil
2b9a5aca51 lm4549: Fix buffer overflow
Report from smatch:
lm4549.c:234 lm4549_write_samples(14) error:
 buffer overflow 's->buffer' 1024 <= 1024

There must be enough space to add two entries starting with index
s->buffer_level, therefore the old check was wrong.

[Peter Maydell <peter.maydell@linaro.org> clarifies the nature of the
analyser warning:

I don't object to making the change to placate the analyser,
but I don't think this is actually a buffer overrun. We always
add and remove samples from the buffer two at a time, so it's
not possible to get here with s->buffer_level == BUFFER_SIZE-1
(which is the only case where the old and new conditions
give different answers).]

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit 8139626643)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Stefan Weil
96d90d32ac cadence_uart: Fix buffer overflow
Report from smatch:
hw/cadence_uart.c:413 uart_read(13) error: buffer overflow 's->r' 18 <= 18

This fixes read access to s->r[R_MAX] which is behind the limits of s->r.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit 5d40097fc0)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Stefan Weil
3c980e22ac qemu-sockets: Fix potential memory leak
The old code leaks variable 'peer'.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit 39b384591f)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Stefan Weil
907a34c9d7 qemu-ga: Remove unreachable code after g_error
Report from smatch:
qemu-ga.c:117 register_signal_handlers(11) info: ignoring unreachable code.
qemu-ga.c:122 register_signal_handlers(16) info: ignoring unreachable code.

g_error calls abort which terminates the program.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit b548828862)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Stefan Weil
b79ba45af1 audio: Fix warning from static code analysis
smatch report:
audio/audio_template.h:416 AUD_open_out(18) warn:
 variable dereferenced before check 'as' (see line 414)

Moving the ldebug statement after the statement which checks 'as'
fixes that warning.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: malc <av1474@comtv.ru>
(cherry picked from commit 93b6599734)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Ronnie Sahlberg
75a44ae297 SCSI: Standard INQUIRY data should report HiSup flag as set.
QEMU as far as I know only reports LUN numbers using the modes that
are described in SAM4.
As such, since all LUN numbers generated by the SCSI emulation in QEMU
follow SAM4, we should set the HiSup bit in the standard INQUIRY data
to indicate such.

From SAM4:
  4.6.3 LUNs overview
  All LUN formats described in this standard are hierarchical in
  structure even when only a single level in that hierarchy is used.
  The HISUP bit shall be set to one in the standard INQUIRY data
  (see SPC-4) when any LUN format described in this standard is used.
  Non-hierarchical formats are outside the scope of this standard.

Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
(cherry picked from commit 1109c89405)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:20 -05:00
Paolo Bonzini
ff498e4a0d scsi-disk: fix check for out-of-range LBA
This fix is needed to correctly handle 0-block read and writes.
Without it, a 0-block access at LBA 0 would underflow.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 12ca76fc48)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:19 -05:00
Paolo Bonzini
394a2f28cb scsi-disk: introduce check_lba_range
Abstract the test for an out-of-range (starting block, block count)
pair.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 444bc90861)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:19 -05:00
Ronnie Sahlberg
60088e5b83 iSCSI: We dont need to explicitely call qemu_notify_event() any more
We no longer need to explicitely call qemu_notify_event() any more
since this is now done automatically any time the filehandles we listen
to change.

Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 40a13ca8d2)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:19 -05:00
Ronnie Sahlberg
ae06193d73 iSCSI: We need to support SG_IO also from iscsi_ioctl()
We need to support SG_IO from the synchronous iscsi_ioctl() since
scsi-block uses this to do an INQ to the device to discover its properties
This patch makes scsi-block work with iscsi.

Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit f1a12821d7)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:19 -05:00
Andreas Färber
e8ca4a8ac7 MAINTAINERS: Add entry for QOM CPU
Signed-off-by: Andreas Färber <afaerber@suse.de>
(cherry picked from commit f2ca052414)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:19 -05:00
Aurelien Jarno
68958c31b5 pflash_cfi01: fix vendor specific extended query
pflash_cfi01 announces a version number of 1.1, which implies
"Protection Register Information" and "Burst Read information"
sections, which are not provided.

Decrease the version number to 1.0 so that only the "Protection
Register Information" section is needed.

Set the number of protection fields (0x3f) to 0x01, as 0x00 means 256
protections field, which makes the CFI table bigger than the current
implementation, causing some kernels to fail to read it.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 262e1eaafa)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:19 -05:00
Chris Wulff
584717a39a xilinx_timer: Fix a compile error if debug enabled
There was a missing include of qemu-log and a variable name in a printf was out
of date.

Signed-off-by: Chris Wulff <crwulff@gmail.com>
Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
(cherry picked from commit 8354cd722e)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:19 -05:00
Peter A. G. Crosthwaite
85368b79a0 xilinx.h: Error check when setting links
Assert that the ethernet and dma controller are sucessfully linked to their
peers.

Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
(cherry picked from commit 4b5e52101f)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:19 -05:00
Peter A. G. Crosthwaite
36d7fb299a xilinx_timer: Send dbg msgs to stderr not stdout
Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
(cherry picked from commit e03377ae75)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:19 -05:00
Peter A. G. Crosthwaite
3412955066 xilinx_timer: Removed comma in device name
Fixes an error in a61e4b07a3

Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
(cherry picked from commit c0a1dcb9f0)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:19 -05:00
Peter Maydell
b52c8f78f2 arch_init.c: Improve '-soundhw help' for non-HAS_AUDIO_CHOICE archs
For architectures which don't set HAS_AUDIO_CHOICE, improve the
'-soundhw help' message so that it doesn't simply print an empty
list, implying no sound support at all.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: malc <av1474@comtv.ru>
(cherry picked from commit 55d4fd3c24)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:19 -05:00
David Gibson
668194d5a5 cpu_physical_memory_write_rom() needs to do TB invalidates
cpu_physical_memory_write_rom(), despite the name, can also be used to
write images into RAM - and will often be used that way if the machine
uses load_image_targphys() into RAM addresses.

However, cpu_physical_memory_write_rom(), unlike cpu_physical_memory_rw()
doesn't invalidate any cached TBs which might be affected by the region
written.

This was breaking reset (under full emu) on the pseries machine - we loaded
our firmware image into RAM, and while executing it rewrite the code at
the entry point (correctly causing a TB invalidate/refresh).  When we
reset the firmware image was reloaded, but the TB from the rewrite was
still active and caused us to get an illegal instruction trap.

This patch fixes the bug by duplicating the tb invalidate code from
cpu_physical_memory_rw() in cpu_physical_memory_write_rom().

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 0b57e28713)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:19 -05:00
David Gibson
8484fead29 qemu-char: BUGFIX, don't call FD_ISSET with negative fd
tcp_chr_connect(), unlike for example udp_chr_update_read_handler() does
not check if the fd it is using is valid (>= 0) before passing it to
qemu_set_fd_handler2().  If using e.g. a TCP serial port, which is not
initially connected, this can result in -1 being passed to FD_ISSET, which
has undefined behaviour.  On x86 it seems to harmlessly return 0, but on
PowerPC, it causes a fortify buffer overflow error to be thrown.

This patch fixes this by putting an extra test in tcp_chr_connect(), and
also adds an assert qemu_set_fd_handler2() to catch other such errors on
all platforms, rather than just some.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit bbdd2ad081)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:19 -05:00
Anthony Liguori
57683d6354 Revert 455aa1e08 and c3767ed0eb
commit c3767ed0eb
    qemu-char: (Re-)connect for tcp_chr_write() unconnected writing

Has no hope of working because tcp_chr_connect() does not actually connect.

455aa1e08 just fixes the SEGV with server() but the attempt to connect a client
socket is still completely broken.

This patch reverts both.

Reported-by: Richard W.M. Jones <rjones@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 6db0fdce02)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:19 -05:00
Natanael Copa
5d6ad6262b configure: properly check if -lrt and -lm is needed
Fixes build against uClibc.

uClibc provides 2 versions of clock_gettime(), one with realtime
support and one without (this is so you can avoid linking in -lrt
unless actually needed). This means that the clock_gettime() don't
need -lrt. We still need it for timer_create() so we check for this
function in addition.

We also need check if -lm is needed for isnan().

Both -lm and -lrt are needed for libs_qga.

Signed-off-by: Natanael Copa <ncopa@alpinelinux.org>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
(cherry picked from commit 8bacde8d86)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:18 -05:00
Yann E. MORIN
a63eb7a227 configure: fix seccomp check
Currently, if libseccomp is missing but the user explicitly requested
seccomp support using --enable-seccomp, configure silently ignores the
situation and disables seccomp support.

This is unlike all other tests that explicitly fail in such situation.

Fix that.

Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.fr>
Reviewed-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit e84d5956cc)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:18 -05:00
Stefan Hajnoczi
a638498f51 net: EAGAIN handling for net/socket.c TCP
Replace spinning send_all() with a proper non-blocking send.  When the
socket write buffer limit is reached, we should stop trying to send and
wait for the socket to become writable again.

Non-blocking TCP sockets can return in two different ways when the write
buffer limit is reached:

1. ret = -1 and errno = EAGAIN/EWOULDBLOCK.  No data has been written.

2. ret < total_size.  Short write, only part of the message was
   transmitted.

Handle both cases and keep track of how many bytes have been written in
s->send_index.  (This includes the 'length' header before the actual
payload buffer.)

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit 45a7f54a8b)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:18 -05:00
Stefan Hajnoczi
9d72a090b2 net: EAGAIN handling for net/socket.c UDP
Implement asynchronous send for UDP (or other SOCK_DGRAM) sockets.  If
send fails with EAGAIN we wait for the socket to become writable again.

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit 213fd5087e)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:18 -05:00
Stefan Hajnoczi
ab52df7712 net: asynchronous send/receive infrastructure for net/socket.c
The net/socket.c net client is not truly asynchronous.  This patch
borrows the qemu_set_fd_handler2() code from net/tap.c as the basis for
proper asynchronous send/receive.

Only read packets from the socket when the peer is able to receive.
This avoids needless queuing.

Later patches implement asynchronous send.

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit 863f678fba)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:18 -05:00
Stefan Hajnoczi
5c8240c09c net: broadcast hub packets if at least one port can receive
In commit 60c07d933c ("net: fix
qemu_can_send_packet logic") the "VLAN" broadcast behavior was changed
to queue packets if any net client cannot receive.  It turns out that
this was not actually the right fix and just hides the real bug that
hw/usb/dev-network.c:usbnet_receive() clobbers its receive buffer when
called multiple times in a row.  The commit also introduced a new bug
that "VLAN" packets would not be sent if one of multiple net clients was
down.

The hw/usb/dev-network.c bug has since been fixed, so this patch reverts
broadcast behavior to send packets as long as one net client can
receive.  Packets simply get queued for the net clients that are
temporarily unable to receive.

Reported-by: Roy.Li <rongqing.li@windriver.com>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit 61518a74ca)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:18 -05:00
Stefan Hajnoczi
d8f4811880 net: fix usbnet_receive() packet drops
The USB network interface has a single buffer which the guest reads
from.  This patch prevents multiple calls to usbnet_receive() from
clobbering the input buffer.  Instead we queue packets until buffer
space becomes available again.

This is inspired by virtio-net and e1000 rxbuf handling.

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit 190563f9a9)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:18 -05:00
Stefan Hajnoczi
2747a3eee3 net: clean up usbnet_receive()
The USB network interface has two code paths depending on whether or not
RNDIS mode is enabled.  Refactor usbnet_receive() so that there is a
common path throughout the function instead of duplicating everything
across if (is_rndis(s)) ... else ... code paths.

Clean up coding style and 80 character line wrap along the way.

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit f237ddbb89)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:18 -05:00
Stefan Hajnoczi
aa69dd05ce net: add -netdev options to man page
Document the -netdev syntax which supercedes the older -net syntax.
This patch is a first step to making -netdev prominent in the QEMU
manual.

Reported-by: Anatoly Techtonik <techtonik@gmail.com>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit 08d12022c7)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:18 -05:00
Stefan Hajnoczi
a9d8f7b1c4 net: do not report queued packets as sent
Net send functions have a return value where 0 means the packet has not
been sent and will be queued.  A non-zero value means the packet was
sent or an error caused the packet to be dropped.

This patch fixes two instances where packets are queued but we return
their size.  This causes callers to believe the packets were sent.  When
the caller uses the async send interface this creates a real problem
because the callback will be invoked for a packet that the caller
believed to be already sent.  This bug can cause double-frees in the
caller.

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit 06b5f36d05)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:18 -05:00
Stefan Hajnoczi
0d91cd5aa7 net: add receive_disabled logic to iov delivery path
This patch adds the missing NetClient->receive_disabled logic in the
sendv delivery code path.  It seems that commit
893379efd0 ("net: disable receiving if
client returns zero") only added the logic to qemu_deliver_packet() and
not qemu_deliver_packet_iov().

The receive_disabled flag should be automatically set when .receive(),
.receive_raw(), or .receive_iov() return 0.  No further packets will be
delivered to the NetClient until the receive_disabled flag is cleared
again by calling qemu_flush_queued_packets().

Typically the NetClient will wait until its file descriptor becomes
writable and then invoke qemu_flush_queued_packets() to resume
transmission.

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit c67f5dc105)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:18 -05:00
Bo Yang
bfa23099aa eepro100: Fix network hang when rx buffers run out
This is reported by QA. When installing os with pxe, after the initial
kernel and initrd are loaded, the procedure tries to copy files from install
server to local harddisk, the network becomes stall because of running out of
receive descriptor.

[Whitespace fixes and removed qemu_notify_event() because Paolo's
earlier net patches have moved it into qemu_flush_queued_packets().

Additional info:

I can reproduce the network hang with a tap device doing a iPXE HTTP
boot as follows:

  $ qemu -enable-kvm -m 1024 \
    -netdev tap,id=netdev0,script=no,downscript=no \
    -device i82559er,netdev=netdev0,romfile=80861209.rom \
    -drive if=virtio,cache=none,file=test.img
  iPXE> ifopen net0
  iPXE> config # set static network configuration
  iPXE> kernel http://mirror.bytemark.co.uk/fedora/linux/releases/17/Fedora/x86_64/os/images/pxeboot/vmlinuz

I needed a vanilla iPXE ROM to get to the iPXE prompt.  I think the boot
prompt has been disabled in the ROMs that ship with QEMU to reduce boot
time.

During the vmlinuz HTTP download there is a network hang.  hw/eepro100.c
has reached the end of the rx descriptor list.  When the iPXE driver
replenishes the rx descriptor list we don't kick the QEMU net subsystem
and event loop, thereby leaving the tap netdev without its file
descriptor in select(2).

Stefan Hajnoczi <stefanha@gmail.com>]

Signed-off-by: Bo Yang <boyang@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit 1069985fb1)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:18 -05:00
Paolo Bonzini
65a2f8e27c xen: flush queue when getting an event
xen does not have a register that, when written, will cause can_receive
to go from false to true.  However, flushing the queue can be attempted
whenever the front-end raises its side of the Xen event channel.  There
is a single event channel for tx and rx.

Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Cc: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Amos Kong <akong@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit a98b140223)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:18 -05:00
Paolo Bonzini
7575a6d2f2 e1000: flush queue whenever can_receive can go from false to true
When the guests replenish the receive ring buffer, the network device
should flush its queue of pending packets.  This is done with
qemu_flush_queued_packets.

e1000's can_receive can go from false to true when RCTL or RDT are
modified.

Reported-by: Luigi Rizzo <rizzo@iet.unipi.it>
Cc: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Cc: Jan Kiszka <jan.kiszka@siemens.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Amos Kong <akong@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit e8b4c680b4)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:18 -05:00
Paolo Bonzini
8e9fdc4a88 net: notify iothread after flushing queue
virtio-net has code to flush the queue and notify the iothread
whenever new receive buffers are added by the guest.  That is
fine, and indeed we need to do the same in all other drivers.
However, notifying the iothread should be work for the network
subsystem.  And since we are at it we can add a little smartness:
if some of the queued packets already could not be delivered,
there is no need to notify the iothread.

Reported-by: Luigi Rizzo <rizzo@iet.unipi.it>
Cc: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Cc: Jan Kiszka <jan.kiszka@siemens.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Amos Kong <akong@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit 987a9b4800)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Igor Mitsyanko
ca54dc1e75 arch_init.c: add missing '%' symbols before PRIu64 in debug printfs
'%' symbols were missing in front of PRIu64 macros in DPRINTF() messages in
arch_init.c, this caused compilation warnings when compiled with DEBUG_ARCH_INIT defined.

Signed-off-by: Igor Mitsyanko <i.mitsyanko@samsung.com>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit ef37a699a0)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Stefan Weil
a78cedc09e kvm: Fix warning from static code analysis
Report from smatch:

kvm-all.c:1373 kvm_init(135) warn:
 variable dereferenced before check 's' (see line 1360)

's' cannot by NULL (it was alloced using g_malloc0), so there is no need
to check it here.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit 6d1cc3210c)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Lei Li
59a01f73c3 qapi: Fix enumeration typo error
Signed-off-by: Lei Li <lilei@linux.vnet.ibm.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit 6932a69b20)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
BALATON Zoltan
c6553fee81 console: Clean up bytes per pixel calculation
Division with round up is the correct way to compute this even if the
only case where division with round down gives incorrect result is
probably 15 bpp. This case was explicitely patched up in one of these
functions but was unhandled in the other. (I'm not sure about setting
16 bpp for the 15bpp case either but I left that there for now.)

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit feadf1a4de)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Stefan Weil
a0d718a395 Spelling fixes in comments and documentation
These wrong spellings were detected by codespell:

* successully -> successfully

* alot -> a lot

* wanna -> want to

* infomation -> information

* occured -> occurred

["also is" -> "is also" and "ressources" -> "resources" suggested by
Peter Maydell <peter.maydell@linaro.org>]

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit 0546b8c2f0)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Stefan Weil
34173da021 srp: Don't use QEMU_PACKED for single elements of a structured type
QEMU_PACKED results in a MinGW compiler warning when it is
used for single structure elements:

warning: 'gcc_struct' attribute ignored

Using QEMU_PACKED for the whole structure avoids the compiler warning
without changing the memory layout.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit 93d3ad2a80)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Hervé Poussineau
c23314334d slirp: Implement TFTP Blocksize option
This option is described in RFC 1783. As this is only an optional field,
we may ignore it in some situations and handle it in some others.

However, MS Windows 2003 PXE boot client requests a block size of the MTU
(most of the times 1472 bytes), and doesn't work if the option is not
acknowledged (with whatever value).

According to the RFC 1783, we cannot acknowledge the option with a bigger
value than the requested one.

As current implementation is using 512 bytes by block, accept the option
with a value of 512 if the option was specified, and don't acknowledge it
if it is not present or less than 512 bytes.

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
(cherry picked from commit 95b1ad7ad8)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Hervé Poussineau
b83f395ba1 slirp: Handle more than 65535 blocks in TFTP transfers
RFC 1350 does not mention block count roll-over. However, a lot of TFTP servers
implement it to be able to transmit big files, so do it also.

Current block size is 512 bytes, so TFTP files were limited to 32 MB.

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
(cherry picked from commit 4aa401f39e)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Hervé Poussineau
34f7e690c3 slirp: improve TFTP performance
When transferring a file, keep it open during the whole transfer,
instead of opening/closing it for each block.

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
(cherry picked from commit 78be056628)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Stefan Weil
6116adbc0e slirp: Fix error reported by static code analysis
Report from smatch:

slirp/tcp_subr.c:127 tcp_respond(17) error:
 we previously assumed 'tp' could be null (see line 124)

Return if 'tp' is NULL.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
(cherry picked from commit e56afbc54a)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Stefan Weil
3ed791b42d slirp: Remove wrong type casts ins debug statements
The type casts of pointers to long are not allowed
when sizeof(pointer) != sizeof(long).

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
(cherry picked from commit c4d12a743c)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Hans de Goede
2ee160f8e1 uhci: Don't queue up packets after one with the SPD flag set
Don't queue up packets after a packet with the SPD (short packet detect)
flag set. Since we won't know if the packet will actually be short until it
has completed, and if it is short we should stop the queue.

This fixes a miniature photoframe emulating a USB cdrom with the windows
software for it not working.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Hans de Goede
981e213cf7 usb-redir: Revert usb-redir part of commit 93bfef4c
Commit 93bfef4c6e makes qemu-devices
which report the qemu version string to the guest in some way use a
qemu_get_version function which reports a machine-specific version string.

However usb-redir does not expose the qemu version to the guest, only to
the usbredir-host as part of the initial handshake. This can then be logged
on the usbredir-host side for debugging purposes and is otherwise completely
unused! For debugging purposes it is important to have the real qemu version
in there, rather then the machine-specific version.

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

Conflicts:

	hw/usb/redirect.c

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Hans de Goede
d56d7e6ef8 ehci: Walk async schedule before and after migration
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit ceab6f9645)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Hans de Goede
ad2cea3878 ehci: Don't set seen to 0 when removing unseen queue-heads
When removing unseen queue-heads from the async queue list, we should not
set the seen flag to 0, as this may cause them to be removed by
ehci_queues_rip_unused() during the next call to ehci_advance_async_state()
if the timer is late or running at a low frequency.

Note:
1) This *may* have caused the instant unlink / relinks described in commit
   9bc3a3a216

2) Rather then putting more if-s inside ehci_queues_rip_unused, this patch
   instead introduces a new ehci_queues_rip_unseen function.

3) This patch also makes it save to call ehci_queues_rip_unseen() multiple
   times, which gets used in the folluw up patch titled:
   "ehci: Walk async schedule before and after migration"

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:17 -05:00
Aurelien Jarno
d28ed2ffbb configure: usbredir fixes
usbredir is only used by system emulation, so add the libraries to
libs_softmmu instead of LIBS.

Cc: Michael Tokarev <mjt@tls.msk.ru>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 56ab2ad177)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:16 -05:00
Alon Levy
bffb221775 hw/qxl: tracing fixes
Add two new trace events:
qxl_send_events(int qid, uint32_t events) "%d %d"
qxl_set_guest_bug(int qid) "%d"

Change qxl_io_unexpected_vga_mode parameters to be equivalent to those
of qxl_io_write for easier grouping under a single systemtap probe.

Change d to qxl in one place.

Signed-off-by: Alon Levy <alevy@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 917ae08ca1)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:16 -05:00
Dunrong Huang
9cf4af689b block: Don't forget to delete temporary file
The caller would not delete temporary file after failed get_tmp_filename().

Signed-off-by: Dunrong Huang <riegamaths@gmail.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit fe235a06e1)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:16 -05:00
Daniel P. Berrange
f9f552e80b Don't require encryption password for 'qemu-img info' command
The encryption password is only required if I/O is going to be
performed on a disk image. The 'qemu-img info' command merely
reports metadata, so it should not ask for a decryption password

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit f0536bb848)

Conflicts:

	qemu-img.c

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:16 -05:00
Jason Baron
7cf7e305cc ahci: properly reset PxCMD on HBA reset
While testing q35, I found that windows 7 (specifically, windows 7 ultimate
with sp1 x64), wouldn't install because it can't find the cdrom or disk drive.
The failure message is: 'A required cd/dvd device driver is missing. If you
have a driver floppy disk, CD, DVD, or USB flash drive, please insert it now.'
This can also be reproduced on piix by adding an ahci controller, and
observing that windows 7 does not see any devices behind it.

The problem is that when windows issues a HBA reset, qemu does not reset the
individual ports' PxCMD register. Windows 7 then reads back the PxCMD register
and presumably assumes that the ahci controller has already been initialized.
Windows then never sets up the PxIE register to enable interrupts, and thus it
never gets irqs back when it sends ata device inquiry commands.

This change brings qemu into ahci 1.3 specification compliance.

Section 10.4.3 HBA Reset:

"
When GHC.HR is set to '1', GHC.AE, GHC.IE, the IS register, and all port
register fields (except PxFB/PxFBU/PxCLB/PxCLBU) that are not HwInit in the
HBA's register memory space are reset.
"

I've also re-tested Fedora 16 and 17 to verify that they continue to work with
this change.

Signed-off-by: Jason Baron <jbaron@redhat.com>
Acked-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 2a4f4f34e6)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:16 -05:00
Pavel Hrdina
84a2ca9f90 block: fix block tray status
The tray status should change also if you eject empty block device.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 9ca111544c)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:16 -05:00
Stefan Weil
1c224f0ab3 vdi: Fix warning from clang
ccc-analyzer reports these warnings:

block/vdi.c:704:13: warning: Dereference of null pointer
            bmap[i] = VDI_UNALLOCATED;
            ^
block/vdi.c:702:13: warning: Dereference of null pointer
            bmap[i] = i;
            ^

Moving some code into the if block fixes this.
It also avoids calling function write with 0 bytes of data.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 514f21a5d4)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:16 -05:00
Stefan Weil
1e32a1651a block/curl: Fix wrong free statement
Report from smatch:
block/curl.c:546 curl_close(21) info: redundant null check on s->url calling free()

The check was redundant, and free was also wrong because the memory
was allocated using g_strdup.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 45724d6d02)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:16 -05:00
Stefan Weil
3900d1d992 ide: Fix error messages from static code analysis (no real error)
Report from smatch:
hw/ide/core.c:1472 ide_exec_cmd(423) error: buffer overflow 'smart_attributes' 8 <= 29
hw/ide/core.c:1474 ide_exec_cmd(425) error: buffer overflow 'smart_attributes' 8 <= 29
hw/ide/core.c:1475 ide_exec_cmd(426) error: buffer overflow 'smart_attributes' 8 <= 29
...

The upper limit of 30 was never reached because both for loops terminated
when 'smart_attributes' reached end of list, so there was no real buffer
overflow.

Nevertheless, changing the code not only fixes the error report, but also
reduces the size of smart_attributes and simplifies the for loops.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 1e53537fda)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:16 -05:00
MORITA Kazutaka
1fce4135f3 sheepdog: fix savevm and loadvm
This patch sets data to be sent to Sheepdog correctly and fixes savevm
and loadvm operations on a Sheepdog image.

Signed-off-by: MORITA Kazutaka <morita.kazutaka@lab.ntt.co.jp>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 1f7a48de44)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:16 -05:00
Hans de Goede
349b4e9070 ehci: Don't process too much frames in 1 timer tick (v2)
The Linux ehci isoc scheduling code fills the entire schedule ahead of
time minus 80 frames. If we make a large jump in where we are in the
schedule, ie 40 frames, then the scheduler all of a sudden will only have
40 frames left to work in, causing it to fail packet submissions
with error -27 (-EFBIG).

Changes in v2:
-Don't hardcode a maximum number of frames to process in one tick, instead:
 -Process a minimum number of frames to ensure we do eventually catch up
 -Stop (after the minimum number) when the guest has requested an irq

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:16 -05:00
Hans de Goede
29ecaa26a8 ehci: Fix interrupts stopping when Interrupt Threshold Control is 8
If Interrupt Threshold Control is 8 or a multiple of 8, then
s->usbsts_frindex can become exactly 0x4000, at which point
(s->usbsts_frindex > s->frindex) will never become true, as
s->usbsts_frindex will not be lowered / reset in this case.

This patch fixes this.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:16 -05:00
Gerd Hoffmann
1f97f6c9fe ehci: switch to new-style memory ops
Also register different memory regions for capabilities,
operational registers and port status registers.  Create
separate tracepoints for operational regs and port status
regs.  Ditch a bunch of sanity checks because the memory
core will do this for us now.

Offloading the byte, word and dword access handling to the
memory core also has the side effect of fixing ehci register
access on bigendian hosts.

Cc: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 3e4f910c8d)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:16 -05:00
Uri Lublin
9a5a94de58 qxl: better cleanup for surface destroy
Add back a call to qxl_spice_destroy_surface_wait_complete() in qxl_spice_destroy_surface_wait(),
that was removed by commit c480bb7da4

It is needed to complete surface-removal cleanup, for non async.
For async, qxl_spice_destroy_surface_wait_complete is called upon operation completion.

Signed-off-by: Uri Lublin <uril@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 753b8b0d77)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:15 -05:00
Gerd Hoffmann
462ff6fda1 usb-host: allow emulated (non-async) control requests without USBPacket
xhci needs this for USB_REQ_SET_ADDRESS due to the way
usb addressing is handled by the xhci hardware.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:15 -05:00
Dunrong Huang
b26859ab18 qxl: dont update invalid area
This patch fixes the following error:

$ ~/usr/bin/qemu-system-x86_64 -enable-kvm -m 1024 -spice port=5900,disable-ticketing -vga qxl -cdrom ~/Images/linuxmint-13-mate-dvd-32bit.iso
(/home/mathslinux/usr/bin/qemu-system-x86_64:10068): SpiceWorker-CRITICAL **: red_worker.c:4599:red_update_area: condition `area->left >= 0 && area->top >= 0 && area->left < area->right && area->top < area->bottom' failed
Aborted

spice server terminates QEMU process if we pass invalid area to it,
so dont update those invalid areas.

Signed-off-by: Dunrong Huang <riegamaths@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit ccc2960d65)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:15 -05:00
Gerd Hoffmann
03c0342cb8 xhci: allow bytewise capability register reads
Some guests need this according to
Alejandro Martinez Ruiz <alex@securiforest.com>

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

Conflicts:

	hw/usb/hcd-xhci.c

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:15 -05:00
Gerd Hoffmann
23ba9d4838 xhci: fix runtime write tracepoint
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 8e9f18b6db)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:15 -05:00
Gerd Hoffmann
640bda8df5 xhci: drop buffering
This patch splits the xhci_xfer_data function into three.
The xhci_xfer_data function used to do does two things:

  (1) copy transfer data between guest memory and a temporary buffer.
  (2) report transfer results to the guest using events.

Now we three functions to handle this:

  (1) xhci_xfer_map creates a scatter list for the transfer and
      uses that (instead of the temporary buffer) to build a
      USBPacket.
  (2) xhci_xfer_unmap undoes the mapping.
  (3) xhci_xfer_report sends out events.

The patch also fixes reporting of transaction errors which must be
reported unconditinally, not only in case the guest asks for it
using the ISP flag.

[ v2: fix warning ]

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:15 -05:00
Gerd Hoffmann
64022e9d58 xhci: rip out background transfer code
original xhci code (the one which used libusb directly) used to use
'background transfers' for iso streams.  In upstream qemu the iso
stream buffering is handled by usb-host & usb-redir, so we will
never ever need this.  It has been left in as reference, but is dead
code anyway.  Rip it out.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:15 -05:00
Gerd Hoffmann
3e3750e10a usb-audio: fix usb version
usb-audio is a full speed (1.1) device,
but bcdUSB claims it is usb 2.0.  Fix it.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:15 -05:00
Samuel Thibault
fbcb89ddc9 Better name usb braille device
Windows users need to know that they have to use the Baum driver to make
the qemu braille device work.

Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 2964cd9bfa)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:15 -05:00
Hans de Goede
22ba7a7488 usb-redir: Return babble when getting more bulk data then requested
Babble is the appropriate error in this case (rather then signalling a stall).

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:15 -05:00
Hans de Goede
636071de92 usb-redir: Move to core packet id and queue handling
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit de550a6afb)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:15 -05:00
Hans de Goede
55a2f465b9 usb-redir: Get rid of unused async-struct dev member
This is a preparation patch for completely getting rid of the async-packet
struct in usb-redir, instead relying on the (new) per ep queues in the
qemu usb core.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:15 -05:00
Hans de Goede
aa57b628e0 usb-redir: Get rid of local shadow copy of packet headers
The shadow copy only serves as an extra check (besides the packet-id) to
ensure the packet we get back is a reply to the packet we think it is.

This check has never triggered in all the time usb-redir is in use now,
and since the verified data in the returned packet-header is not used
otherwise, removing the check does not open any possibilities for the
usbredirhost to confuse us.

This is a preparation patch for completely getting rid of the async-packet
struct in usb-redir, instead relying on the (new) per ep queues in the
qemu usb core.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:15 -05:00
Hans de Goede
57eae744d4 usb-redir: Get rid of async-struct get member
This is a preparation patch for completely getting rid of the async-packet
struct in usb-redir, instead relying on the (new) per ep queues in the
qemu usb core.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:14 -05:00
Hans de Goede
14ecfb09fa usb-redir: Don't delay handling of open events to a bottom half
There is no need for this, and doing so means that a backend trying to
write immediately after an open event will see qemu_chr_be_can_write
returning 0, which not all backends handle well as there is no wakeup
mechanism to detect when the frontend does become writable.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:14 -05:00
Hans de Goede
1d5ba9a6a8 usb-redir: Never return USB_RET_NAK for async handled packets
USB_RET_NAK is not a valid response for async handled packets (and will
trigger an assert as such).

Also drop the warning when receiving a status of cancelled for packets not
cancelled by qemu itself, this can happen when a device gets unredirected
by the usbredir-host while transfers are pending.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:14 -05:00
Hans de Goede
77c3d59256 ehci: Correct a comment in fetchqtd packet processing
Since my previous comment said "Should never happen", I tried changing the
next line to an assert(0), which did not go well, which as the new comments
explains is logical if you think about it for a moment.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:14 -05:00
Hans de Goede
e2ab86fe2d ehci: Handle USB_RET_PROCERR in ehci_fill_queue
USB_RET_PROCERR can be triggered by the guest (by for example requesting more
then BUFFSIZE bytes), so don't assert on it.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:14 -05:00
Hans de Goede
2f7ba4731b ehci: Fix memory leak in handling of NAK-ed packets
Currently each time we try to execute a NAK-ed packet we redo
ehci_init_transfer, and usb_packet_map, re-allocing (without freeing) the
sg list every time.

This patch fixes this, it does this by introducing another async state, so
that we also properly cleanup a NAK-ed packet on cancel.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:14 -05:00
Hans de Goede
0154d330c7 ehci: Add some additional ehci_trace_guest_bug() calls
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 3a8ca08e01)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:14 -05:00
Gerd Hoffmann
d294ad6323 ehci: add doorbell trace events
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 1defcbd1e8)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:14 -05:00
Gerd Hoffmann
62fc5e6983 ehci: trace guest bugs
make qemu_queue_{cancel,reset} return the number of packets released,
so the caller can figure whenever there have been active packets even
though there shouldn't have been any.  Add tracepoint to log this.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:14 -05:00
Gerd Hoffmann
4a6cdb4807 ehci: check for EHCI_ASYNC_FINISHED first in ehci_free_packet
Otherwise we'll see the packet free twice in the trace log even though
it actually happens only once.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:14 -05:00
Hans de Goede
a8cf10d5d6 ehci: Properly report completed but not yet processed packets to the guest
Reported packets which have completed before being cancelled as such to the
host. Note that the new code path this patch adds is untested since it I've
been unable to actually trigger the race which needs this code path.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
(cherry picked from commit 4b63a0df3b)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:14 -05:00
Hans de Goede
307fea863a ehci: Properly cleanup packets on cancel
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
(cherry picked from commit 0e7953525f)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:14 -05:00
Hans de Goede
c15d61b252 ehci: Update copyright headers to reflect recent work
Update copyright headers to reflect all the work Gerd and I have been doing
on the EHCI emulation.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
(cherry picked from commit 522079dd44)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:14 -05:00
Hans de Goede
712fc762a6 ehci: Validate qh is not changed unexpectedly by the guest
-combine the qh check with the check for devaddr changes
-also ensure that p gets set to NULL when the queue gets cancelled on
 devaddr change, which was not done properly before this patch

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:13 -05:00
Hans de Goede
a37d5e521a Revert "ehci: don't flush cache on doorbell rings."
This reverts commit 9bc3a3a216, which got
added to fix an issue where the real, underlying cause was not stopping
the ep queue on an error.

Now that the underlying cause is fixed by the "usb: Halt ep queue and
cancel pending packets on a packet error" patch, the "don't flush" fix
is no longer needed.

Not only is it not needed, it causes us to see cancellations (unlinks)
done by the Linux EHCI driver too late, which in combination with the new
usb-core packet-id generation where qtd addresses are used as ids, causes
duplicate ids for in flight packets.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
(cherry picked from commit 66f092d256)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:13 -05:00
Hans de Goede
d6e508d3a5 usb-core: Allow the first packet of a pipelined ep to complete immediately
This can happen with usb-redir live-migration when the packet gets re-queued
after the migration and the original queuing from the migration source side
has already finished.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:13 -05:00
Hans de Goede
d780116ab0 usb-core: Add a usb_ep_find_packet_by_id() helper function
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit c13a9e6136)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:13 -05:00
Hans de Goede
597330bd8d usb-core: Don't set packet state to complete on a nak
This way the hcd can re-use the same packet to retry without needing
to re-init it.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:13 -05:00
Hans de Goede
4ebbf3229a usb: controllers do not need to check for babble themselves
If an (emulated) usb-device tries to write more data to a packet then
its iov len, this will trigger an assert in usb_packet_copy(), and if
a driver somehow circumvents that check and writes more data to the
iov then there is space, we have a much bigger problem then not correctly
reporting babble to the guest.

In practice babble will only happen with (real) redirected devices, and there
both the usb-host os and the qemu usb-device code already check for it.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:13 -05:00
Daniel P. Berrange
b5701820f8 Add ability to force enable/disable of tools build
The qemu-img, qemu-nbd and qemu-io tools are built conditionally
based on whether any softmmu target is enabled. These are useful
self-contained tools which can be used in many other scenarios.
Add new --enable-tools/--disable-tools args to configure to allow
the user to explicitly turn on / off their build. The default
behaviour is now to build these tools are all times, regardless
of whether any softmmu target is enabled

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 4b1c11fd20)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-11 21:44:13 -05:00
Anthony Liguori
5af6b07ab0 socket: don't attempt to reconnect a TCP socket in server mode
Commit c3767ed0eb introduced a possible SEGV when
using a socket chardev with server=on because it assumes that all TCP sockets
are in client mode.

This patch adds a check to only reconnect when in client mode.

Cc: Lei Li <lilei@linux.vnet.ibm.com>
Reported-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 455aa1e081)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:30 -05:00
Michael Tokarev
82645b9e93 use --libexecdir instead of ignoring it first and reinventing it later
Commit 7b93fadf3a "Add basic version
of bridge helper" put the bridge helper executable into a fixed
${prefix}/libexec/ location, instead of using ${libexecdir} for
this.  At the same time, --libexecdir is being happily ignored
by ./configure.  Even more, the same patch sets unused $libexecdir
variable in the generated config-host.mak, and uses fixed string
(\${prefix}/libexecdir) for the bridge helper binary.

Fix this braindamage by introducing $libexecdir variable, using
it for the bridge helper binary, and recognizing --libexecdir.

This patch is applicable to stable-1.1.

Reviewed-by: Andreas Färber <afaerber@suse.de>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
Cc: Corey Bryant <coreyb@linux.vnet.ibm.com>
Cc: Richa Marwaha <rmarwah@linux.vnet.ibm.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 8bf188aa18)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:30 -05:00
Stefan Weil
b750d22466 hw/mcf5206: Fix buffer overflow for MBAR read / write
Report from smatch:

mcf5206.c:384 m5206_mbar_readb(7) error: buffer overflow 'm5206_mbar_width' 128 <= 128
mcf5206.c:403 m5206_mbar_readw(8) error: buffer overflow 'm5206_mbar_width' 128 <= 128
mcf5206.c:427 m5206_mbar_readl(8) error: buffer overflow 'm5206_mbar_width' 128 <= 128
mcf5206.c:451 m5206_mbar_writeb(9) error: buffer overflow 'm5206_mbar_width' 128 <= 128
mcf5206.c:475 m5206_mbar_writew(9) error: buffer overflow 'm5206_mbar_width' 128 <= 128
mcf5206.c:503 m5206_mbar_writel(9) error: buffer overflow 'm5206_mbar_width' 128 <= 128

m5206_mbar_width has 0x80 elements and supports 0 <= offset < 0x200.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit a32354e206)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:30 -05:00
Stefan Weil
bd4dba6658 hw/wm8750: Fix potential buffer overflow
Report from smatch:

hw/wm8750.c:369 wm8750_tx(12) error: buffer overflow 's->i2c_data' 2 <= 2

It looks like the preprocessor statements were simply misplaced.

Replace also __FUNCTION__ by __func__ to please checkpatch.pl.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 149eeb5fe5)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:30 -05:00
Christian Borntraeger
7566759fd5 qemu: Use valgrind annotations to mark kvm guest memory as defined
valgrind with kvm produces a big amount of false positives regarding
"Conditional jump or move depends on uninitialised value(s)". This
happens because the guest memory is allocated with qemu_vmalloc which
boils down posix_memalign etc. This function is (correctly) considered
by valgrind as returning undefined memory.

Since valgrind is based on jitting code, it will not be able to see
changes made by the guest to guest memory if this is done by KVM_RUN,
thus keeping most of the guest memory undefined.

Now lots of places in qemu will then use guest memory to change behaviour.
To avoid the flood of these messages, lets declare the whole guest
memory as defined. This will reduce the noise and allows us to see real
problems.

In the future we might want to make this conditional, since there
is actually something that we can use those false positives for:
These messages will point to code that depends on guest memory, so
we can use these backtraces to actually make an audit that is focussed
only at those code places. For normal development we dont want to
see those messages, though.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
(cherry picked from commit 62fe83318d)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:30 -05:00
Jan Kiszka
47b11da1e9 musicpal: Fix flash mapping
The old arithmetic assumed 32 physical address bits which is no longer
true for ARM since 3cc0cd61f4.

Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
(cherry picked from commit 0c267217ca)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:30 -05:00
Fabien Chouteau
2ecd8831e0 Add MAINTAINERS entry for leon3
Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
(cherry picked from commit ce6c760c37)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:30 -05:00
Maciej W. Rozycki
27aae39fa0 MIPS/user: Fix reset CPU state initialization
This change updates the CPU reset sequence to use a common piece of code
that figures out CPU state flags, fixing the problem with MIPS_HFLAG_COP1X
not being set where applicable that causes floating-point MADD family
instructions (and other instructions from the MIPS IV FP subset) to trap.

 As compute_hflags is now shared between op_helper.c and translate.c, the
function is now moved to a common header.  There are no changes to this
function.

 The problem was seen with the 24Kf MIPS32r2 processor in user emulation.
The new approach prevents system and user emulation from diverging -- all
the hflags state is initialized in one place now.

Signed-off-by: Maciej W. Rozycki <macro@codesourcery.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 03e6e50177)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:30 -05:00
Aurelien Jarno
635cc81bf9 lan9118: fix multicast filtering
The lan9118 emulation tries to compute the multicast index by calling
directly the crc32() function from zlib, but fails to get the correct
result.

Use the common compute_mcast_idx() function instead, which gives the
correct result. This fixes IPv6 support.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 449bc90e1f)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:30 -05:00
Henning Schild
4de6467cbc fix entry pointer for ELF kernels loaded with -kernel option
Find a hopefully proper patch attached. Take it or leave it.

Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Henning Schild <henning@hennsch.de>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 7e9c7ffe9f)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:29 -05:00
Jason Baron
4382057785 pcie_aer: clear cmask for Advanced Error Interrupt Message Number
The Advanced Error Interrupt Message Number (bits 31:27 of the Root
Error Status Register) is updated when the number of msi messages assigned to a
device changes. Migration of windows 7 on q35 chipset failed because the check
in get_pci_config_device() fails due to cmask being set on these bits. Its valid
to update these bits and we must restore this state across migration.

Signed-off-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit 0e180d9c8a)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:29 -05:00
Jason Baron
6ac46e3216 pcie: drop version_id field for live migration
While testing q35 live migration, I found that the migration would abort with
the following error: "Unknown savevm section type 76".

The error is due to this check failing in 'vmstate_load_state()':

    while(field->name) {
        if ((field->field_exists &&
             field->field_exists(opaque, version_id)) ||
            (!field->field_exists &&
             field->version_id <= version_id)) {

The VMSTATE_PCIE_DEVICE() currently has a 'version_id' set to 2. However,
'version_id' in the above check is 1. And thus we fail to load the pcie device
field. Further the code returns to 'qemu_loadvm_state()' which produces the
error that I saw.

I'm proposing to fix this by simply dropping the 'version_id' field from
VMSTATE_PCIE_DEVICE(). VMSTATE_PCI_DEVICE() defines no such field and further
the vmstate_pcie_device that VMSTATE_PCI_DEVICE() refers to is already
versioned. Thus, any versioning issues could be detected at the vmsd level.

Taking a step back, I think that the 'field->version_id' should be compared
against a saved version number for the field not the 'version_id'. Futhermore,
once vmstate_load_state() is called recursively on another vmsd, the check of:

    if (version_id > vmsd->version_id) {
        return -EINVAL;
    }

Will never fail since version_id is always equal to vmsd->version_id. So I'm
wondering why we aren't storing the vmsd version id of the source in the
migration stream?

This patch also renames the 'name' field of vmstate_pcie_device from:
PCIDevice -> PCIEDevice to differentiate it from vmstate_pci_device.

Signed-off-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit 1de5345927)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:29 -05:00
Stefan Weil
3aec24d195 json-parser: Fix potential NULL pointer segfault
Report from smatch:
json-parser.c:474 parse_object(62) error: potential null derefence 'dict'.
json-parser.c:553 parse_array(75) error: potential null derefence 'list'.

Label 'out' in json-parser.c can be called with list == NULL
which is passed to QDECREF.

Modify QDECREF to handle a NULL argument (inline function qobject_decref
already handles them, too).

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
(cherry picked from commit 149474c934)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:29 -05:00
Stefan Weil
122b92d90a qapi: Fix potential NULL pointer segfault
Report from smatch:

qapi-visit.c:1640 visit_type_BlockdevAction(8) error:
 we previously assumed 'obj' could be null (see line 1639)
qapi-visit.c:2432 visit_type_NetClientOptions(8) error:
 we previously assumed 'obj' could be null (see line 2431)

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
(cherry picked from commit 227ccf6bff)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:29 -05:00
Amos Kong
23086b2054 fix doc of using raw values with sendkey
(qemu) sendkey a
(qemu) sendkey 0x1e
(qemu) sendkey #0x1e
 unknown key: '#0x1e'

The last command doesn't work, '#' is not requested before
raw values, and the raw value in decimal format is not supported.

Signed-off-by: Amos Kong <akong@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
(cherry picked from commit 886cc706ce)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:29 -05:00
Alon Levy
ea4c86551d configure: print spice-protocol and spice-server versions
Signed-off-by: Alon Levy <alevy@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 2e0e3c399a)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:29 -05:00
Alon Levy
b75c710575 qxl: add QXL_IO_MONITORS_CONFIG_ASYNC
Revision bumped to 4 for new IO support, enabled for spice-server >=
0.11.1. New io enabled if revision is 4. Revision can be set to 4.

[ kraxel: 3 continues to be the default revision.  Once we have a new
          stable spice-server release and the qemu patches to enable
          the new bits merged we'll go flip the switch and make rev4
          the default ]

This io calls the corresponding new spice api
spice_qxl_monitors_config_async to let spice-server read a new guest set
monitors config and notify the client.

On migration reissue spice_qxl_monitors_config_async.

RHBZ: 770842

Signed-off-by: Alon Levy <alevy@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

fixup

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

Conflicts:

	hw/qxl.c

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:29 -05:00
Alon Levy
5b7582af06 qxl/update_area_io: guest_bug on invalid parameters
Signed-off-by: Alon Levy <alevy@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 511b13e2c9)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:29 -05:00
Yonit Halperin
615198836c spice: increase the verbosity of spice section in "qemu --help"
Added all spice options to the help string. This can be used by libvirt
to determine which spice related features are supported by qemu.

Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 27af778828)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:29 -05:00
Yonit Halperin
7908e4a388 spice: adding seamless-migration option to the command line
The seamless-migration flag is required in order to identify
whether libvirt supports the new QEVENT_SPICE_MIGRATE_COMPLETED or not
(by default the flag is off).
New libvirt versions that wait for QEVENT_SPICE_MIGRATE_COMPLETED should turn on this flag.
When this flag is off, spice fallbacks to its old migration method, which
can result in data loss.

Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 8c9570530c)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:29 -05:00
Yonit Halperin
38a01d68c6 spice: add 'migrated' flag to spice info
The flag is 'true' when spice migration has completed on the src side.
It is needed for a case where libvirt dies before migration completes
and it misses the event QEVENT_SPICE_MIGRATE_COMPLETED.
When libvirt is restored and queries the migration status, it also needs
to query spice and check if its migration has completed.

Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 61c4efe2cb)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:29 -05:00
Yonit Halperin
986b9a1a2a spice migration: add QEVENT_SPICE_MIGRATE_COMPLETED
When migrating, libvirt queries the migration status, and upon migration
completions, it closes the migration src. On the other hand, when
migration is completed, spice transfers data from the src to destination
via the client. This data is required for keeping the spice session
after migration, without suffering from data loss and inconsistencies.
In order to allow this data transfer, we add QEVENT for signaling
libvirt that spice migration has completed, and libvirt needs to wait
for this event before quitting the src process.

Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 2fdd16e239)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:28 -05:00
Yonit Halperin
25bc2251eb spice: notify on vm state change only via spice_server_vm_start/stop
QXLWorker->start/stop are deprecated since spice-server 0.11.2

Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 71d388d420)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:28 -05:00
Yonit Halperin
fc24f3bd2e spice: notify spice server on vm start/stop
Spice server needs to know about the vm state in order to prevent
attempts to write to devices when they are stopped, mainly during
the non-live stage of migration.
Instead, spice will take care of restoring this writes, on the migration
target side, after migration completes.

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:28 -05:00
Christophe Fergeau
3c82758f04 spice: abort on invalid streaming cmdline params
When parsing its command line parameters, spice aborts when it
finds unexpected values, except for the 'streaming-video' option.
This happens because the parsing of the parameters for this option
is done using the 'name2enum' helper, which does not error out
on unknown values. Using the 'parse_name' helper makes sure we
error out in this case. Looking at git history, the use of
'name2enum' instead of 'parse_name' seems to have been an oversight,
so let's change to that now.

Fixes rhbz#831708

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:58:28 -05:00
Stefan Weil
7fd494086b tci: Fix for AREG0 free mode
Support for helper functions with 5 arguments was missing
in the code generator and in the interpreter.

There is no need to pass the constant TCG_AREG0 from the
code generator to the interpreter. Remove that code for
the INDEX_op_qemu_st* opcodes.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:11 -05:00
Stefan Weil
e46258fb50 tcg: Fix MAX_OPC_PARAM_IARGS
DEF_HELPER_FLAGS_5 was added some time ago without adjusting
MAX_OPC_PARAM_IARGS.

Fixing the definition becomes more important as QEMU is using
an increasing number of helper functions called with 5 arguments.

Add also a comment to avoid future problems when DEF_HELPER_FLAGS_6
will be added.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:11 -05:00
Aurelien Jarno
c90a8840b4 tcg/i386: fix build with -march < i686
The movcond_i32 op has to be protected with TCG_TARGET_HAS_movcond_i32
to fix the build with -march < i686.

Thanks to Richard Henderson for the hint.

Reported-by: Alex Barcelo <abarcelo@ac.upc.edu>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:11 -05:00
Richard Henderson
e1312991ed tcg: Adjust descriptions of *cond opcodes
The README file documented the operand ordering of the tcg_gen_*
functions.  Since we're documenting opcodes here, use the true
operand ordering.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Cc: malc <av1474@comtv.ru>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:11 -05:00
Aurelien Jarno
6c975d03a2 tcg/mips: fix MIPS32(R2) detection
Fix the MIPS32(R2) cpu detection so that it also works with
-march=octeon. Thanks to Andrew Pinski for the hint.

Cc: Andrew Pinski <apinski@cavium.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:11 -05:00
Richard Henderson
df6502fac5 target-alpha: Initialize env->cpu_model_str
Save the cpu_model_str so that we have a non-null value when
creating a new cpu during clone.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:11 -05:00
Richard Henderson
fef28a4336 tcg-sparc: Preserve branch destinations during retranslation
Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:11 -05:00
Richard Henderson
38df9027ce tcg-sparc: Fix and enable direct TB chaining.
Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Richard Henderson
ba8b16fac5 tcg-sparc: Add %g/%o registers to alloc_order
Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Richard Henderson
39cbcb4b45 tcg-sparc: Use defines for temporaries.
And change from %i4/%i5 to %g1/%o7 to remove a v8plus fixme.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Richard Henderson
db0cfd14ba tcg-sparc: Mask shift immediates to avoid illegal insns.
The xtensa-test image generates a sra_i32 with count 0x40.
Whether this is accident of tcg constant propagation or
originating directly from the instruction stream is immaterial.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Richard Henderson
5c7199f164 tcg-sparc: Clean up cruft stemming from attempts to use global registers.
Don't use -ffixed-gN.  Don't link statically.  Don't save/restore
AREG0 around calls.  Don't allocate space on the stack for AREG0 save.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Richard Henderson
60db655378 tcg-sparc: Change AREG0 in generated code to %i0.
We can now move the TCG variable from %g[56] to a call-preserved
windowed register.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Richard Henderson
757ee3f9e2 tcg-sparc: Support GUEST_BASE.
Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Richard Henderson
e85ec822e9 tcg-sparc: Fix qemu_ld/st to handle 32-bit host.
At the same time, split out the tlb load logic to a new function.
Fixes the cases of two data registers and two address registers.
Fixes the signature of, and adds missing, qemu_ld/st opcodes.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Richard Henderson
181dd0b27c tcg-sparc: Assume v9 cpu always, i.e. force v8plus in 32-bit mode.
Current code doesn't actually work in 32-bit mode at all.  Since
no one really noticed, drop the complication of v7 and v8 cpus.
Eliminate the --sparc_cpu configure option and standardize macro
testing on TCG_TARGET_REG_BITS / HOST_LONG_BITS

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Richard Henderson
e1784a4cbd tcg-sparc: Don't MAP_FIXED on top of the program
The address we pick in sparc64.ld is also 0x60000000, so doing a fixed map
on top of that is guaranteed to blow up.  Choosing 0x40000000 is exactly
right for the max of code_gen_buffer_size set below.

No need to ever use MAP_FIXED.  While getting our desired address helps
optimize the generated code, we won't fail if we don't get it.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Richard Henderson
e183eb99fa tcg-sparc: Fix ADDX opcode.
Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Richard Henderson
ee13de2853 tcg-sparc: Hack in qemu_ld/st64 for 32-bit.
Not actually implemented, but at least we avoid the tcg assert at startup.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
malc
6164c1274e tcg/ppc32: Implement movcond32
Thanks to Richard Henderson

Signed-off-by: malc <av1474@comtv.ru>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Stefan Weil
a48028b8e9 w64: Fix TCG helper functions with 5 arguments
TCG uses 6 registers for function arguments on 64 bit Linux hosts,
but only 4 registers on W64 hosts.

Commit 2999a0b200 increased the number
of arguments for some important helper functions from 4 to 5
which triggered a bug for W64 hosts: QEMU aborts when executing
helper_lcall_real in the guest's BIOS because function
tcg_target_get_call_iarg_regs_count always returned 6.

As W64 has only 4 registers for arguments, the 5th argument must be
passed on the stack using a correct stack offset.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Max Filippov
5096a7c7d8 tcg/README: document tcg_gen_goto_tb restrictions
See
http://lists.nongnu.org/archive/html/qemu-devel/2012-09/msg03196.html
for the whole story.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Aurelien Jarno
2e1d09263b tcg/optimize: add constant folding for deposit
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Aurelien Jarno
ffc1c56815 tcg: remove #ifdef #endif around TCGOpcode tests
Commit 25c4d9cc changed all TCGOpcode enums to be available, so we don't
need to #ifdef #endif the one that are available only on some targets.
This makes the code easier to read.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Aurelien Jarno
cfca711212 tcg/optimize: prefer the "op a, a, b" form for commutative ops
The "op a, a, b" form is better handled on non-RISC host than the "op
a, b, a" form, so swap the arguments to this form when possible, and
when b is not a constant.

This reduces the number of generated instructions by a tiny bit.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Aurelien Jarno
26adaf07da tcg/optimize: further optimize brcond/movcond/setcond
When both argument of brcond/movcond/setcond are the same or when one
of the two values is a constant equal to zero, it's possible to do
further optimizations.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:10 -05:00
Aurelien Jarno
f4643451e9 tcg/optimize: optimize "op r, a, a => movi r, 0"
Now that it's possible to detect copies, we can optimize the case
the "op r, a, a => movi r, 0". This helps in the computation of
overflow flags when one of the two args is 0.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
d3b9fb75c6 tcg/optimize: optimize "op r, a, a => mov r, a"
Now that we can easily detect all copies, we can optimize the
"op r, a, a => mov r, a" case a bit more.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
6599e3faae tcg/optimize: do copy propagation for all operations
It is possible to due copy propagation for all operations, even the one
that have side effects or clobber arguments (it only concerns input
arguments). That said, the call operation should be handled differently
due to the variable number of arguments.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
a17f24e08d tcg/optimize: rework copy progagation
The copy propagation pass tries to keep track what is a copy of what
and what has copy of what, and in addition it keep a circular list of
of all the copies. Unfortunately this doesn't fully work: a mov from
a temp which has a state "COPY" changed it into a state "HAS_COPY".
Later when this temp is used again, it is considered has not having
copy and thus no propagation is done.

This patch fixes that by removing the hiearchy between copies, and thus
only keeping a "COPY" state both meaning "is a copy" and "has a copy".
The decision of which copy to use is deferred to the actual temp
replacement. At this stage there is not one best choice to do, but only
better choices than others. For doing the best choice the operation
would have to be parsed in reversed to know if a temp is going to be
used later or not. That what is done by the liveness analysis. At this
stage it is known that globals will be always live, that local temps
will be dead at the end of the translation block, and that the temps
will be dead at the end of the basic block. This means that this stage
should try to replace temps by local temps or globals and local temps
by globals.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
a4c701ee76 tcg/optimize: check types in copy propagation
The copy propagation doesn't check the types of the temps during copy
propagation. However TCG is using the mov_i32 for the i64 to i32
conversion and thus the two are not equivalent.

With this patch tcg_opt_gen_mov() doesn't consider two temps of
different type as copies anymore.

So far it seems the optimization was not aggressive enough to trigger
this bug, but it will be triggered later in this series once the copy
propagation is improved.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
ad797145ae tcg/optimize: remove TCG_TEMP_ANY
TCG_TEMP_ANY has no different meaning than TCG_TEMP_UNDEF, so use
the later instead.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
7ef9bee924 tcg/mips: implement movcond op on MIPS32R2
movcond operation can be implemented on MIPS32 Release 2 using the MOVN,
MOVZ, SLT and SLTU instructions.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
6d82e71b6a tcg/mips: implement deposit op on MIPS32R2
deposit operations can be optimized on MIPS32 Release 2 using the INS
instruction.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
a8067da5d1 tcg/mips: implement rotl/rotr ops on MIPS32R2
rotr operations can be optimized on MIPS32 Release 2 using the ROTR and
ROTRV instructions. Also implemented rotl operations by subtracting the
shift from 32.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
3b63392482 tcg/mips: optimize bswap{16,16s,32} on MIPS32R2
bswap operations can be optimized on MIPS32 Release 2 using the ROTR,
WSBH and SEH instructions. We can't use the non-R2 code to implement the
ops due to registers constraints, so don't define the corresponding
TCG_TARGET_HAS_bswap* values.

Also bswap16* operations are supposed to be called with the 16 high bits
zeroed. This is the case everywhere (including for TCG by definition)
except when called from the store helper. Remove the AND instructions from
bswap16* and move it there.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
86b4f7ca05 tcg/mips: optimize brcond arg, 0
MIPS has some conditional branch instructions when comparing with zero.
Use them.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
adf89e7483 tcg/mips: use stack for TCG temps
Use stack instead of temp_buf array in CPUState for TCG
temps.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
8193cdd0d0 tcg/mips: don't use global pointer
Don't use the global pointer in TCG, in case helpers try access global
variables.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
f25f0d7751 tcg/mips: use TCGArg or TCGReg instead of int
Instead of int, use the correct TCGArg and TCGReg type: TCGReg when
representing a TCG target register, TCGArg when representing the latter
or a constant.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
b7505cfd52 tcg/mips: kill warnings in user mode
Recent versions of GCC emit warnings when compiling user mode targets.
Kill them by reordering a bit the #ifdef.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
df3e097e21 tcg-mips: fix wrong usage of 'Z' constraint
The 'Z' constraint has been introduced to map the zero register. However
when the op also accept a constant, there is no point to accept the zero
register in addition.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Richard Henderson
707eee12fd tcg-hppa: Fix broken load/store helpers
The CONFIG_TCG_PASS_AREG0 code for calling ld/st helpers
was not respecting the ABI requirement for 64-bit values
being aligned in registers.

Mirror the ARM port in use of helper functions to marshal
arguments into the correct registers.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Richard Henderson
fb1d48edb6 tcg-hppa: Fix brcond2 and setcond2
Neither of these functions were performing double-word
compares properly.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Richard Henderson
4c8f62d388 tcg: Fix !USE_DIRECT_JUMP
Commit 6375e09e changed the type of TranslationBlock.tb_next,
but failed to change the type of TCGContext.tb_next.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Reviewed-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Aurelien Jarno
15658ad01b gdbstub/sh4: fix build with USE_SOFTFLOAT_STRUCT_TYPES
We have to use different type to access float values when
USE_SOFTFLOAT_STRUCT_TYPES is defined.

Rework SH4 version of cpu_gdb_{read,write}_register() using
a single case, and fixing the coding style. Use ldll_p() and
stfl_p() to access float values.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Richard Henderson
1d465a94ad tcg: Optimize two-address commutative operations
While swapping constants to the second operand, swap
sources matching destinations to the first operand.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Richard Henderson
b5b6bb16b9 tcg: Optimize movcond for constant comparisons
Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:09 -05:00
Richard Henderson
52080f688b tcg-i386: Implement movcond
Signed-off-by: Richard Henderson <rth@twiddle.net>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Richard Henderson
72bdbb7f46 target-alpha: Use movcond
For proper cmov insns, as well as the non-goto-tb case
of conditional branch.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Richard Henderson
6314cc0c73 tcg: Introduce movcond
Implemented with setcond if the target does not provide
the optional opcode.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Max Filippov
cc10061717 target-xtensa: don't emit extra tcg_gen_goto_tb
Unconditional gen_check_loop_end at the end of disas_xtensa_insn
can emit tcg_gen_goto_tb with slot id already used in the TB (e.g. when
TB ends at LEND with a branch).

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Cc: qemu-stable <qemu-stable@nongnu.org>
Signed-off-by: malc <av1474@comtv.ru>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Max Filippov
44219e7df2 target-xtensa: fix extui shift amount
extui opcode only uses lowermost op1 bit for sa4.

Reported-by: malc <av1474@comtv.ru>
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Cc: qemu-stable <qemu-stable@nongnu.org>
Signed-off-by: malc <av1474@comtv.ru>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Aurelien Jarno
5b681fffe4 tcg/optimize: fix end of basic block detection
Commit e31b0a7c05 fixed copy propagation on
32-bit host by restricting the copy between different types. This was the
wrong fix.

The real problem is that the all temps states should be reset at the end
of a basic block. This was done by adding such operations in the switch,
but brcond2 was forgotten (that's why the crash was only observed on 32-bit
hosts).

Fix that by looking at the TCG_OPF_BB_END instead. We need to keep the case
for op_set_label as temps might be modified through another path.

Cc: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Richard Henderson
447f11b945 target-mips: Always evaluate debugging macro arguments
this will prevent some of the compilation errors with debugging
enabled from creeping back in.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Richard Henderson
fe07dcf262 target-mips: Fix MIPS_DEBUG.
The macro uses the DisasContext.  Pass it around as needed.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Acked-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Richard Henderson
d25c2359de target-mips: Set opn in gen_ldst_multiple.
Used by MIPS_DEBUG, when enabled.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Acked-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Aurelien Jarno
4f17bc1e89 revert "TCG: fix copy propagation"
Given the copy propagation breakage on 32-bit hosts has been fixed
commit e31b0a7c05 can be reverted.

Cc: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Aurelien Jarno
d39d648846 tcg: mark set_label with TCG_OPF_BB_END flag
set_label is effectively the end of a basic block, as no optimization
can be made accross it. It was treated as such in the liveness analysis
code, but as a special case.

Mark it with TCG_OPF_BB_END flag so that this information can be used
by other parts of the TCG code, and remove the special case in the liveness
analysis code.

Cc: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Aurelien Jarno
ea15fd7c1a tcg/i386: allow constants in load/store ops
On x86, it is possible to move a constant value to memory. Add code to
handle a constant argument to load/store ops.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Blue Swirl
a0969d7a46 Remove unused CONFIG_TCG_PASS_AREG0 and dead code
Now that CONFIG_TCG_PASS_AREG0 is enabled for all targets,
remove dead code and support for !CONFIG_TCG_PASS_AREG0 case.

Remove dyngen-exec.h and all references to it. Although included by
hw/spapr_hcall.c, it does not seem to use it.

Remove unused HELPER_CFLAGS.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Blue Swirl
0c4b3c0198 target-mips: switch to AREG0 free mode
Add an explicit CPUState parameter instead of relying on AREG0
and switch to AREG0 free mode.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Acked-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Blue Swirl
ca75e56821 target-sh4: switch to AREG0 free mode
Add an explicit CPUState parameter instead of relying on AREG0
and switch to AREG0 free mode.

Acked-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Aurelien Jarno
c383331e9d target-cris: Switch to AREG0 free mode
Add an explicit CPUCRISState parameter instead of relying on AREG0, and
use cpu_ld* in translation and interrupt handling. Remove AREG0 swapping
in tlb_fill(). Switch to AREG0 free mode

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:08 -05:00
Aurelien Jarno
d36ae16dd4 target-cris: Avoid AREG0 for helpers
Add an explicit CPUCRISState parameter instead of relying on AREG0.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Blue Swirl
c9b89e8224 target-microblaze: switch to AREG0 free mode
Add an explicit CPUState parameter instead of relying on AREG0
and switch to AREG0 free mode.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Blue Swirl
40b1f8a804 target-arm: final conversion to AREG0 free mode
Convert code load functions and switch to AREG0 free mode.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Blue Swirl
883864650e target-arm: convert remaining helpers
Convert remaining helpers to AREG0 free mode: add an explicit
CPUState parameter instead of relying on AREG0.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Blue Swirl
6178b83f35 target-arm: convert void helpers
Add an explicit CPUState parameter instead of relying on AREG0.

For easier review, convert only op helpers which don't return any value.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Blue Swirl
af411212ce target-unicore32: switch to AREG0 free mode
Add an explicit CPUState parameter instead of relying on AREG0
and switch to AREG0 free mode.

Tested-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Blue Swirl
e67d4921fd target-m68k: avoid using cpu_single_env
Pass around CPUState instead of using global cpu_single_env.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Blue Swirl
3654ef451e target-m68k: switch to AREG0 free mode
Add an explicit CPUState parameter instead of relying on AREG0
and switch to AREG0 free mode.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Blue Swirl
7a5311f64f target-lm32: switch to AREG0 free mode
Add an explicit CPUState parameter instead of relying on AREG0
and switch to AREG0 free mode.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Blue Swirl
1ada516f0e target-s390x: avoid cpu_single_env
Pass around CPUState instead of using global cpu_single_env.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Aurelien Jarno
578c758200 tcg/optimize: fix if/else/break coding style
optimizer.c contains some cases were the break is appearing in both the
if and the else parts. Fix that by moving it to the outer part. Also
move some common code there.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Aurelien Jarno
97c012c76a tcg/optimize: add constant folding for brcond
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Aurelien Jarno
2108a786ba tcg/optimize: add constant folding for setcond
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Aurelien Jarno
decddd9021 tcg/optimize: swap brcond/setcond arguments when possible
brcond and setcond ops are not commutative, but it's easy to compute the
new condition after swapping the arguments. Try to always put the constant
argument in second position like for commutative ops, to help backends to
generate better code.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Aurelien Jarno
52173babad tcg/optimize: simplify shift/rot r, 0, a => movi r, 0 cases
shift/rot r, 0, a is equivalent to movi r, 0.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Aurelien Jarno
f66f1dab29 tcg/optimize: simplify and r, a, 0 cases
and r, a, 0 is equivalent to a movi r, 0.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Aurelien Jarno
6c9785fb4b tcg/optimize: simplify or/xor r, a, 0 cases
or/xor r, a, 0 is equivalent to a mov r, a.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Aurelien Jarno
d969307261 tcg/optimize: split expression simplification
Split expression simplification in multiple parts so that a given op
can appear multiple times. This patch should not change anything.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:07 -05:00
Stefan Weil
62cdb0fdd3 target-arm: Fix potential buffer overflow
Report from smatch:

target-arm/helper.c:651 arm946_prbs_read(6) error:
 buffer overflow 'env->cp15.c6_region' 8 <= 8
target-arm/helper.c:661 arm946_prbs_write(6) error:
 buffer overflow 'env->cp15.c6_region' 8 <= 8

c7_region is an array with 8 elements, so the index must be less than 8.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Aurelien Jarno
3bc7da7cd7 tcg/s390: fix ld/st with CONFIG_TCG_PASS_AREG0
The load/store slow path has been broken in e141ab52d:
- We need to move 4 registers for store functions and 3 registers for
  load functions and not the reverse.
- According to the s390x calling convention the arguments of a function
  should be zero extended. This means that the register shift should be
  done with TCG_TYPE_I64 to ensure the higher word is correctly zero
  extended when needed.

I am aware that CONFIG_TCG_PASS_AREG0 is being removed and thus that
this patch can be improved, but doing so means it can also be applied to
the 1.1 and 1.2 stable branches.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Blue Swirl
265434460e target-s390x: switch to AREG0 free mode
Add an explicit CPUState parameter instead of relying on AREG0.

Remove temporary wrappers and switch to AREG0 free mode.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
[agraf: fix conflicts]
Signed-off-by: Alexander Graf <agraf@suse.de>

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Blue Swirl
71742e6c68 target-s390x: avoid AREG0 for misc helpers
Make misc helpers take a parameter for CPUState instead
of relying on global env.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
[agraf: fix conflict]
Signed-off-by: Alexander Graf <agraf@suse.de>

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Blue Swirl
719a60ddb3 target-s390x: avoid AREG0 for condition code helpers
Make condition code helpers take a parameter for CPUState instead
of relying on global env.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Blue Swirl
1f983b49f7 target-s390x: avoid AREG0 for integer helpers
Make integer helpers take a parameter for CPUState instead
of relying on global env.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Blue Swirl
313e38b4a1 target-s390x: avoid AREG0 for FPU helpers
Make FPU helpers take a parameter for CPUState instead
of relying on global env.

Introduce temporary wrappers for FPU load and store ops.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Blue Swirl
1a392c8957 target-s390x: rename op_helper.c to misc_helper.c
Now op_helper.c contains miscellaneous helpers, rename
it to misc_helper.c.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
[agraf: fix conflict]
Signed-off-by: Alexander Graf <agraf@suse.de>

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Blue Swirl
84dde20eea target-s390x: split memory access helpers
Move memory access helpers to mem_helper.c.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
[agraf: fold softmmu include ifdefs together]
Signed-off-by: Alexander Graf <agraf@suse.de>

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Blue Swirl
7dc581be44 target-s390x: split integer helpers
Move integer helpers to int_helper.c.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Blue Swirl
f7c50726dd target-s390x: split condition code helpers
Move condition code helpers to cc_helper.c.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Blue Swirl
4bae8a0a90 target-s390x: split FPU ops
Move floating point instructions to fpu_helper.c.

While exporting some condition code helpers,
avoid duplicate identifier conflict with translate.c.

Remove unused set_cc_nz_f64() in translate.c.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Blue Swirl
b05900a761 target-s390x: fix style
Before splitting op_helper.c and helper.c in the next patches,
fix style issues. No functional changes.

Replace also GCC specific __FUNCTION__ with
standard __func__.

Don't init static variable (cpu_s390x_init:inited) with 0.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Aurelien Jarno
b16148e1c6 target-sparc: fix fcmp{s,d,q} instructions wrt exception
fcmp{s,d,q} instructions are supposed to ignore quiet NaN (contrary to
the fcmpe{s,d,q} instructions), but the current code is wrongly setting
the NV exception in that case. Moreover the current code is duplicated:
first the arguments are checked for NaN to generate an exception, and
later in case the comparison is unordered (which can only happens if one
of the argument is a NaN), the same check is done to generate an
exception.

Fix that by calling clear_float_exceptions() followed by
check_ieee_exceptions() as for the other floating point instructions.
Use the _compare_quiet functions for fcmp{s,d,q} and the _compare ones
for fcmpe{s,d,q}. Simplify the flag setting by not clearing a flag that
is set the line just below.

This fix allows the math glibc testsuite to pass.

Cc: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Max Filippov
dafd8866be target-xtensa: fix missing errno codes for mingw32
Put the following errno value mappings under #ifdef:

xtensa-semi.c: In function 'errno_h2g':
xtensa-semi.c:113: error: 'ENOTBLK' undeclared (first use in this function)
xtensa-semi.c:113: error: (Each undeclared identifier is reported only once
xtensa-semi.c:113: error: for each function it appears in.)
xtensa-semi.c:113: error: array index in initializer not of integer type
xtensa-semi.c:113: error: (near initialization for 'guest_errno')
xtensa-semi.c:124: error: 'ETXTBSY' undeclared (first use in this function)
xtensa-semi.c:124: error: array index in initializer not of integer type
xtensa-semi.c:124: error: (near initialization for 'guest_errno')
xtensa-semi.c:134: error: 'ELOOP' undeclared (first use in this function)
xtensa-semi.c:134: error: array index in initializer not of integer type
xtensa-semi.c:134: error: (near initialization for 'guest_errno')

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Stefan Weil
631287933e target-cris: Fix buffer overflow
Report from smatch:

target-cris/translate.c:3464 cpu_dump_state(32) error:
 buffer overflow 'env->sregs' 4 <= 255

sregs is declared 'uint32_t sregs[4][16]', so the first index must be
less than 4 or ARRAY_SIZE(env->sregs).

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
Max Filippov
814395979e target-xtensa: convert host errno values to guest
Guest errno values are taken from the newlib. Convert only those errno
values that can be returned from used system calls.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2012-10-09 01:42:06 -05:00
2043 changed files with 46766 additions and 128635 deletions

7
.exrc
View File

@@ -1,7 +0,0 @@
"VIM settings to match QEMU coding style. They are activated by adding the
"following settings (without the " symbol) as last two lines in $HOME/.vimrc:
"set secure
"set exrc
set expandtab
set shiftwidth=4
set smarttab

14
.gitignore vendored
View File

@@ -1,19 +1,19 @@
config-devices.*
config-all-devices.*
config-all-disas.*
config-host.*
config-target.*
trace/generated-tracers.h
trace/generated-tracers.c
trace/generated-tracers-dtrace.h
trace/generated-tracers-dtrace.dtrace
libcacard/trace/generated-tracers.c
trace.h
trace.c
trace-dtrace.h
trace-dtrace.dtrace
*-timestamp
*-softmmu
*-darwin-user
*-linux-user
*-bsd-user
libdis*
libhw32
libhw64
libuser
linux-headers/asm
qapi-generated
@@ -49,7 +49,6 @@ test-qmp-output-visitor
test-string-input-visitor
test-string-output-visitor
test-visitor-serialization
fsdev/virtfs-proxy-helper
fsdev/virtfs-proxy-helper.1
fsdev/virtfs-proxy-helper.pod
.gdbinit
@@ -71,7 +70,6 @@ fsdev/virtfs-proxy-helper.pod
*.tp
*.vr
*.d
!scripts/qemu-guest-agent/fsfreeze-hook.d
*.o
*.lo
*.la

3
.gitmodules vendored
View File

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

31
HACKING
View File

@@ -32,7 +32,7 @@ mandatory for VMState fields.
Don't use Linux kernel internal types like u32, __u32 or __le32.
Use hwaddr for guest physical addresses except pcibus_t
Use target_phys_addr_t for guest physical addresses except pcibus_t
for PCI addresses. In addition, ram_addr_t is a QEMU internal address
space that maps guest RAM physical addresses into an intermediate
address space that can map to host virtual address spaces. Generally
@@ -91,11 +91,10 @@ emulators.
4. String manipulation
Do not use the strncpy function. As mentioned in the man page, it does *not*
guarantee a NULL-terminated buffer, which makes it extremely dangerous to use.
It also zeros trailing destination bytes out to the specified length. Instead,
use this similar function when possible, but note its different signature:
void pstrcpy(char *dest, int dest_buf_size, const char *src)
Do not use the strncpy function. According to the man page, it does
*not* guarantee a NULL-terminated buffer, which makes it extremely dangerous
to use. Instead, use functionally equivalent function:
void pstrcpy(char *buf, int buf_size, const char *str)
Don't use strcat because it can't check for buffer overflows, but:
char *pstrcat(char *buf, int buf_size, const char *s)
@@ -123,23 +122,3 @@ gcc's printf attribute directive in the prototype.
This makes it so gcc's -Wformat and -Wformat-security options can do
their jobs and cross-check format strings with the number and types
of arguments.
6. C standard, implementation defined and undefined behaviors
C code in QEMU should be written to the C99 language specification. A copy
of the final version of the C99 standard with corrigenda TC1, TC2, and TC3
included, formatted as a draft, can be downloaded from:
http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf
The C language specification defines regions of undefined behavior and
implementation defined behavior (to give compiler authors enough leeway to
produce better code). In general, code in QEMU should follow the language
specification and avoid both undefined and implementation defined
constructs. ("It works fine on the gcc I tested it with" is not a valid
argument...) However there are a few areas where we allow ourselves to
assume certain behaviors because in practice all the platforms we care about
behave in the same way and writing strictly conformant code would be
painful. These are:
* you may assume that integers are 2s complement representation
* you may assume that right shift of a signed integer duplicates
the sign bit (ie it is an arithmetic shift, not a logical shift)

View File

@@ -98,7 +98,6 @@ S: Maintained
F: target-ppc/
S390
M: Richard Henderson <rth@twiddle.net>
M: Alexander Graf <agraf@suse.de>
S: Maintained
F: target-s390x/
@@ -133,7 +132,7 @@ Guest CPU Cores (KVM):
----------------------
Overall
M: Gleb Natapov <gleb@redhat.com>
M: Avi Kivity <avi@redhat.com>
M: Marcelo Tosatti <mtosatti@redhat.com>
L: kvm@vger.kernel.org
S: Supported
@@ -151,7 +150,7 @@ S: Maintained
F: target-s390x/kvm.c
X86
M: Gleb Natapov <gleb@redhat.com>
M: Avi Kivity <avi@redhat.com>
M: Marcelo Tosatti <mtosatti@redhat.com>
L: kvm@vger.kernel.org
S: Supported
@@ -269,7 +268,6 @@ S: Maintained
F: hw/xilinx_zynq.c
F: hw/zynq_slcr.c
F: hw/cadence_*
F: hw/xilinx_spips.c
CRIS Machines
-------------
@@ -351,36 +349,14 @@ PowerPC Machines
405
M: Alexander Graf <agraf@suse.de>
L: qemu-ppc@nongnu.org
S: Odd Fixes
S: Maintained
F: hw/ppc405_boards.c
Bamboo
M: Alexander Graf <agraf@suse.de>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc440_bamboo.c
e500
M: Alexander Graf <agraf@suse.de>
M: Scott Wood <scottwood@freescale.com>
L: qemu-ppc@nongnu.org
S: Supported
F: hw/ppc/e500.[hc]
F: hw/ppc/e500plat.c
mpc8544ds
M: Alexander Graf <agraf@suse.de>
M: Scott Wood <scottwood@freescale.com>
L: qemu-ppc@nongnu.org
S: Supported
F: hw/ppc/mpc8544ds.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/ppc_newworld.c
F: hw/unin_pci.c
F: hw/dec_pci.[hc]
@@ -388,29 +364,15 @@ Old World
M: Alexander Graf <agraf@suse.de>
L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc/mac_oldworld.c
F: hw/ppc_oldworld.c
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/ppc_prep.c
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*
virtex_ml507
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/virtex_ml507.c
SH4 Machines
------------
@@ -492,23 +454,9 @@ F: hw/omap*
PCI
M: Michael S. Tsirkin <mst@redhat.com>
S: Supported
F: hw/pci/*
F: hw/pci*
F: hw/piix*
ppc4xx
M: Alexander Graf <agraf@suse.de>
L: qemu-ppc@nongnu.org
S: Odd Fixes
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/ppce500_*
SCSI
M: Paolo Bonzini <pbonzini@redhat.com>
S: Supported
@@ -521,22 +469,11 @@ M: Paul Brook <paul@codesourcery.com>
S: Odd Fixes
F: hw/lsi53c895a.c
SSI
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
S: Maintained
F: hw/ssi.*
F: hw/m25p80.c
USB
M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained
F: hw/usb*
VFIO
M: Alex Williamson <alex.williamson@redhat.com>
S: Supported
F: hw/vfio*
vhost
M: Michael S. Tsirkin <mst@redhat.com>
S: Supported
@@ -556,7 +493,6 @@ T: git git://github.com/kvaneesh/QEMU.git
virtio-blk
M: Kevin Wolf <kwolf@redhat.com>
M: Stefan Hajnoczi <stefanha@redhat.com>
S: Supported
F: hw/virtio-blk*
@@ -576,7 +512,6 @@ 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
----------
@@ -587,7 +522,6 @@ F: audio/
Block
M: Kevin Wolf <kwolf@redhat.com>
M: Stefan Hajnoczi <stefanha@redhat.com>
S: Supported
F: block*
F: block/
@@ -602,7 +536,6 @@ M: Andreas Färber <afaerber@suse.de>
S: Supported
F: qom/cpu.c
F: include/qemu/cpu.h
F: target-i386/cpu.c
Device Tree
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
@@ -647,7 +580,7 @@ F: monitor.c
Network device layer
M: Anthony Liguori <aliguori@us.ibm.com>
M: Stefan Hajnoczi <stefanha@redhat.com>
M: Stefan Hajnoczi <stefanha@gmail.com>
S: Maintained
F: net/
T: git git://github.com/stefanha/qemu.git net
@@ -667,7 +600,7 @@ F: slirp/
T: git git://git.kiszka.org/qemu.git queues/slirp
Tracing
M: Stefan Hajnoczi <stefanha@redhat.com>
M: Stefan Hajnoczi <stefanha@gmail.com>
S: Maintained
F: trace/
F: scripts/tracetool.py

132
Makefile
View File

@@ -8,38 +8,22 @@ ifneq ($(wildcard config-host.mak),)
# Put the all: rule here so that config-host.mak can contain dependencies.
all:
include config-host.mak
# Check that we're not trying to do an out-of-tree build from
# a tree that's been used for an in-tree build.
ifneq ($(realpath $(SRC_PATH)),$(realpath .))
ifneq ($(wildcard $(SRC_PATH)/config-host.mak),)
$(error This is an out of tree build but your source tree ($(SRC_PATH)) \
seems to have been used for an in-tree build. You can fix this by running \
"make distclean && rm -rf *-linux-user *-softmmu" in your source tree)
endif
endif
include $(SRC_PATH)/rules.mak
config-host.mak: $(SRC_PATH)/configure
@echo $@ is out-of-date, running configure
@sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh
else
config-host.mak:
ifneq ($(filter-out %clean,$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail))
@echo "Please call configure before running make!"
@exit 1
endif
endif
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-tracers.h
GENERATED_HEADERS = config-host.h trace.h qemu-options.def
ifeq ($(TRACE_BACKEND),dtrace)
GENERATED_HEADERS += trace/generated-tracers-dtrace.h
GENERATED_HEADERS += trace-dtrace.h
endif
GENERATED_SOURCES += trace/generated-tracers.c
GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h
GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c trace.c
# Don't try to regenerate Makefile or configure
# We don't generate any of them
@@ -102,18 +86,6 @@ 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
endif
ifeq ($(CONFIG_SMARTCARD_NSS),y)
include $(SRC_PATH)/libcacard/Makefile
endif
all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all
@@ -127,16 +99,15 @@ SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
subdir-%:
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
subdir-pixman: pixman/Makefile
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C pixman V="$(V)" all,)
ifneq ($(wildcard config-host.mak),)
include $(SRC_PATH)/Makefile.objs
endif
pixman/Makefile: $(SRC_PATH)/pixman/configure
(cd pixman; CFLAGS="$(CFLAGS) -fPIC $(extra_cflags) $(extra_ldflags)" $(SRC_PATH)/pixman/configure $(AUTOCONF_HOST) --disable-gtk --disable-shared --enable-static)
subdir-libcacard: $(oslib-obj-y) $(trace-obj-y) qemu-timer-common.o
$(SRC_PATH)/pixman/configure:
(cd $(SRC_PATH)/pixman; autoreconf -v --install)
$(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(common-obj-y) $(extra-obj-y) subdir-libdis
$(SUBDIR_RULES): libqemuutil.a libqemustub.a $(common-obj-y)
$(filter %-user,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) subdir-libdis-user subdir-libuser
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
romsubdir-%:
@@ -146,31 +117,61 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
QEMU_CFLAGS+=$(CURL_CFLAGS)
QEMU_CFLAGS += -I$(SRC_PATH)/include
ui/cocoa.o: ui/cocoa.m
ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o hw/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
version.o: $(SRC_PATH)/version.rc config-host.h
$(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@")
version-obj-$(CONFIG_WIN32) += version.o
Makefile: $(version-obj-y)
######################################################################
# Build libraries
# Support building shared library libcacard
libqemustub.a: $(stub-obj-y)
libqemuutil.a: $(util-obj-y)
.PHONY: libcacard.la install-libcacard
ifeq ($(LIBTOOL),)
libcacard.la:
@echo "libtool is missing, please install and rerun configure"; exit 1
install-libcacard:
@echo "libtool is missing, please install and rerun configure"; exit 1
else
libcacard.la: $(oslib-obj-y) qemu-timer-common.o $(addsuffix .lo, $(basename $(trace-obj-y)))
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" libcacard.la,)
install-libcacard: libcacard.la
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" install-libcacard,)
endif
######################################################################
qemu-img.o: qemu-img-cmds.h
qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a
qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a
qemu-io$(EXESUF): qemu-io.o cmd.o $(block-obj-y) libqemuutil.a libqemustub.a
tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
qemu-timer-common.o main-loop.o notify.o \
iohandler.o cutils.o iov.o async.o
tools-obj-$(CONFIG_POSIX) += compatfd.o
qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o libqemuutil.a libqemustub.a
vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) $(tools-obj-y) qemu-timer-common.o libcacard/vscclient.o
$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(libcacard_libs) $(LIBS)," LINK $@")
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
@@ -181,16 +182,20 @@ qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated
gen-out-type = $(subst .,-,$(suffix $@))
ifneq ($(wildcard config-host.mak),)
include $(SRC_PATH)/tests/Makefile
endif
qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
qapi-types.c qapi-types.h :\
@@ -206,27 +211,27 @@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
qemu-ga$(EXESUF): $(qga-obj-y) libqemuutil.a libqemustub.a
$(call LINK, $^)
qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(tools-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y)
QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
clean:
# avoid old build problems by removing potentially incorrect old files
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
rm -f qemu-options.def
find . -name '*.[oda]' -type f -exec rm -f {} +
find . -name '*.l[oa]' -type f -exec rm -f {} +
rm -f $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
find . -name '*.[od]' -exec rm -f {} +
rm -f *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
rm -Rf .libs
rm -f qemu-img-cmds.h
rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
@# May not be present in GENERATED_HEADERS
rm -f trace/generated-tracers-dtrace.dtrace*
rm -f trace/generated-tracers-dtrace.h*
rm -f trace-dtrace.h trace-dtrace.h-timestamp
rm -f $(foreach f,$(GENERATED_HEADERS),$(f) $(f)-timestamp)
rm -f $(foreach f,$(GENERATED_SOURCES),$(f) $(f)-timestamp)
rm -rf qapi-generated
rm -rf qga/qapi-generated
$(MAKE) -C tests/tcg clean
for d in $(ALL_SUBDIRS); do \
for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
rm -f $$d/qemu-options.def; \
done
@@ -240,7 +245,7 @@ qemu-%.tar.bz2:
distclean: clean
rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi
rm -f config-all-devices.mak config-all-disas.mak
rm -f config-all-devices.mak
rm -f roms/seabios/config.mak roms/vgabios/config.mak
rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.cps qemu-doc.dvi
rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
@@ -249,10 +254,9 @@ distclean: clean
rm -f config.log
rm -f linux-headers/asm
rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
for d in $(TARGET_DIRS); do \
for d in $(TARGET_DIRS) $(QEMULIBS); do \
rm -rf $$d || exit 1 ; \
done
if test -f pixman/config.log; then make -C pixman distclean; 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 \
@@ -262,7 +266,6 @@ bepo
ifdef INSTALL_BLOBS
BLOBS=bios.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
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 \
@@ -299,6 +302,7 @@ install-confdir:
install-sysconfig: install-datadir install-confdir
$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)"
$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/cpus-x86_64.conf "$(DESTDIR)$(qemu_datadir)"
install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig install-datadir
$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
@@ -399,9 +403,7 @@ qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
# Add a dependency on the generated files, so that they are always
# rebuilt before other object files
ifneq ($(filter-out %clean,$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail))
Makefile: $(GENERATED_HEADERS)
endif
# Include automatically generated dependency files
# Dependencies in Makefile.objs files come from our recursive subdir rules

20
Makefile.dis Normal file
View File

@@ -0,0 +1,20 @@
# Makefile for disassemblers.
include ../config-host.mak
include config.mak
include $(SRC_PATH)/rules.mak
.PHONY: all
$(call set-vpath, $(SRC_PATH))
QEMU_CFLAGS+=-I..
include $(SRC_PATH)/Makefile.objs
all: $(libdis-y)
# Dummy command so that make thinks it has done something
@true
clean:
rm -f *.o *.d *.a *~

23
Makefile.hw Normal file
View File

@@ -0,0 +1,23 @@
# Makefile for qemu target independent devices.
include ../config-host.mak
include ../config-all-devices.mak
include config.mak
include $(SRC_PATH)/rules.mak
.PHONY: all
$(call set-vpath, $(SRC_PATH))
QEMU_CFLAGS+=-I..
QEMU_CFLAGS += -I$(SRC_PATH)/include
include $(SRC_PATH)/Makefile.objs
all: $(hw-obj-y)
# Dummy command so that make thinks it has done something
@true
clean:
rm -f $(addsuffix *.o, $(sort $(dir $(hw-obj-y))))
rm -f $(addsuffix *.d, $(sort $(dir $(hw-obj-y))))

View File

@@ -1,31 +1,52 @@
#######################################################################
# Common libraries for tools and emulators
stub-obj-y = stubs/
util-obj-y = util/ qobject/ qapi/ trace/
# Target-independent parts used in system and user emulation
universal-obj-y =
universal-obj-y += qemu-log.o
#######################################################################
# QObject
qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
qobject-obj-y += qerror.o error.o qemu-error.o
universal-obj-y += $(qobject-obj-y)
#######################################################################
# QOM
qom-obj-y = qom/
universal-obj-y += $(qom-obj-y)
#######################################################################
# oslib-obj-y is code depending on the OS (win32 vs posix)
oslib-obj-y = osdep.o
oslib-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o
oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
#######################################################################
# coroutines
coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
coroutine-obj-y += qemu-coroutine-sleep.o
ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
else
ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y)
coroutine-obj-$(CONFIG_POSIX) += coroutine-sigaltstack.o
else
coroutine-obj-$(CONFIG_POSIX) += coroutine-gthread.o
endif
endif
coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o
#######################################################################
# block-obj-y is code used by both qemu system emulation and qemu-img
block-obj-y = async.o thread-pool.o
block-obj-y += nbd.o block.o blockjob.o
block-obj-y += main-loop.o iohandler.o qemu-timer.o
block-obj-$(CONFIG_POSIX) += aio-posix.o
block-obj-$(CONFIG_WIN32) += aio-win32.o
block-obj-y = cutils.o iov.o cache-utils.o qemu-option.o module.o async.o
block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o
block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y)
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
block-obj-y += block/
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
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.
@@ -33,6 +54,155 @@ ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
CONFIG_REALLY_VIRTFS=y
endif
######################################################################
# Target independent part of system emulation. The long term path is to
# suppress *all* target specific code in case of system emulation, i.e. a
# single QEMU executable should support all CPUs and machines.
common-obj-y = $(block-obj-y) blockdev.o
common-obj-y += net.o net/
common-obj-y += qom/
common-obj-y += readline.o console.o cursor.o
common-obj-y += $(oslib-obj-y)
common-obj-$(CONFIG_WIN32) += os-win32.o
common-obj-$(CONFIG_POSIX) += os-posix.o
common-obj-$(CONFIG_LINUX) += fsdev/
extra-obj-$(CONFIG_LINUX) += fsdev/
common-obj-y += tcg-runtime.o host-utils.o main-loop.o
common-obj-y += input.o
common-obj-y += buffered_file.o migration.o migration-tcp.o
common-obj-y += qemu-char.o #aio.o
common-obj-y += block-migration.o iohandler.o
common-obj-y += pflib.o
common-obj-y += bitmap.o bitops.o
common-obj-y += page_cache.o
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
common-obj-$(CONFIG_WIN32) += version.o
common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
common-obj-y += audio/
common-obj-y += hw/
common-obj-y += ui/
common-obj-y += bt-host.o bt-vhci.o
common-obj-y += iov.o acl.o
common-obj-$(CONFIG_POSIX) += compatfd.o
common-obj-y += notify.o event_notifier.o
common-obj-y += qemu-timer.o qemu-timer-common.o
common-obj-$(CONFIG_SLIRP) += slirp/
######################################################################
# libseccomp
ifeq ($(CONFIG_SECCOMP),y)
common-obj-y += qemu-seccomp.o
endif
######################################################################
# libuser
user-obj-y =
user-obj-y += envlist.o path.o
user-obj-y += tcg-runtime.o host-utils.o
user-obj-y += cutils.o iov.o cache-utils.o
user-obj-y += module.o
user-obj-y += qemu-user.o
user-obj-y += $(trace-obj-y)
user-obj-y += qom/
######################################################################
# libhw
hw-obj-y = vl.o dma-helpers.o qtest.o hw/
######################################################################
# libdis
# NOTE: the disassembler code is only needed for debugging
libdis-y =
libdis-$(CONFIG_ALPHA_DIS) += alpha-dis.o
libdis-$(CONFIG_ARM_DIS) += arm-dis.o
libdis-$(CONFIG_CRIS_DIS) += cris-dis.o
libdis-$(CONFIG_HPPA_DIS) += hppa-dis.o
libdis-$(CONFIG_I386_DIS) += i386-dis.o
libdis-$(CONFIG_IA64_DIS) += ia64-dis.o
libdis-$(CONFIG_M68K_DIS) += m68k-dis.o
libdis-$(CONFIG_MICROBLAZE_DIS) += microblaze-dis.o
libdis-$(CONFIG_MIPS_DIS) += mips-dis.o
libdis-$(CONFIG_PPC_DIS) += ppc-dis.o
libdis-$(CONFIG_S390_DIS) += s390-dis.o
libdis-$(CONFIG_SH4_DIS) += sh4-dis.o
libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
libdis-$(CONFIG_LM32_DIS) += lm32-dis.o
######################################################################
# trace
ifeq ($(TRACE_BACKEND),dtrace)
TRACE_H_EXTRA_DEPS=trace-dtrace.h
endif
trace.h: trace.h-timestamp $(TRACE_H_EXTRA_DEPS)
trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
$(call quiet-command,$(TRACETOOL) \
--format=h \
--backend=$(TRACE_BACKEND) \
< $< > $@," GEN trace.h")
@cmp -s $@ trace.h || cp $@ trace.h
trace.c: trace.c-timestamp
trace.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
$(call quiet-command,$(TRACETOOL) \
--format=c \
--backend=$(TRACE_BACKEND) \
< $< > $@," GEN trace.c")
@cmp -s $@ trace.c || cp $@ trace.c
trace.o: trace.c $(GENERATED_HEADERS)
trace-dtrace.h: trace-dtrace.dtrace
$(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h")
# Normal practice is to name DTrace probe file with a '.d' extension
# but that gets picked up by QEMU's Makefile as an external dependency
# rule file. So we use '.dtrace' instead
trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
$(call quiet-command,$(TRACETOOL) \
--format=d \
--backend=$(TRACE_BACKEND) \
< $< > $@," GEN trace-dtrace.dtrace")
@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
$(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o")
ifeq ($(LIBTOOL),)
trace-dtrace.lo: trace-dtrace.dtrace
@echo "missing libtool. please install and rerun configure."; exit 1
else
trace-dtrace.lo: trace-dtrace.dtrace
$(call quiet-command,$(LIBTOOL) --mode=compile --tag=CC dtrace -o $@ -G -s $<, " lt GEN trace-dtrace.o")
endif
trace/simple.o: trace/simple.c $(GENERATED_HEADERS)
trace-obj-$(CONFIG_TRACE_DTRACE) += trace-dtrace.o
ifneq ($(TRACE_BACKEND),dtrace)
trace-obj-y = trace.o
endif
trace-obj-$(CONFIG_TRACE_DEFAULT) += trace/default.o
trace-obj-$(CONFIG_TRACE_SIMPLE) += trace/simple.o
trace-obj-$(CONFIG_TRACE_SIMPLE) += qemu-timer-common.o
trace-obj-$(CONFIG_TRACE_STDERR) += trace/stderr.o
trace-obj-y += trace/control.o
$(trace-obj-y): $(GENERATED_HEADERS)
######################################################################
# smartcard
@@ -42,68 +212,25 @@ libcacard-y += libcacard/vcard_emul_nss.o
libcacard-y += libcacard/vcard_emul_type.o
libcacard-y += libcacard/card_7816.o
######################################################################
# Target independent part of system emulation. The long term path is to
# suppress *all* target specific code in case of system emulation, i.e. a
# single QEMU executable should support all CPUs and machines.
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-$(CONFIG_WIN32) += os-win32.o
common-obj-$(CONFIG_POSIX) += os-posix.o
common-obj-$(CONFIG_LINUX) += fsdev/
common-obj-y += migration.o migration-tcp.o
common-obj-y += qemu-char.o #aio.o
common-obj-y += block-migration.o
common-obj-y += page_cache.o xbzrle.o
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
common-obj-y += audio/
common-obj-y += hw/
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-$(CONFIG_SLIRP) += slirp/
common-obj-y += backends/
common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o
common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y)
######################################################################
# qapi
qapi-obj-y = qapi/
qapi-obj-y += qapi-types.o qapi-visit.o
common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o
common-obj-y += qmp.o hmp.o
endif
#######################################################################
# Target-independent parts used in system and user emulation
common-obj-y += qemu-log.o
common-obj-y += tcg-runtime.o
common-obj-y += hw/
common-obj-y += qom/
common-obj-y += disas/
universal-obj-y += $(qapi-obj-y)
######################################################################
# guest agent
# FIXME: a few definitions from qapi-types.o/qapi-visit.o are needed
# by libqemuutil.a. These should be moved to a separate .json schema.
qga-obj-y = qga/ qapi-types.o qapi-visit.o
qga-obj-y = qga/ qemu-ga.o module.o
qga-obj-$(CONFIG_WIN32) += oslib-win32.o
qga-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-sockets.o qemu-option.o
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
@@ -112,9 +239,12 @@ vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
QEMU_CFLAGS+=$(GLIB_CFLAGS)
nested-vars += \
stub-obj-y \
util-obj-y \
hw-obj-y \
qga-obj-y \
block-obj-y \
common-obj-y
qom-obj-y \
qapi-obj-y \
user-obj-y \
common-obj-y \
extra-obj-y
dummy := $(call unnest-vars)

View File

@@ -4,6 +4,9 @@ include ../config-host.mak
include config-devices.mak
include config-target.mak
include $(SRC_PATH)/rules.mak
ifneq ($(HWDIR),)
include $(HWDIR)/config.mak
endif
$(call set-vpath, $(SRC_PATH))
ifdef CONFIG_LINUX
@@ -54,7 +57,7 @@ $(QEMU_PROG).stp: $(SRC_PATH)/trace-events
--binary=$(bindir)/$(QEMU_PROG) \
--target-arch=$(TARGET_ARCH) \
--target-type=$(TARGET_TYPE) \
< $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG).stp")
< $< > $@," GEN $(QEMU_PROG).stp")
else
stap:
endif
@@ -69,12 +72,14 @@ all: $(PROGS) stap
obj-y = exec.o translate-all.o cpu-exec.o
obj-y += tcg/tcg.o tcg/optimize.o
obj-$(CONFIG_TCG_INTERPRETER) += tci.o
obj-$(CONFIG_TCG_INTERPRETER) += disas/tci.o
obj-y += fpu/softfloat.o
obj-y += target-$(TARGET_BASE_ARCH)/
obj-y += disas.o
obj-$(CONFIG_TCI_DIS) += tci-dis.o
obj-y += target-$(TARGET_BASE_ARCH)/
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
tci-dis.o: QEMU_CFLAGS += -I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/tci
#########################################################
# Linux user emulator target
@@ -83,7 +88,7 @@ ifdef CONFIG_LINUX_USER
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user
obj-y += linux-user/
obj-y += gdbstub.o thunk.o user-exec.o
obj-y += gdbstub.o thunk.o user-exec.o $(oslib-obj-y)
endif #CONFIG_LINUX_USER
@@ -95,7 +100,7 @@ ifdef CONFIG_BSD_USER
QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH)
obj-y += bsd-user/
obj-y += gdbstub.o user-exec.o
obj-y += gdbstub.o user-exec.o $(oslib-obj-y)
endif #CONFIG_BSD_USER
@@ -119,6 +124,11 @@ obj-$(CONFIG_NO_GET_MEMORY_MAPPING) += memory_mapping-stub.o
obj-$(CONFIG_NO_CORE_DUMP) += dump-stub.o
LIBS+=-lz
QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
# xen support
obj-$(CONFIG_XEN) += xen-all.o xen-mapcache.o
obj-$(CONFIG_NO_XEN) += xen-stub.o
@@ -136,25 +146,32 @@ GENERATED_HEADERS += hmp-commands.h qmp-commands-old.h
endif # CONFIG_SOFTMMU
# Workaround for http://gcc.gnu.org/PR55489, see configure.
%/translate.o: QEMU_CFLAGS += $(TRANSLATE_OPT_CFLAGS)
nested-vars += obj-y
# This resolves all nested paths, so it must come last
include $(SRC_PATH)/Makefile.objs
all-obj-y = $(obj-y)
all-obj-y += $(addprefix ../, $(universal-obj-y))
ifdef CONFIG_SOFTMMU
all-obj-y += $(addprefix ../, $(common-obj-y))
all-obj-y += $(addprefix ../libdis/, $(libdis-y))
all-obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
all-obj-y += $(addprefix ../, $(trace-obj-y))
else
all-obj-y += $(addprefix ../libuser/, $(user-obj-y))
all-obj-y += $(addprefix ../libdis-user/, $(libdis-y))
endif #CONFIG_LINUX_USER
ifdef QEMU_PROGW
# The linker builds a windows executable. Make also a console executable.
$(QEMU_PROGW): $(all-obj-y) ../libqemuutil.a ../libqemustub.a
$(QEMU_PROGW): $(all-obj-y)
$(call LINK,$^)
$(QEMU_PROG): $(QEMU_PROGW)
$(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)")
else
$(QEMU_PROG): $(all-obj-y) ../libqemuutil.a ../libqemustub.a
$(QEMU_PROG): $(all-obj-y)
$(call LINK,$^)
endif

24
Makefile.user Normal file
View File

@@ -0,0 +1,24 @@
# Makefile for qemu target independent user files.
include ../config-host.mak
include $(SRC_PATH)/rules.mak
-include config.mak
.PHONY: all
$(call set-vpath, $(SRC_PATH))
QEMU_CFLAGS+=-I..
QEMU_CFLAGS += -I$(SRC_PATH)/include
QEMU_CFLAGS += -DCONFIG_USER_ONLY
include $(SRC_PATH)/Makefile.objs
all: $(user-obj-y)
# Dummy command so that make thinks it has done something
@true
clean:
for d in . trace; do \
rm -f $$d/*.o $$d/*.d $$d/*.a $$d/*~; \
done

View File

@@ -1,299 +0,0 @@
#!/usr/bin/python
# QEMU Guest Agent Client
#
# Copyright (C) 2012 Ryota Ozaki <ozaki.ryota@gmail.com>
#
# This work is licensed under the terms of the GNU GPL, version 2. See
# the COPYING file in the top-level directory.
#
# Usage:
#
# Start QEMU with:
#
# # qemu [...] -chardev socket,path=/tmp/qga.sock,server,nowait,id=qga0 \
# -device virtio-serial -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
#
# Run the script:
#
# $ qemu-ga-client --address=/tmp/qga.sock <command> [args...]
#
# or
#
# $ export QGA_CLIENT_ADDRESS=/tmp/qga.sock
# $ qemu-ga-client <command> [args...]
#
# For example:
#
# $ qemu-ga-client cat /etc/resolv.conf
# # Generated by NetworkManager
# nameserver 10.0.2.3
# $ qemu-ga-client fsfreeze status
# thawed
# $ qemu-ga-client fsfreeze freeze
# 2 filesystems frozen
#
# See also: http://wiki.qemu.org/Features/QAPI/GuestAgent
#
import base64
import random
import qmp
class QemuGuestAgent(qmp.QEMUMonitorProtocol):
def __getattr__(self, name):
def wrapper(**kwds):
return self.command('guest-' + name.replace('_', '-'), **kwds)
return wrapper
class QemuGuestAgentClient:
error = QemuGuestAgent.error
def __init__(self, address):
self.qga = QemuGuestAgent(address)
self.qga.connect(negotiate=False)
def sync(self, timeout=3):
# Avoid being blocked forever
if not self.ping(timeout):
raise EnvironmentError('Agent seems not alive')
uid = random.randint(0, (1 << 32) - 1)
while True:
ret = self.qga.sync(id=uid)
if isinstance(ret, int) and int(ret) == uid:
break
def __file_read_all(self, handle):
eof = False
data = ''
while not eof:
ret = self.qga.file_read(handle=handle, count=1024)
_data = base64.b64decode(ret['buf-b64'])
data += _data
eof = ret['eof']
return data
def read(self, path):
handle = self.qga.file_open(path=path)
try:
data = self.__file_read_all(handle)
finally:
self.qga.file_close(handle=handle)
return data
def info(self):
info = self.qga.info()
msgs = []
msgs.append('version: ' + info['version'])
msgs.append('supported_commands:')
enabled = [c['name'] for c in info['supported_commands'] if c['enabled']]
msgs.append('\tenabled: ' + ', '.join(enabled))
disabled = [c['name'] for c in info['supported_commands'] if not c['enabled']]
msgs.append('\tdisabled: ' + ', '.join(disabled))
return '\n'.join(msgs)
def __gen_ipv4_netmask(self, prefixlen):
mask = int('1' * prefixlen + '0' * (32 - prefixlen), 2)
return '.'.join([str(mask >> 24),
str((mask >> 16) & 0xff),
str((mask >> 8) & 0xff),
str(mask & 0xff)])
def ifconfig(self):
nifs = self.qga.network_get_interfaces()
msgs = []
for nif in nifs:
msgs.append(nif['name'] + ':')
if 'ip-addresses' in nif:
for ipaddr in nif['ip-addresses']:
if ipaddr['ip-address-type'] == 'ipv4':
addr = ipaddr['ip-address']
mask = self.__gen_ipv4_netmask(int(ipaddr['prefix']))
msgs.append("\tinet %s netmask %s" % (addr, mask))
elif ipaddr['ip-address-type'] == 'ipv6':
addr = ipaddr['ip-address']
prefix = ipaddr['prefix']
msgs.append("\tinet6 %s prefixlen %s" % (addr, prefix))
if nif['hardware-address'] != '00:00:00:00:00:00':
msgs.append("\tether " + nif['hardware-address'])
return '\n'.join(msgs)
def ping(self, timeout):
self.qga.settimeout(timeout)
try:
self.qga.ping()
except self.qga.timeout:
return False
return True
def fsfreeze(self, cmd):
if cmd not in ['status', 'freeze', 'thaw']:
raise StandardError('Invalid command: ' + cmd)
return getattr(self.qga, 'fsfreeze' + '_' + cmd)()
def fstrim(self, minimum=0):
return getattr(self.qga, 'fstrim')(minimum=minimum)
def suspend(self, mode):
if mode not in ['disk', 'ram', 'hybrid']:
raise StandardError('Invalid mode: ' + mode)
try:
getattr(self.qga, 'suspend' + '_' + mode)()
# On error exception will raise
except self.qga.timeout:
# On success command will timed out
return
def shutdown(self, mode='powerdown'):
if mode not in ['powerdown', 'halt', 'reboot']:
raise StandardError('Invalid mode: ' + mode)
try:
self.qga.shutdown(mode=mode)
except self.qga.timeout:
return
def _cmd_cat(client, args):
if len(args) != 1:
print('Invalid argument')
print('Usage: cat <file>')
sys.exit(1)
print(client.read(args[0]))
def _cmd_fsfreeze(client, args):
usage = 'Usage: fsfreeze status|freeze|thaw'
if len(args) != 1:
print('Invalid argument')
print(usage)
sys.exit(1)
if args[0] not in ['status', 'freeze', 'thaw']:
print('Invalid command: ' + args[0])
print(usage)
sys.exit(1)
cmd = args[0]
ret = client.fsfreeze(cmd)
if cmd == 'status':
print(ret)
elif cmd == 'freeze':
print("%d filesystems frozen" % ret)
else:
print("%d filesystems thawed" % ret)
def _cmd_fstrim(client, args):
if len(args) == 0:
minimum = 0
else:
minimum = int(args[0])
print(client.fstrim(minimum))
def _cmd_ifconfig(client, args):
print(client.ifconfig())
def _cmd_info(client, args):
print(client.info())
def _cmd_ping(client, args):
if len(args) == 0:
timeout = 3
else:
timeout = float(args[0])
alive = client.ping(timeout)
if not alive:
print("Not responded in %s sec" % args[0])
sys.exit(1)
def _cmd_suspend(client, args):
usage = 'Usage: suspend disk|ram|hybrid'
if len(args) != 1:
print('Less argument')
print(usage)
sys.exit(1)
if args[0] not in ['disk', 'ram', 'hybrid']:
print('Invalid command: ' + args[0])
print(usage)
sys.exit(1)
client.suspend(args[0])
def _cmd_shutdown(client, args):
client.shutdown()
_cmd_powerdown = _cmd_shutdown
def _cmd_halt(client, args):
client.shutdown('halt')
def _cmd_reboot(client, args):
client.shutdown('reboot')
commands = [m.replace('_cmd_', '') for m in dir() if '_cmd_' in m]
def main(address, cmd, args):
if not os.path.exists(address):
print('%s not found' % address)
sys.exit(1)
if cmd not in commands:
print('Invalid command: ' + cmd)
print('Available commands: ' + ', '.join(commands))
sys.exit(1)
try:
client = QemuGuestAgentClient(address)
except QemuGuestAgent.error, e:
import errno
print(e)
if e.errno == errno.ECONNREFUSED:
print('Hint: qemu is not running?')
sys.exit(1)
if cmd != 'ping':
client.sync()
globals()['_cmd_' + cmd](client, args)
if __name__ == '__main__':
import sys
import os
import optparse
address = os.environ['QGA_CLIENT_ADDRESS'] if 'QGA_CLIENT_ADDRESS' in os.environ else None
usage = "%prog [--address=<unix_path>|<ipv4_address>] <command> [args...]\n"
usage += '<command>: ' + ', '.join(commands)
parser = optparse.OptionParser(usage=usage)
parser.add_option('--address', action='store', type='string',
default=address, help='Specify a ip:port pair or a unix socket path')
options, args = parser.parse_args()
address = options.address
if address is None:
parser.error('address is not specified')
sys.exit(1)
if len(args) == 0:
parser.error('Less argument')
sys.exit(1)
main(address, args[0], args[1:])

View File

@@ -50,8 +50,7 @@ Emitted when a block job has been cancelled.
Data:
- "type": Job type (json-string; "stream" for image streaming
"commit" for block commit)
- "type": Job type ("stream" for image streaming, json-string)
- "device": Device name (json-string)
- "len": Maximum progress value (json-int)
- "offset": Current progress value (json-int)
@@ -74,8 +73,7 @@ Emitted when a block job has completed.
Data:
- "type": Job type (json-string; "stream" for image streaming
"commit" for block commit)
- "type": Job type ("stream" for image streaming, json-string)
- "device": Device name (json-string)
- "len": Maximum progress value (json-int)
- "offset": Current progress value (json-int)
@@ -96,46 +94,6 @@ Example:
"speed": 0 },
"timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
BLOCK_JOB_ERROR
---------------
Emitted when a block job encounters an error.
Data:
- "device": device name (json-string)
- "operation": I/O operation (json-string, "read" or "write")
- "action": action that has been taken, it's one of the following (json-string):
"ignore": error has been ignored, the job may fail later
"report": error will be reported and the job canceled
"stop": error caused job to be paused
Example:
{ "event": "BLOCK_JOB_ERROR",
"data": { "device": "ide0-hd1",
"operation": "write",
"action": "stop" },
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
BLOCK_JOB_READY
---------------
Emitted when a block job is ready to complete.
Data:
- "device": device name (json-string)
Example:
{ "event": "BLOCK_JOB_READY",
"data": { "device": "ide0-hd1" },
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
Note: The "ready to complete" status is always reset by a BLOCK_JOB_ERROR
event.
DEVICE_TRAY_MOVED
-----------------

View File

@@ -33,7 +33,6 @@
import qmp
import readline
import sys
import pprint
class QMPCompleter(list):
def complete(self, text, state):
@@ -53,11 +52,10 @@ class QMPShellBadPort(QMPShellError):
# TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and
# _execute_cmd()). Let's design a better one.
class QMPShell(qmp.QEMUMonitorProtocol):
def __init__(self, address, pp=None):
def __init__(self, address):
qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address))
self._greeting = None
self._completer = None
self._pp = pp
def __get_address(self, arg):
"""
@@ -116,11 +114,7 @@ class QMPShell(qmp.QEMUMonitorProtocol):
if resp is None:
print 'Disconnected'
return False
if self._pp is not None:
self._pp.pprint(resp)
else:
print resp
print resp
return True
def connect(self):
@@ -228,36 +222,22 @@ def die(msg):
def fail_cmdline(option=None):
if option:
sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option)
sys.stderr.write('qemu-shell [ -p ] [ -H ] < UNIX socket path> | < TCP address:port >\n')
sys.stderr.write('qemu-shell [ -H ] < UNIX socket path> | < TCP address:port >\n')
sys.exit(1)
def main():
addr = ''
qemu = None
hmp = False
pp = None
try:
for arg in sys.argv[1:]:
if arg == "-H":
if qemu is not None:
fail_cmdline(arg)
hmp = True
elif arg == "-p":
if pp is not None:
fail_cmdline(arg)
pp = pprint.PrettyPrinter(indent=4)
else:
if qemu is not None:
fail_cmdline(arg)
if hmp:
qemu = HMPShell(arg)
else:
qemu = QMPShell(arg, pp)
addr = arg
if qemu is None:
fail_cmdline()
if len(sys.argv) == 2:
qemu = QMPShell(sys.argv[1])
addr = sys.argv[1]
elif len(sys.argv) == 3:
if sys.argv[1] != '-H':
fail_cmdline(sys.argv[1])
qemu = HMPShell(sys.argv[2])
addr = sys.argv[2]
else:
fail_cmdline()
except QMPShellBadPort:
die('bad port number in command-line')

View File

@@ -49,6 +49,7 @@ class QEMUMonitorProtocol:
return socket.socket(family, socket.SOCK_STREAM)
def __negotiate_capabilities(self):
self.__sockfile = self.__sock.makefile()
greeting = self.__json_read()
if greeting is None or not greeting.has_key('QMP'):
raise QMPConnectError
@@ -72,7 +73,7 @@ class QEMUMonitorProtocol:
error = socket.error
def connect(self, negotiate=True):
def connect(self):
"""
Connect to the QMP Monitor and perform capabilities negotiation.
@@ -82,9 +83,7 @@ class QEMUMonitorProtocol:
@raise QMPCapabilitiesError if fails to negotiate capabilities
"""
self.__sock.connect(self.__address)
self.__sockfile = self.__sock.makefile()
if negotiate:
return self.__negotiate_capabilities()
return self.__negotiate_capabilities()
def accept(self):
"""
@@ -96,7 +95,6 @@ class QEMUMonitorProtocol:
@raise QMPCapabilitiesError if fails to negotiate capabilities
"""
self.__sock, _ = self.__sock.accept()
self.__sockfile = self.__sock.makefile()
return self.__negotiate_capabilities()
def cmd_obj(self, qmp_cmd):
@@ -136,26 +134,6 @@ class QEMUMonitorProtocol:
raise Exception(ret['error']['desc'])
return ret['return']
def pull_event(self, wait=False):
"""
Get and delete the first available QMP event.
@param wait: block until an event is available (bool)
"""
self.__sock.setblocking(0)
try:
self.__json_read()
except socket.error, err:
if err[0] == errno.EAGAIN:
# No data available
pass
self.__sock.setblocking(1)
if not self.__events and wait:
self.__json_read(only_event=True)
event = self.__events[0]
del self.__events[0]
return event
def get_events(self, wait=False):
"""
Get a list of available QMP events.
@@ -183,8 +161,3 @@ class QEMUMonitorProtocol:
def close(self):
self.__sock.close()
self.__sockfile.close()
timeout = socket.timeout
def settimeout(self, timeout):
self.__sock.settimeout(timeout)

View File

@@ -1 +1 @@
1.4.1
1.2.2

430
a.out.h Normal file
View File

@@ -0,0 +1,430 @@
/* a.out.h
Copyright 1997, 1998, 1999, 2001 Red Hat, Inc.
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#ifndef _A_OUT_H_
#define _A_OUT_H_
#ifdef __cplusplus
extern "C" {
#endif
#define COFF_IMAGE_WITH_PE
#define COFF_LONG_SECTION_NAMES
/*** coff information for Intel 386/486. */
/********************** FILE HEADER **********************/
struct external_filehdr {
short f_magic; /* magic number */
short f_nscns; /* number of sections */
host_ulong f_timdat; /* time & date stamp */
host_ulong f_symptr; /* file pointer to symtab */
host_ulong f_nsyms; /* number of symtab entries */
short f_opthdr; /* sizeof(optional hdr) */
short f_flags; /* flags */
};
/* Bits for f_flags:
* F_RELFLG relocation info stripped from file
* F_EXEC file is executable (no unresolved external references)
* F_LNNO line numbers stripped from file
* F_LSYMS local symbols stripped from file
* F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax)
*/
#define F_RELFLG (0x0001)
#define F_EXEC (0x0002)
#define F_LNNO (0x0004)
#define F_LSYMS (0x0008)
#define I386MAGIC 0x14c
#define I386PTXMAGIC 0x154
#define I386AIXMAGIC 0x175
/* This is Lynx's all-platform magic number for executables. */
#define LYNXCOFFMAGIC 0415
#define I386BADMAG(x) (((x).f_magic != I386MAGIC) \
&& (x).f_magic != I386AIXMAGIC \
&& (x).f_magic != I386PTXMAGIC \
&& (x).f_magic != LYNXCOFFMAGIC)
#define FILHDR struct external_filehdr
#define FILHSZ 20
/********************** AOUT "OPTIONAL HEADER"=
**********************/
typedef struct
{
unsigned short magic; /* type of file */
unsigned short vstamp; /* version stamp */
host_ulong tsize; /* text size in bytes, padded to FW bdry*/
host_ulong dsize; /* initialized data " " */
host_ulong bsize; /* uninitialized data " " */
host_ulong entry; /* entry pt. */
host_ulong text_start; /* base of text used for this file */
host_ulong data_start; /* base of data used for this file=
*/
}
AOUTHDR;
#define AOUTSZ 28
#define AOUTHDRSZ 28
#define OMAGIC 0404 /* object files, eg as output */
#define ZMAGIC 0413 /* demand load format, eg normal ld output */
#define STMAGIC 0401 /* target shlib */
#define SHMAGIC 0443 /* host shlib */
/* define some NT default values */
/* #define NT_IMAGE_BASE 0x400000 moved to internal.h */
#define NT_SECTION_ALIGNMENT 0x1000
#define NT_FILE_ALIGNMENT 0x200
#define NT_DEF_RESERVE 0x100000
#define NT_DEF_COMMIT 0x1000
/********************** SECTION HEADER **********************/
struct external_scnhdr {
char s_name[8]; /* section name */
host_ulong s_paddr; /* physical address, offset
of last addr in scn */
host_ulong s_vaddr; /* virtual address */
host_ulong s_size; /* section size */
host_ulong s_scnptr; /* file ptr to raw data for section */
host_ulong s_relptr; /* file ptr to relocation */
host_ulong s_lnnoptr; /* file ptr to line numbers */
unsigned short s_nreloc; /* number of relocation entries */
unsigned short s_nlnno; /* number of line number entries*/
host_ulong s_flags; /* flags */
};
#define SCNHDR struct external_scnhdr
#define SCNHSZ 40
/*
* names of "special" sections
*/
#define _TEXT ".text"
#define _DATA ".data"
#define _BSS ".bss"
#define _COMMENT ".comment"
#define _LIB ".lib"
/********************** LINE NUMBERS **********************/
/* 1 line number entry for every "breakpointable" source line in a section.
* Line numbers are grouped on a per function basis; first entry in a function
* grouping will have l_lnno = 0 and in place of physical address will be the
* symbol table index of the function name.
*/
struct external_lineno {
union {
host_ulong l_symndx; /* function name symbol index, iff l_lnno 0 */
host_ulong l_paddr; /* (physical) address of line number */
} l_addr;
unsigned short l_lnno; /* line number */
};
#define LINENO struct external_lineno
#define LINESZ 6
/********************** SYMBOLS **********************/
#define E_SYMNMLEN 8 /* # characters in a symbol name */
#define E_FILNMLEN 14 /* # characters in a file name */
#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */
struct QEMU_PACKED external_syment
{
union {
char e_name[E_SYMNMLEN];
struct {
host_ulong e_zeroes;
host_ulong e_offset;
} e;
} e;
host_ulong e_value;
unsigned short e_scnum;
unsigned short e_type;
char e_sclass[1];
char e_numaux[1];
};
#define N_BTMASK (0xf)
#define N_TMASK (0x30)
#define N_BTSHFT (4)
#define N_TSHIFT (2)
union external_auxent {
struct {
host_ulong x_tagndx; /* str, un, or enum tag indx */
union {
struct {
unsigned short x_lnno; /* declaration line number */
unsigned short x_size; /* str/union/array size */
} x_lnsz;
host_ulong x_fsize; /* size of function */
} x_misc;
union {
struct { /* if ISFCN, tag, or .bb */
host_ulong x_lnnoptr;/* ptr to fcn line # */
host_ulong x_endndx; /* entry ndx past block end */
} x_fcn;
struct { /* if ISARY, up to 4 dimen. */
char x_dimen[E_DIMNUM][2];
} x_ary;
} x_fcnary;
unsigned short x_tvndx; /* tv index */
} x_sym;
union {
char x_fname[E_FILNMLEN];
struct {
host_ulong x_zeroes;
host_ulong x_offset;
} x_n;
} x_file;
struct {
host_ulong x_scnlen; /* section length */
unsigned short x_nreloc; /* # relocation entries */
unsigned short x_nlinno; /* # line numbers */
host_ulong x_checksum; /* section COMDAT checksum */
unsigned short x_associated;/* COMDAT associated section index */
char x_comdat[1]; /* COMDAT selection number */
} x_scn;
struct {
host_ulong x_tvfill; /* tv fill value */
unsigned short x_tvlen; /* length of .tv */
char x_tvran[2][2]; /* tv range */
} x_tv; /* info about .tv section (in auxent of symbol .tv)) */
};
#define SYMENT struct external_syment
#define SYMESZ 18
#define AUXENT union external_auxent
#define AUXESZ 18
#define _ETEXT "etext"
/********************** RELOCATION DIRECTIVES **********************/
struct external_reloc {
char r_vaddr[4];
char r_symndx[4];
char r_type[2];
};
#define RELOC struct external_reloc
#define RELSZ 10
/* end of coff/i386.h */
/* PE COFF header information */
#ifndef _PE_H
#define _PE_H
/* NT specific file attributes */
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
#define IMAGE_FILE_32BIT_MACHINE 0x0100
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
#define IMAGE_FILE_SYSTEM 0x1000
#define IMAGE_FILE_DLL 0x2000
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
/* additional flags to be set for section headers to allow the NT loader to
read and write to the section data (to replace the addresses of data in
dlls for one thing); also to execute the section in .text's case=
*/
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
#define IMAGE_SCN_MEM_READ 0x40000000
#define IMAGE_SCN_MEM_WRITE 0x80000000
/*
* Section characteristics added for ppc-nt
*/
#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved. */
#define IMAGE_SCN_CNT_CODE 0x00000020 /* Section contains code. */
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* Section contains initialized data. */
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* Section contains uninitialized data. */
#define IMAGE_SCN_LNK_OTHER 0x00000100 /* Reserved. */
#define IMAGE_SCN_LNK_INFO 0x00000200 /* Section contains comments or some other type of information. */
#define IMAGE_SCN_LNK_REMOVE 0x00000800 /* Section contents will not become part of image. */
#define IMAGE_SCN_LNK_COMDAT 0x00001000 /* Section contents comdat. */
#define IMAGE_SCN_MEM_FARDATA 0x00008000
#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
#define IMAGE_SCN_MEM_16BIT 0x00020000
#define IMAGE_SCN_MEM_LOCKED 0x00040000
#define IMAGE_SCN_MEM_PRELOAD 0x00080000
#define IMAGE_SCN_ALIGN_1BYTES 0x00100000
#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default alignment if no others are specified. */
#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* Section contains extended relocations. */
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* Section is not cachable. */
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* Section is not pageable. */
#define IMAGE_SCN_MEM_SHARED 0x10000000 /* Section is shareable. */
/* COMDAT selection codes. */
#define IMAGE_COMDAT_SELECT_NODUPLICATES (1) /* Warn if duplicates. */
#define IMAGE_COMDAT_SELECT_ANY (2) /* No warning. */
#define IMAGE_COMDAT_SELECT_SAME_SIZE (3) /* Warn if different size. */
#define IMAGE_COMDAT_SELECT_EXACT_MATCH (4) /* Warn if different. */
#define IMAGE_COMDAT_SELECT_ASSOCIATIVE (5) /* Base on other section. */
/* Magic values that are true for all dos/nt implementations */
#define DOSMAGIC 0x5a4d
#define NT_SIGNATURE 0x00004550
/* NT allows long filenames, we want to accommodate this. This may break
some of the bfd functions */
#undef FILNMLEN
#define FILNMLEN 18 /* # characters in a file name */
#ifdef COFF_IMAGE_WITH_PE
/* The filehdr is only weired in images */
#undef FILHDR
struct external_PE_filehdr
{
/* DOS header fields */
unsigned short e_magic; /* Magic number, 0x5a4d */
unsigned short e_cblp; /* Bytes on last page of file, 0x90 */
unsigned short e_cp; /* Pages in file, 0x3 */
unsigned short e_crlc; /* Relocations, 0x0 */
unsigned short e_cparhdr; /* Size of header in paragraphs, 0x4 */
unsigned short e_minalloc; /* Minimum extra paragraphs needed, 0x0 */
unsigned short e_maxalloc; /* Maximum extra paragraphs needed, 0xFFFF */
unsigned short e_ss; /* Initial (relative) SS value, 0x0 */
unsigned short e_sp; /* Initial SP value, 0xb8 */
unsigned short e_csum; /* Checksum, 0x0 */
unsigned short e_ip; /* Initial IP value, 0x0 */
unsigned short e_cs; /* Initial (relative) CS value, 0x0 */
unsigned short e_lfarlc; /* File address of relocation table, 0x40 */
unsigned short e_ovno; /* Overlay number, 0x0 */
char e_res[4][2]; /* Reserved words, all 0x0 */
unsigned short e_oemid; /* OEM identifier (for e_oeminfo), 0x0 */
unsigned short e_oeminfo; /* OEM information; e_oemid specific, 0x0 */
char e_res2[10][2]; /* Reserved words, all 0x0 */
host_ulong e_lfanew; /* File address of new exe header, 0x80 */
char dos_message[16][4]; /* other stuff, always follow DOS header */
unsigned int nt_signature; /* required NT signature, 0x4550 */
/* From standard header */
unsigned short f_magic; /* magic number */
unsigned short f_nscns; /* number of sections */
host_ulong f_timdat; /* time & date stamp */
host_ulong f_symptr; /* file pointer to symtab */
host_ulong f_nsyms; /* number of symtab entries */
unsigned short f_opthdr; /* sizeof(optional hdr) */
unsigned short f_flags; /* flags */
};
#define FILHDR struct external_PE_filehdr
#undef FILHSZ
#define FILHSZ 152
#endif
typedef struct
{
unsigned short magic; /* type of file */
unsigned short vstamp; /* version stamp */
host_ulong tsize; /* text size in bytes, padded to FW bdry*/
host_ulong dsize; /* initialized data " " */
host_ulong bsize; /* uninitialized data " " */
host_ulong entry; /* entry pt. */
host_ulong text_start; /* base of text used for this file */
host_ulong data_start; /* base of all data used for this file */
/* NT extra fields; see internal.h for descriptions */
host_ulong ImageBase;
host_ulong SectionAlignment;
host_ulong FileAlignment;
unsigned short MajorOperatingSystemVersion;
unsigned short MinorOperatingSystemVersion;
unsigned short MajorImageVersion;
unsigned short MinorImageVersion;
unsigned short MajorSubsystemVersion;
unsigned short MinorSubsystemVersion;
char Reserved1[4];
host_ulong SizeOfImage;
host_ulong SizeOfHeaders;
host_ulong CheckSum;
unsigned short Subsystem;
unsigned short DllCharacteristics;
host_ulong SizeOfStackReserve;
host_ulong SizeOfStackCommit;
host_ulong SizeOfHeapReserve;
host_ulong SizeOfHeapCommit;
host_ulong LoaderFlags;
host_ulong NumberOfRvaAndSizes;
/* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */
char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */
} PEAOUTHDR;
#undef AOUTSZ
#define AOUTSZ (AOUTHDRSZ + 196)
#undef E_FILNMLEN
#define E_FILNMLEN 18 /* # characters in a file name */
#endif
/* end of coff/pe.h */
#define DT_NON (0) /* no derived type */
#define DT_PTR (1) /* pointer */
#define DT_FCN (2) /* function */
#define DT_ARY (3) /* array */
#define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT))
#define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT))
#define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT))
#ifdef __cplusplus
}
#endif
#endif /* _A_OUT_H_ */

View File

@@ -24,7 +24,7 @@
#include "qemu-common.h"
#include "qemu/acl.h"
#include "acl.h"
#ifdef CONFIG_FNMATCH
#include <fnmatch.h>
@@ -103,8 +103,8 @@ void qemu_acl_reset(qemu_acl *acl)
acl->defaultDeny = 1;
QTAILQ_FOREACH_SAFE(entry, &acl->entries, next, next_entry) {
QTAILQ_REMOVE(&acl->entries, entry, next);
g_free(entry->match);
g_free(entry);
free(entry->match);
free(entry);
}
acl->nentries = 0;
}
@@ -168,9 +168,6 @@ int qemu_acl_remove(qemu_acl *acl,
i++;
if (strcmp(entry->match, match) == 0) {
QTAILQ_REMOVE(&acl->entries, entry, next);
acl->nentries--;
g_free(entry->match);
g_free(entry);
return i;
}
}

View File

@@ -25,7 +25,7 @@
#ifndef __QEMU_ACL_H__
#define __QEMU_ACL_H__
#include "qemu/queue.h"
#include "qemu-queue.h"
typedef struct qemu_acl_entry qemu_acl_entry;
typedef struct qemu_acl qemu_acl;

View File

@@ -28,7 +28,7 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "qemu-common.h"
#include "block/aes.h"
#include "aes.h"
#ifndef NDEBUG
#define NDEBUG

View File

@@ -1,269 +0,0 @@
/*
* QEMU aio implementation
*
* Copyright IBM, Corp. 2008
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#include "qemu-common.h"
#include "block/block.h"
#include "qemu/queue.h"
#include "qemu/sockets.h"
struct AioHandler
{
GPollFD pfd;
IOHandler *io_read;
IOHandler *io_write;
AioFlushHandler *io_flush;
int deleted;
void *opaque;
QLIST_ENTRY(AioHandler) node;
};
static AioHandler *find_aio_handler(AioContext *ctx, int fd)
{
AioHandler *node;
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
if (node->pfd.fd == fd)
if (!node->deleted)
return node;
}
return NULL;
}
void aio_set_fd_handler(AioContext *ctx,
int fd,
IOHandler *io_read,
IOHandler *io_write,
AioFlushHandler *io_flush,
void *opaque)
{
AioHandler *node;
node = find_aio_handler(ctx, fd);
/* Are we deleting the fd handler? */
if (!io_read && !io_write) {
if (node) {
g_source_remove_poll(&ctx->source, &node->pfd);
/* If the lock is held, just mark the node as deleted */
if (ctx->walking_handlers) {
node->deleted = 1;
node->pfd.revents = 0;
} else {
/* Otherwise, delete it for real. We can't just mark it as
* deleted because deleted nodes are only cleaned up after
* releasing the walking_handlers lock.
*/
QLIST_REMOVE(node, node);
g_free(node);
}
}
} else {
if (node == NULL) {
/* Alloc and insert if it's not already there */
node = g_malloc0(sizeof(AioHandler));
node->pfd.fd = fd;
QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
g_source_add_poll(&ctx->source, &node->pfd);
}
/* Update handler with latest information */
node->io_read = io_read;
node->io_write = io_write;
node->io_flush = io_flush;
node->opaque = opaque;
node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP : 0);
node->pfd.events |= (io_write ? G_IO_OUT : 0);
}
aio_notify(ctx);
}
void aio_set_event_notifier(AioContext *ctx,
EventNotifier *notifier,
EventNotifierHandler *io_read,
AioFlushEventNotifierHandler *io_flush)
{
aio_set_fd_handler(ctx, event_notifier_get_fd(notifier),
(IOHandler *)io_read, NULL,
(AioFlushHandler *)io_flush, notifier);
}
bool aio_pending(AioContext *ctx)
{
AioHandler *node;
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;
}
if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) {
return true;
}
}
return false;
}
bool aio_poll(AioContext *ctx, bool blocking)
{
static struct timeval tv0;
AioHandler *node;
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.
*/
node = QLIST_FIRST(&ctx->aio_handlers);
while (node) {
AioHandler *tmp;
int revents;
ctx->walking_handlers++;
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 &&
FD_ISSET(node->pfd.fd, &rdfds) &&
node->io_read) {
node->io_read(node->opaque);
progress = true;
}
if (!node->deleted &&
FD_ISSET(node->pfd.fd, &wrfds) &&
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);
}
}
}
assert(progress || busy);
return true;
}

View File

@@ -1,219 +0,0 @@
/*
* QEMU aio implementation
*
* Copyright IBM Corp., 2008
* Copyright Red Hat Inc., 2012
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
* Paolo Bonzini <pbonzini@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#include "qemu-common.h"
#include "block/block.h"
#include "qemu/queue.h"
#include "qemu/sockets.h"
struct AioHandler {
EventNotifier *e;
EventNotifierHandler *io_notify;
AioFlushEventNotifierHandler *io_flush;
GPollFD pfd;
int deleted;
QLIST_ENTRY(AioHandler) node;
};
void aio_set_event_notifier(AioContext *ctx,
EventNotifier *e,
EventNotifierHandler *io_notify,
AioFlushEventNotifierHandler *io_flush)
{
AioHandler *node;
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
if (node->e == e && !node->deleted) {
break;
}
}
/* Are we deleting the fd handler? */
if (!io_notify) {
if (node) {
g_source_remove_poll(&ctx->source, &node->pfd);
/* If the lock is held, just mark the node as deleted */
if (ctx->walking_handlers) {
node->deleted = 1;
node->pfd.revents = 0;
} else {
/* Otherwise, delete it for real. We can't just mark it as
* deleted because deleted nodes are only cleaned up after
* releasing the walking_handlers lock.
*/
QLIST_REMOVE(node, node);
g_free(node);
}
}
} else {
if (node == NULL) {
/* Alloc and insert if it's not already there */
node = g_malloc0(sizeof(AioHandler));
node->e = e;
node->pfd.fd = (uintptr_t)event_notifier_get_handle(e);
node->pfd.events = G_IO_IN;
QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
g_source_add_poll(&ctx->source, &node->pfd);
}
/* Update handler with latest information */
node->io_notify = io_notify;
node->io_flush = io_flush;
}
aio_notify(ctx);
}
bool aio_pending(AioContext *ctx)
{
AioHandler *node;
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
if (node->pfd.revents && node->io_notify) {
return true;
}
}
return false;
}
bool aio_poll(AioContext *ctx, bool blocking)
{
AioHandler *node;
HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
bool busy, progress;
int count;
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.
*/
node = QLIST_FIRST(&ctx->aio_handlers);
while (node) {
AioHandler *tmp;
ctx->walking_handlers++;
if (node->pfd.revents && node->io_notify) {
node->pfd.revents = 0;
node->io_notify(node->e);
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++;
/* fill fd sets */
busy = false;
count = 0;
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->e) == 0) {
continue;
}
busy = true;
}
if (!node->deleted && node->io_notify) {
events[count++] = event_notifier_get_handle(node->e);
}
}
ctx->walking_handlers--;
/* No AIO operations? Get us out of here */
if (!busy) {
return progress;
}
/* wait until next event */
while (count > 0) {
int timeout = blocking ? INFINITE : 0;
int ret = WaitForMultipleObjects(count, events, FALSE, timeout);
/* if we have any signaled events, dispatch event */
if ((DWORD) (ret - WAIT_OBJECT_0) >= count) {
break;
}
blocking = false;
/* 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 &&
event_notifier_get_handle(node->e) == events[ret - WAIT_OBJECT_0] &&
node->io_notify) {
node->io_notify(node->e);
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);
}
}
/* Try again, but only call each handler once. */
events[ret - WAIT_OBJECT_0] = events[--count];
}
assert(progress || busy);
return true;
}

194
aio.c Normal file
View File

@@ -0,0 +1,194 @@
/*
* QEMU aio implementation
*
* Copyright IBM, Corp. 2008
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#include "qemu-common.h"
#include "block.h"
#include "qemu-queue.h"
#include "qemu_socket.h"
typedef struct AioHandler AioHandler;
/* The list of registered AIO handlers */
static QLIST_HEAD(, AioHandler) aio_handlers;
/* This is a simple lock used to protect the aio_handlers list. Specifically,
* it's used to ensure that no callbacks are removed while we're walking and
* dispatching callbacks.
*/
static int walking_handlers;
struct AioHandler
{
int fd;
IOHandler *io_read;
IOHandler *io_write;
AioFlushHandler *io_flush;
int deleted;
void *opaque;
QLIST_ENTRY(AioHandler) node;
};
static AioHandler *find_aio_handler(int fd)
{
AioHandler *node;
QLIST_FOREACH(node, &aio_handlers, node) {
if (node->fd == fd)
if (!node->deleted)
return node;
}
return NULL;
}
int qemu_aio_set_fd_handler(int fd,
IOHandler *io_read,
IOHandler *io_write,
AioFlushHandler *io_flush,
void *opaque)
{
AioHandler *node;
node = find_aio_handler(fd);
/* Are we deleting the fd handler? */
if (!io_read && !io_write) {
if (node) {
/* If the lock is held, just mark the node as deleted */
if (walking_handlers)
node->deleted = 1;
else {
/* Otherwise, delete it for real. We can't just mark it as
* deleted because deleted nodes are only cleaned up after
* releasing the walking_handlers lock.
*/
QLIST_REMOVE(node, node);
g_free(node);
}
}
} else {
if (node == NULL) {
/* Alloc and insert if it's not already there */
node = g_malloc0(sizeof(AioHandler));
node->fd = fd;
QLIST_INSERT_HEAD(&aio_handlers, node, node);
}
/* Update handler with latest information */
node->io_read = io_read;
node->io_write = io_write;
node->io_flush = io_flush;
node->opaque = opaque;
}
qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
return 0;
}
void qemu_aio_flush(void)
{
while (qemu_aio_wait());
}
bool qemu_aio_wait(void)
{
AioHandler *node;
fd_set rdfds, wrfds;
int max_fd = -1;
int ret;
bool busy;
/*
* 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 (qemu_bh_poll()) {
return true;
}
walking_handlers = 1;
FD_ZERO(&rdfds);
FD_ZERO(&wrfds);
/* fill fd sets */
busy = false;
QLIST_FOREACH(node, &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->io_flush) {
if (node->io_flush(node->opaque) == 0) {
continue;
}
busy = true;
}
if (!node->deleted && node->io_read) {
FD_SET(node->fd, &rdfds);
max_fd = MAX(max_fd, node->fd + 1);
}
if (!node->deleted && node->io_write) {
FD_SET(node->fd, &wrfds);
max_fd = MAX(max_fd, node->fd + 1);
}
}
walking_handlers = 0;
/* No AIO operations? Get us out of here */
if (!busy) {
return false;
}
/* wait until next event */
ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
/* if we have any readable fds, dispatch event */
if (ret > 0) {
walking_handlers = 1;
/* we have to walk very carefully in case
* qemu_aio_set_fd_handler is called while we're walking */
node = QLIST_FIRST(&aio_handlers);
while (node) {
AioHandler *tmp;
if (!node->deleted &&
FD_ISSET(node->fd, &rdfds) &&
node->io_read) {
node->io_read(node->opaque);
}
if (!node->deleted &&
FD_ISSET(node->fd, &wrfds) &&
node->io_write) {
node->io_write(node->opaque);
}
tmp = node;
node = QLIST_NEXT(node, node);
if (tmp->deleted) {
QLIST_REMOVE(tmp, node);
g_free(tmp);
}
}
walking_handlers = 0;
}
return true;
}

View File

@@ -20,7 +20,7 @@ along with this file; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include <stdio.h>
#include "disas/bfd.h"
#include "dis-asm.h"
/* MAX is redefined below, so remove any previous definition. */
#undef MAX

View File

@@ -29,26 +29,22 @@
#include <sys/mman.h>
#endif
#include "config.h"
#include "monitor/monitor.h"
#include "sysemu/sysemu.h"
#include "qemu/bitops.h"
#include "qemu/bitmap.h"
#include "sysemu/arch_init.h"
#include "monitor.h"
#include "sysemu.h"
#include "arch_init.h"
#include "audio/audio.h"
#include "hw/pc.h"
#include "hw/pci/pci.h"
#include "hw/pci.h"
#include "hw/audiodev.h"
#include "sysemu/kvm.h"
#include "migration/migration.h"
#include "exec/gdbstub.h"
#include "kvm.h"
#include "migration.h"
#include "net.h"
#include "gdbstub.h"
#include "hw/smbios.h"
#include "exec/address-spaces.h"
#include "exec-memory.h"
#include "hw/pcspk.h"
#include "migration/page_cache.h"
#include "qemu/config-file.h"
#include "qemu/page_cache.h"
#include "qmp-commands.h"
#include "trace.h"
#include "exec/cpu-all.h"
#ifdef DEBUG_ARCH_INIT
#define DPRINTF(fmt, ...) \
@@ -140,6 +136,7 @@ static struct defconfig_file {
/* Indicates it is an user config file (disabled by -no-user-config) */
bool userconfig;
} default_config_files[] = {
{ CONFIG_QEMU_DATADIR "/cpus-" TARGET_ARCH ".conf", false },
{ CONFIG_QEMU_CONFDIR "/qemu.conf", true },
{ CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".conf", true },
{ NULL }, /* end of list */
@@ -265,21 +262,16 @@ uint64_t xbzrle_mig_pages_overflow(void)
return acct_info.xbzrle_overflows;
}
static size_t save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
int cont, int flag)
static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
int cont, int flag)
{
size_t size;
qemu_put_be64(f, offset | cont | flag);
if (!cont) {
qemu_put_byte(f, strlen(block->idstr));
qemu_put_buffer(f, (uint8_t *)block->idstr,
strlen(block->idstr));
}
qemu_put_be64(f, offset | cont | flag);
size = 8;
if (!cont) {
qemu_put_byte(f, strlen(block->idstr));
qemu_put_buffer(f, (uint8_t *)block->idstr,
strlen(block->idstr));
size += 1 + strlen(block->idstr);
}
return size;
}
#define ENCODING_FLAG_XBZRLE 0x1
@@ -326,147 +318,56 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
}
/* Send XBZRLE based compressed page */
bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_XBZRLE);
save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_XBZRLE);
qemu_put_byte(f, ENCODING_FLAG_XBZRLE);
qemu_put_be16(f, encoded_len);
qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
bytes_sent += encoded_len + 1 + 2;
bytes_sent = encoded_len + 1 + 2;
acct_info.xbzrle_pages++;
acct_info.xbzrle_bytes += bytes_sent;
return bytes_sent;
}
/* This is the last block that we have visited serching for dirty pages
*/
static RAMBlock *last_seen_block;
/* This is the last block from where we have sent data */
static RAMBlock *last_sent_block;
static RAMBlock *last_block;
static ram_addr_t last_offset;
static unsigned long *migration_bitmap;
static uint64_t migration_dirty_pages;
static uint32_t last_version;
static inline
ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr,
ram_addr_t start)
{
unsigned long base = mr->ram_addr >> TARGET_PAGE_BITS;
unsigned long nr = base + (start >> TARGET_PAGE_BITS);
unsigned long size = base + (int128_get64(mr->size) >> TARGET_PAGE_BITS);
unsigned long next = find_next_bit(migration_bitmap, size, nr);
if (next < size) {
clear_bit(next, migration_bitmap);
migration_dirty_pages--;
}
return (next - base) << TARGET_PAGE_BITS;
}
static inline bool migration_bitmap_set_dirty(MemoryRegion *mr,
ram_addr_t offset)
{
bool ret;
int nr = (mr->ram_addr + offset) >> TARGET_PAGE_BITS;
ret = test_and_set_bit(nr, migration_bitmap);
if (!ret) {
migration_dirty_pages++;
}
return ret;
}
static void migration_bitmap_sync(void)
{
RAMBlock *block;
ram_addr_t addr;
uint64_t num_dirty_pages_init = migration_dirty_pages;
MigrationState *s = migrate_get_current();
static int64_t start_time;
static int64_t num_dirty_pages_period;
int64_t end_time;
if (!start_time) {
start_time = qemu_get_clock_ms(rt_clock);
}
trace_migration_bitmap_sync_start();
memory_global_sync_dirty_bitmap(get_system_memory());
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
if (memory_region_test_and_clear_dirty(block->mr,
addr, TARGET_PAGE_SIZE,
DIRTY_MEMORY_MIGRATION)) {
migration_bitmap_set_dirty(block->mr, addr);
}
}
}
trace_migration_bitmap_sync_end(migration_dirty_pages
- num_dirty_pages_init);
num_dirty_pages_period += migration_dirty_pages - num_dirty_pages_init;
end_time = qemu_get_clock_ms(rt_clock);
/* more than 1 second = 1000 millisecons */
if (end_time > start_time + 1000) {
s->dirty_pages_rate = num_dirty_pages_period * 1000
/ (end_time - start_time);
start_time = end_time;
num_dirty_pages_period = 0;
}
}
/*
* ram_save_block: Writes a page of memory to the stream f
*
* Returns: The number of bytes written.
* 0 means no dirty pages
* Returns: 0: if the page hasn't changed
* -1: if there are no more dirty pages
* n: the amount of bytes written in other case
*/
static int ram_save_block(QEMUFile *f, bool last_stage)
{
RAMBlock *block = last_seen_block;
RAMBlock *block = last_block;
ram_addr_t offset = last_offset;
bool complete_round = false;
int bytes_sent = 0;
int bytes_sent = -1;
MemoryRegion *mr;
ram_addr_t current_addr;
if (!block)
block = QTAILQ_FIRST(&ram_list.blocks);
block = QLIST_FIRST(&ram_list.blocks);
while (true) {
do {
mr = block->mr;
offset = migration_bitmap_find_and_reset_dirty(mr, offset);
if (complete_round && block == last_seen_block &&
offset >= last_offset) {
break;
}
if (offset >= block->length) {
offset = 0;
block = QTAILQ_NEXT(block, next);
if (!block) {
block = QTAILQ_FIRST(&ram_list.blocks);
complete_round = true;
}
} else {
if (memory_region_get_dirty(mr, offset, TARGET_PAGE_SIZE,
DIRTY_MEMORY_MIGRATION)) {
uint8_t *p;
int cont = (block == last_sent_block) ?
RAM_SAVE_FLAG_CONTINUE : 0;
int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
memory_region_reset_dirty(mr, offset, TARGET_PAGE_SIZE,
DIRTY_MEMORY_MIGRATION);
p = memory_region_get_ram_ptr(mr) + offset;
/* In doubt sent page as normal */
bytes_sent = -1;
if (is_dup_page(p)) {
acct_info.dup_pages++;
bytes_sent = save_block_hdr(f, block, offset, cont,
RAM_SAVE_FLAG_COMPRESS);
save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_COMPRESS);
qemu_put_byte(f, *p);
bytes_sent += 1;
bytes_sent = 1;
} else if (migrate_use_xbzrle()) {
current_addr = block->offset + offset;
bytes_sent = save_xbzrle_page(f, p, current_addr, block,
@@ -476,22 +377,30 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
}
}
/* XBZRLE overflow or normal page */
/* either we didn't send yet (we may have had XBZRLE overflow) */
if (bytes_sent == -1) {
bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
bytes_sent += TARGET_PAGE_SIZE;
bytes_sent = TARGET_PAGE_SIZE;
acct_info.norm_pages++;
}
/* if page is unmodified, continue to the next */
if (bytes_sent > 0) {
last_sent_block = block;
if (bytes_sent != 0) {
break;
}
}
}
last_seen_block = block;
offset += TARGET_PAGE_SIZE;
if (offset >= block->length) {
offset = 0;
block = QLIST_NEXT(block, next);
if (!block)
block = QLIST_FIRST(&ram_list.blocks);
}
} while (block != last_block || offset != last_offset);
last_block = block;
last_offset = offset;
return bytes_sent;
@@ -501,7 +410,7 @@ static uint64_t bytes_transferred;
static ram_addr_t ram_save_remaining(void)
{
return migration_dirty_pages;
return ram_list.dirty_pages;
}
uint64_t ram_bytes_remaining(void)
@@ -519,21 +428,46 @@ uint64_t ram_bytes_total(void)
RAMBlock *block;
uint64_t total = 0;
QTAILQ_FOREACH(block, &ram_list.blocks, next)
QLIST_FOREACH(block, &ram_list.blocks, next)
total += block->length;
return total;
}
static int block_compar(const void *a, const void *b)
{
RAMBlock * const *ablock = a;
RAMBlock * const *bblock = b;
return strcmp((*ablock)->idstr, (*bblock)->idstr);
}
static void sort_ram_list(void)
{
RAMBlock *block, *nblock, **blocks;
int n;
n = 0;
QLIST_FOREACH(block, &ram_list.blocks, next) {
++n;
}
blocks = g_malloc(n * sizeof *blocks);
n = 0;
QLIST_FOREACH_SAFE(block, &ram_list.blocks, next, nblock) {
blocks[n++] = block;
QLIST_REMOVE(block, next);
}
qsort(blocks, n, sizeof *blocks, block_compar);
while (--n >= 0) {
QLIST_INSERT_HEAD(&ram_list.blocks, blocks[n], next);
}
g_free(blocks);
}
static void migration_end(void)
{
if (migration_bitmap) {
memory_global_dirty_log_stop();
g_free(migration_bitmap);
migration_bitmap = NULL;
}
memory_global_dirty_log_stop();
if (XBZRLE.cache) {
if (migrate_use_xbzrle()) {
cache_fini(XBZRLE.cache);
g_free(XBZRLE.cache);
g_free(XBZRLE.encoded_buf);
@@ -548,28 +482,17 @@ static void ram_migration_cancel(void *opaque)
migration_end();
}
static void reset_ram_globals(void)
{
last_seen_block = NULL;
last_sent_block = NULL;
last_offset = 0;
last_version = ram_list.version;
}
#define MAX_WAIT 50 /* ms, half buffered_file limit */
static int ram_save_setup(QEMUFile *f, void *opaque)
{
ram_addr_t addr;
RAMBlock *block;
int64_t ram_pages = last_ram_offset() >> TARGET_PAGE_BITS;
migration_bitmap = bitmap_new(ram_pages);
bitmap_set(migration_bitmap, 0, ram_pages);
migration_dirty_pages = ram_pages;
qemu_mutex_lock_ramlist();
bytes_transferred = 0;
reset_ram_globals();
last_block = NULL;
last_offset = 0;
sort_ram_list();
if (migrate_use_xbzrle()) {
XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
@@ -584,18 +507,26 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
acct_clear();
}
/* Make sure all dirty bits are set */
QLIST_FOREACH(block, &ram_list.blocks, next) {
for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
if (!memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
DIRTY_MEMORY_MIGRATION)) {
memory_region_set_dirty(block->mr, addr, TARGET_PAGE_SIZE);
}
}
}
memory_global_dirty_log_start();
migration_bitmap_sync();
qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
QLIST_FOREACH(block, &ram_list.blocks, next) {
qemu_put_byte(f, strlen(block->idstr));
qemu_put_buffer(f, (uint8_t *)block->idstr, strlen(block->idstr));
qemu_put_be64(f, block->length);
}
qemu_mutex_unlock_ramlist();
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
return 0;
@@ -603,28 +534,25 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
static int ram_save_iterate(QEMUFile *f, void *opaque)
{
uint64_t bytes_transferred_last;
double bwidth = 0;
int ret;
int i;
int64_t t0;
int total_sent = 0;
uint64_t expected_time;
qemu_mutex_lock_ramlist();
bytes_transferred_last = bytes_transferred;
bwidth = qemu_get_clock_ns(rt_clock);
if (ram_list.version != last_version) {
reset_ram_globals();
}
t0 = qemu_get_clock_ns(rt_clock);
i = 0;
while ((ret = qemu_file_rate_limit(f)) == 0) {
int bytes_sent;
bytes_sent = ram_save_block(f, false);
/* no more blocks to sent */
if (bytes_sent == 0) {
if (bytes_sent < 0) {
break;
}
total_sent += bytes_sent;
bytes_transferred += bytes_sent;
acct_info.iterations++;
/* we want to check in the 1st loop, just in case it was the 1st time
and we had to sync the dirty bitmap.
@@ -632,7 +560,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
iterations
*/
if ((i & 63) == 0) {
uint64_t t1 = (qemu_get_clock_ns(rt_clock) - t0) / 1000000;
uint64_t t1 = (qemu_get_clock_ns(rt_clock) - bwidth) / 1000000;
if (t1 > MAX_WAIT) {
DPRINTF("big wait: %" PRIu64 " milliseconds, %d iterations\n",
t1, i);
@@ -642,24 +570,38 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
i++;
}
qemu_mutex_unlock_ramlist();
if (ret < 0) {
bytes_transferred += total_sent;
return ret;
}
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
total_sent += 8;
bytes_transferred += total_sent;
bwidth = qemu_get_clock_ns(rt_clock) - bwidth;
bwidth = (bytes_transferred - bytes_transferred_last) / bwidth;
return total_sent;
/* if we haven't transferred anything this round, force expected_time to a
* a very high value, but without crashing */
if (bwidth == 0) {
bwidth = 0.000001;
}
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;
DPRINTF("ram_save_live: expected(%" PRIu64 ") <= max(%" PRIu64 ")?\n",
expected_time, migrate_max_downtime());
if (expected_time <= migrate_max_downtime()) {
memory_global_sync_dirty_bitmap(get_system_memory());
expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;
return expected_time <= migrate_max_downtime();
}
return 0;
}
static int ram_save_complete(QEMUFile *f, void *opaque)
{
qemu_mutex_lock_ramlist();
migration_bitmap_sync();
memory_global_sync_dirty_bitmap(get_system_memory());
/* try transferring iterative blocks of memory */
@@ -669,32 +611,18 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
bytes_sent = ram_save_block(f, true);
/* no more blocks to sent */
if (bytes_sent == 0) {
if (bytes_sent < 0) {
break;
}
bytes_transferred += bytes_sent;
}
migration_end();
memory_global_dirty_log_stop();
qemu_mutex_unlock_ramlist();
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
return 0;
}
static uint64_t ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
{
uint64_t remaining_size;
remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE;
if (remaining_size < max_size) {
migration_bitmap_sync();
remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE;
}
return remaining_size;
}
static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
{
int ret, rc = 0;
@@ -757,7 +685,7 @@ static inline void *host_from_stream_offset(QEMUFile *f,
qemu_get_buffer(f, (uint8_t *)id, len);
id[len] = 0;
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
QLIST_FOREACH(block, &ram_list.blocks, next) {
if (!strncmp(id, block->idstr, sizeof(id)))
return memory_region_get_ram_ptr(block->mr) + offset;
}
@@ -801,7 +729,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
id[len] = 0;
length = qemu_get_be64(f);
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
QLIST_FOREACH(block, &ram_list.blocks, next) {
if (!strncmp(id, block->idstr, sizeof(id))) {
if (block->length != length) {
ret = -EINVAL;
@@ -836,8 +764,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
memset(host, ch, TARGET_PAGE_SIZE);
#ifndef _WIN32
if (ch == 0 &&
(!kvm_enabled() || kvm_has_sync_mmu()) &&
getpagesize() <= TARGET_PAGE_SIZE) {
(!kvm_enabled() || kvm_has_sync_mmu())) {
qemu_madvise(host, TARGET_PAGE_SIZE, QEMU_MADV_DONTNEED);
}
#endif
@@ -851,6 +778,9 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
} else if (flags & RAM_SAVE_FLAG_XBZRLE) {
if (!migrate_use_xbzrle()) {
return -EINVAL;
}
void *host = host_from_stream_offset(f, addr, flags);
if (!host) {
return -EINVAL;
@@ -878,7 +808,6 @@ SaveVMHandlers savevm_ram_handlers = {
.save_live_setup = ram_save_setup,
.save_live_iterate = ram_save_iterate,
.save_live_complete = ram_save_complete,
.save_live_pending = ram_save_pending,
.load_state = ram_load,
.cancel = ram_migration_cancel,
};

View File

@@ -34,6 +34,6 @@ int tcg_available(void);
int kvm_available(void);
int xen_available(void);
CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp);
CpuDefinitionInfoList GCC_WEAK_DECL *arch_query_cpu_definitions(Error **errp);
#endif

View File

@@ -22,7 +22,7 @@
/* Start of qemu specific additions. Mostly this is stub definitions
for things we don't care about. */
#include "disas/bfd.h"
#include "dis-asm.h"
#define ATTRIBUTE_UNUSED __attribute__((unused))
#define ISSPACE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n')

117
async.c
View File

@@ -23,14 +23,16 @@
*/
#include "qemu-common.h"
#include "block/aio.h"
#include "qemu/main-loop.h"
#include "qemu-aio.h"
#include "main-loop.h"
/* Anchor of the list of Bottom Halves belonging to the context */
static struct QEMUBH *first_bh;
/***********************************************************/
/* bottom halves (can be seen as timers which expire ASAP) */
struct QEMUBH {
AioContext *ctx;
QEMUBHFunc *cb;
void *opaque;
QEMUBH *next;
@@ -39,27 +41,27 @@ struct QEMUBH {
bool deleted;
};
QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
{
QEMUBH *bh;
bh = g_malloc0(sizeof(QEMUBH));
bh->ctx = ctx;
bh->cb = cb;
bh->opaque = opaque;
bh->next = ctx->first_bh;
ctx->first_bh = bh;
bh->next = first_bh;
first_bh = bh;
return bh;
}
int aio_bh_poll(AioContext *ctx)
int qemu_bh_poll(void)
{
QEMUBH *bh, **bhp, *next;
int ret;
static int nesting = 0;
ctx->walking_bh++;
nesting++;
ret = 0;
for (bh = ctx->first_bh; bh; bh = next) {
for (bh = first_bh; bh; bh = next) {
next = bh->next;
if (!bh->deleted && bh->scheduled) {
bh->scheduled = 0;
@@ -70,11 +72,11 @@ int aio_bh_poll(AioContext *ctx)
}
}
ctx->walking_bh--;
nesting--;
/* remove deleted bhs */
if (!ctx->walking_bh) {
bhp = &ctx->first_bh;
if (!nesting) {
bhp = &first_bh;
while (*bhp) {
bh = *bhp;
if (bh->deleted) {
@@ -103,7 +105,8 @@ void qemu_bh_schedule(QEMUBH *bh)
return;
bh->scheduled = 1;
bh->idle = 0;
aio_notify(bh->ctx);
/* stop the currently executing CPU to execute the BH ASAP */
qemu_notify_event();
}
void qemu_bh_cancel(QEMUBH *bh)
@@ -117,101 +120,23 @@ void qemu_bh_delete(QEMUBH *bh)
bh->deleted = 1;
}
static gboolean
aio_ctx_prepare(GSource *source, gint *timeout)
void qemu_bh_update_timeout(uint32_t *timeout)
{
AioContext *ctx = (AioContext *) source;
QEMUBH *bh;
for (bh = ctx->first_bh; bh; bh = bh->next) {
for (bh = first_bh; bh; bh = bh->next) {
if (!bh->deleted && bh->scheduled) {
if (bh->idle) {
/* idle bottom halves will be polled at least
* every 10ms */
*timeout = 10;
*timeout = MIN(10, *timeout);
} else {
/* non-idle bottom halves will be executed
* immediately */
*timeout = 0;
return true;
break;
}
}
}
return false;
}
static gboolean
aio_ctx_check(GSource *source)
{
AioContext *ctx = (AioContext *) source;
QEMUBH *bh;
for (bh = ctx->first_bh; bh; bh = bh->next) {
if (!bh->deleted && bh->scheduled) {
return true;
}
}
return aio_pending(ctx);
}
static gboolean
aio_ctx_dispatch(GSource *source,
GSourceFunc callback,
gpointer user_data)
{
AioContext *ctx = (AioContext *) source;
assert(callback == NULL);
aio_poll(ctx, false);
return true;
}
static void
aio_ctx_finalize(GSource *source)
{
AioContext *ctx = (AioContext *) source;
aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL);
event_notifier_cleanup(&ctx->notifier);
}
static GSourceFuncs aio_source_funcs = {
aio_ctx_prepare,
aio_ctx_check,
aio_ctx_dispatch,
aio_ctx_finalize
};
GSource *aio_get_g_source(AioContext *ctx)
{
g_source_ref(&ctx->source);
return &ctx->source;
}
void aio_notify(AioContext *ctx)
{
event_notifier_set(&ctx->notifier);
}
AioContext *aio_context_new(void)
{
AioContext *ctx;
ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
event_notifier_init(&ctx->notifier, false);
aio_set_event_notifier(ctx, &ctx->notifier,
(EventNotifierHandler *)
event_notifier_test_and_clear, NULL);
return ctx;
}
void aio_context_ref(AioContext *ctx)
{
g_source_ref(&ctx->source);
}
void aio_context_unref(AioContext *ctx)
{
g_source_unref(&ctx->source);
}

View File

@@ -12,6 +12,3 @@ common-obj-$(CONFIG_WINWAVE) += winwaveaudio.o
common-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o
common-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
common-obj-y += wavcapture.o
$(obj)/audio.o $(obj)/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
$(obj)/sdlaudio.o: QEMU_CFLAGS += $(SDL_CFLAGS)

View File

@@ -23,7 +23,7 @@
*/
#include <alsa/asoundlib.h>
#include "qemu-common.h"
#include "qemu/main-loop.h"
#include "qemu-char.h"
#include "audio.h"
#if QEMU_GNUC_PREREQ(4, 3)

View File

@@ -23,9 +23,9 @@
*/
#include "hw/hw.h"
#include "audio.h"
#include "monitor/monitor.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "monitor.h"
#include "qemu-timer.h"
#include "sysemu.h"
#define AUDIO_CAP "audio"
#include "audio_int.h"
@@ -828,9 +828,8 @@ static int audio_attach_capture (HWVoiceOut *hw)
QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
QLIST_INSERT_HEAD (&hw->cap_head, sc, entries);
#ifdef DEBUG_CAPTURE
sw->name = g_strdup_printf ("for %p %d,%d,%d",
hw, sw->info.freq, sw->info.bits,
sw->info.nchannels);
asprintf (&sw->name, "for %p %d,%d,%d",
hw, sw->info.freq, sw->info.bits, sw->info.nchannels);
dolog ("Added %s active = %d\n", sw->name, sw->active);
#endif
if (sw->active) {

View File

@@ -25,7 +25,7 @@
#define QEMU_AUDIO_H
#include "config-host.h"
#include "qemu/queue.h"
#include "qemu-queue.h"
typedef void (*audio_callback_fn) (void *opaque, int avail);

View File

@@ -23,7 +23,7 @@
*/
#include "qemu-common.h"
#include "audio.h"
#include "qemu/timer.h"
#include "qemu-timer.h"
#define AUDIO_CAP "noaudio"
#include "audio_int.h"

View File

@@ -31,8 +31,8 @@
#include <sys/soundcard.h>
#endif
#include "qemu-common.h"
#include "qemu/main-loop.h"
#include "qemu/host-utils.h"
#include "host-utils.h"
#include "qemu-char.h"
#include "audio.h"
#define AUDIO_CAP "oss"

View File

@@ -18,7 +18,7 @@
*/
#include "hw/hw.h"
#include "qemu/timer.h"
#include "qemu-timer.h"
#include "ui/qemu-spice.h"
#define AUDIO_CAP "spice"

View File

@@ -22,7 +22,7 @@
* THE SOFTWARE.
*/
#include "hw/hw.h"
#include "qemu/timer.h"
#include "qemu-timer.h"
#include "audio.h"
#define AUDIO_CAP "wav"

View File

@@ -1,5 +1,5 @@
#include "hw/hw.h"
#include "monitor/monitor.h"
#include "monitor.h"
#include "audio.h"
typedef struct {

View File

@@ -1,7 +1,7 @@
/* public domain */
#include "qemu-common.h"
#include "sysemu/sysemu.h"
#include "sysemu.h"
#include "audio.h"
#define AUDIO_CAP "winwave"

View File

@@ -1,2 +0,0 @@
common-obj-y += rng.o rng-egd.o
common-obj-$(CONFIG_POSIX) += rng-random.o

View File

@@ -1,224 +0,0 @@
/*
* QEMU Random Number Generator Backend
*
* Copyright IBM, Corp. 2012
*
* Authors:
* Anthony Liguori <aliguori@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.
*/
#include "qemu/rng.h"
#include "char/char.h"
#include "qapi/qmp/qerror.h"
#include "hw/qdev.h" /* just for DEFINE_PROP_CHR */
#define TYPE_RNG_EGD "rng-egd"
#define RNG_EGD(obj) OBJECT_CHECK(RngEgd, (obj), TYPE_RNG_EGD)
typedef struct RngEgd
{
RngBackend parent;
CharDriverState *chr;
char *chr_name;
GSList *requests;
} RngEgd;
typedef struct RngRequest
{
EntropyReceiveFunc *receive_entropy;
uint8_t *data;
void *opaque;
size_t offset;
size_t size;
} RngRequest;
static void rng_egd_request_entropy(RngBackend *b, size_t size,
EntropyReceiveFunc *receive_entropy,
void *opaque)
{
RngEgd *s = RNG_EGD(b);
RngRequest *req;
req = g_malloc(sizeof(*req));
req->offset = 0;
req->size = size;
req->receive_entropy = receive_entropy;
req->opaque = opaque;
req->data = g_malloc(req->size);
while (size > 0) {
uint8_t header[2];
uint8_t len = MIN(size, 255);
/* synchronous entropy request */
header[0] = 0x02;
header[1] = len;
qemu_chr_fe_write(s->chr, header, sizeof(header));
size -= len;
}
s->requests = g_slist_append(s->requests, req);
}
static void rng_egd_free_request(RngRequest *req)
{
g_free(req->data);
g_free(req);
}
static int rng_egd_chr_can_read(void *opaque)
{
RngEgd *s = RNG_EGD(opaque);
GSList *i;
int size = 0;
for (i = s->requests; i; i = i->next) {
RngRequest *req = i->data;
size += req->size - req->offset;
}
return size;
}
static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size)
{
RngEgd *s = RNG_EGD(opaque);
while (size > 0 && s->requests) {
RngRequest *req = s->requests->data;
int len = MIN(size, req->size - req->offset);
memcpy(req->data + req->offset, buf, len);
req->offset += len;
size -= len;
if (req->offset == req->size) {
s->requests = g_slist_remove_link(s->requests, s->requests);
req->receive_entropy(req->opaque, req->data, req->size);
rng_egd_free_request(req);
}
}
}
static void rng_egd_free_requests(RngEgd *s)
{
GSList *i;
for (i = s->requests; i; i = i->next) {
rng_egd_free_request(i->data);
}
g_slist_free(s->requests);
s->requests = NULL;
}
static void rng_egd_cancel_requests(RngBackend *b)
{
RngEgd *s = RNG_EGD(b);
/* We simply delete the list of pending requests. If there is data in the
* queue waiting to be read, this is okay, because there will always be
* more data than we requested originally
*/
rng_egd_free_requests(s);
}
static void rng_egd_opened(RngBackend *b, Error **errp)
{
RngEgd *s = RNG_EGD(b);
if (s->chr_name == NULL) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE,
"chardev", "a valid character device");
return;
}
s->chr = qemu_chr_find(s->chr_name);
if (s->chr == NULL) {
error_set(errp, QERR_DEVICE_NOT_FOUND, 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);
}
static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
{
RngBackend *b = RNG_BACKEND(obj);
RngEgd *s = RNG_EGD(b);
if (b->opened) {
error_set(errp, QERR_PERMISSION_DENIED);
} else {
g_free(s->chr_name);
s->chr_name = g_strdup(value);
}
}
static char *rng_egd_get_chardev(Object *obj, Error **errp)
{
RngEgd *s = RNG_EGD(obj);
if (s->chr && s->chr->label) {
return g_strdup(s->chr->label);
}
return NULL;
}
static void rng_egd_init(Object *obj)
{
object_property_add_str(obj, "chardev",
rng_egd_get_chardev, rng_egd_set_chardev,
NULL);
}
static void rng_egd_finalize(Object *obj)
{
RngEgd *s = RNG_EGD(obj);
if (s->chr) {
qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
}
g_free(s->chr_name);
rng_egd_free_requests(s);
}
static void rng_egd_class_init(ObjectClass *klass, void *data)
{
RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
rbc->request_entropy = rng_egd_request_entropy;
rbc->cancel_requests = rng_egd_cancel_requests;
rbc->opened = rng_egd_opened;
}
static const TypeInfo rng_egd_info = {
.name = TYPE_RNG_EGD,
.parent = TYPE_RNG_BACKEND,
.instance_size = sizeof(RngEgd),
.class_init = rng_egd_class_init,
.instance_init = rng_egd_init,
.instance_finalize = rng_egd_finalize,
};
static void register_types(void)
{
type_register_static(&rng_egd_info);
}
type_init(register_types);

View File

@@ -1,161 +0,0 @@
/*
* QEMU Random Number Generator Backend
*
* Copyright IBM, Corp. 2012
*
* Authors:
* Anthony Liguori <aliguori@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.
*/
#include "qemu/rng-random.h"
#include "qemu/rng.h"
#include "qapi/qmp/qerror.h"
#include "qemu/main-loop.h"
struct RndRandom
{
RngBackend parent;
int fd;
char *filename;
EntropyReceiveFunc *receive_func;
void *opaque;
size_t size;
};
/**
* A simple and incomplete backend to request entropy from /dev/random.
*
* This backend exposes an additional "filename" property that can be used to
* set the filename to use to open the backend.
*/
static void entropy_available(void *opaque)
{
RndRandom *s = RNG_RANDOM(opaque);
uint8_t buffer[s->size];
ssize_t len;
len = read(s->fd, buffer, s->size);
g_assert(len != -1);
s->receive_func(s->opaque, buffer, len);
s->receive_func = NULL;
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
}
static void rng_random_request_entropy(RngBackend *b, size_t size,
EntropyReceiveFunc *receive_entropy,
void *opaque)
{
RndRandom *s = RNG_RANDOM(b);
if (s->receive_func) {
s->receive_func(s->opaque, NULL, 0);
}
s->receive_func = receive_entropy;
s->opaque = opaque;
s->size = size;
qemu_set_fd_handler(s->fd, entropy_available, NULL, s);
}
static void rng_random_opened(RngBackend *b, Error **errp)
{
RndRandom *s = RNG_RANDOM(b);
if (s->filename == NULL) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE,
"filename", "a valid filename");
} else {
s->fd = open(s->filename, O_RDONLY | O_NONBLOCK);
if (s->fd == -1) {
error_set(errp, QERR_OPEN_FILE_FAILED, s->filename);
}
}
}
static char *rng_random_get_filename(Object *obj, Error **errp)
{
RndRandom *s = RNG_RANDOM(obj);
if (s->filename) {
return g_strdup(s->filename);
}
return NULL;
}
static void rng_random_set_filename(Object *obj, const char *filename,
Error **errp)
{
RngBackend *b = RNG_BACKEND(obj);
RndRandom *s = RNG_RANDOM(obj);
if (b->opened) {
error_set(errp, QERR_PERMISSION_DENIED);
return;
}
if (s->filename) {
g_free(s->filename);
}
s->filename = g_strdup(filename);
}
static void rng_random_init(Object *obj)
{
RndRandom *s = RNG_RANDOM(obj);
object_property_add_str(obj, "filename",
rng_random_get_filename,
rng_random_set_filename,
NULL);
s->filename = g_strdup("/dev/random");
}
static void rng_random_finalize(Object *obj)
{
RndRandom *s = RNG_RANDOM(obj);
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
if (s->fd != -1) {
close(s->fd);
}
g_free(s->filename);
}
static void rng_random_class_init(ObjectClass *klass, void *data)
{
RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
rbc->request_entropy = rng_random_request_entropy;
rbc->opened = rng_random_opened;
}
static const TypeInfo rng_random_info = {
.name = TYPE_RNG_RANDOM,
.parent = TYPE_RNG_BACKEND,
.instance_size = sizeof(RndRandom),
.class_init = rng_random_class_init,
.instance_init = rng_random_init,
.instance_finalize = rng_random_finalize,
};
static void register_types(void)
{
type_register_static(&rng_random_info);
}
type_init(register_types);

View File

@@ -1,93 +0,0 @@
/*
* QEMU Random Number Generator Backend
*
* Copyright IBM, Corp. 2012
*
* Authors:
* Anthony Liguori <aliguori@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.
*/
#include "qemu/rng.h"
#include "qapi/qmp/qerror.h"
void rng_backend_request_entropy(RngBackend *s, size_t size,
EntropyReceiveFunc *receive_entropy,
void *opaque)
{
RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
if (k->request_entropy) {
k->request_entropy(s, size, receive_entropy, opaque);
}
}
void rng_backend_cancel_requests(RngBackend *s)
{
RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
if (k->cancel_requests) {
k->cancel_requests(s);
}
}
static bool rng_backend_prop_get_opened(Object *obj, Error **errp)
{
RngBackend *s = RNG_BACKEND(obj);
return s->opened;
}
void rng_backend_open(RngBackend *s, Error **errp)
{
object_property_set_bool(OBJECT(s), true, "opened", errp);
}
static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
{
RngBackend *s = RNG_BACKEND(obj);
RngBackendClass *k = RNG_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 rng_backend_init(Object *obj)
{
object_property_add_bool(obj, "opened",
rng_backend_prop_get_opened,
rng_backend_prop_set_opened,
NULL);
}
static const TypeInfo rng_backend_info = {
.name = TYPE_RNG_BACKEND,
.parent = TYPE_OBJECT,
.instance_size = sizeof(RngBackend),
.instance_init = rng_backend_init,
.class_size = sizeof(RngBackendClass),
.abstract = true,
};
static void register_types(void)
{
type_register_static(&rng_backend_info);
}
type_init(register_types);

View File

@@ -24,13 +24,13 @@
* THE SOFTWARE.
*/
#include "monitor/monitor.h"
#include "exec/cpu-common.h"
#include "sysemu/kvm.h"
#include "sysemu/balloon.h"
#include "monitor.h"
#include "cpu-common.h"
#include "kvm.h"
#include "balloon.h"
#include "trace.h"
#include "qmp-commands.h"
#include "qapi/qmp/qjson.h"
#include "qjson.h"
static QEMUBalloonEvent *balloon_event_fn;
static QEMUBalloonStatus *balloon_stat_fn;

View File

@@ -14,7 +14,7 @@
#ifndef _QEMU_BALLOON_H
#define _QEMU_BALLOON_H
#include "monitor/monitor.h"
#include "monitor.h"
#include "qapi-types.h"
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);

View File

@@ -9,8 +9,8 @@
* Version 2.
*/
#include "qemu/bitops.h"
#include "qemu/bitmap.h"
#include "bitops.h"
#include "bitmap.h"
/*
* bitmaps provide an array of bits, implemented using an an

View File

@@ -13,7 +13,7 @@
#define BITMAP_H
#include "qemu-common.h"
#include "qemu/bitops.h"
#include "bitops.h"
/*
* The available bitmap operations and their rough meaning in the

View File

@@ -11,7 +11,7 @@
* 2 of the License, or (at your option) any later version.
*/
#include "qemu/bitops.h"
#include "bitops.h"
#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
@@ -60,7 +60,7 @@ found_first:
return result + size; /* Nope. */
}
found_middle:
return result + bitops_ctzl(tmp);
return result + bitops_ffsl(tmp);
}
/*
@@ -109,7 +109,7 @@ found_first:
return result + size; /* Nope. */
}
found_middle:
return result + bitops_ctol(tmp);
return result + ffz(tmp);
}
unsigned long find_last_bit(const unsigned long *addr, unsigned long size)

View File

@@ -13,7 +13,6 @@
#define BITOPS_H
#include "qemu-common.h"
#include "host-utils.h"
#define BITS_PER_BYTE CHAR_BIT
#define BITS_PER_LONG (sizeof (unsigned long) * BITS_PER_BYTE)
@@ -24,29 +23,41 @@
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
/**
* bitops_ctzl - count trailing zeroes in word.
* bitops_ffs - find first bit in word.
* @word: The word to search
*
* Returns -1 if no bit exists. Note that compared to the C library
* routine ffsl, this one returns one less.
* Undefined if no bit exists, so code should check against 0 first.
*/
static unsigned long bitops_ctzl(unsigned long word)
static unsigned long bitops_ffsl(unsigned long word)
{
#if QEMU_GNUC_PREREQ(3, 4)
return __builtin_ffsl(word) - 1;
#else
if (!word) {
return -1;
}
int num = 0;
if (sizeof(long) == 4) {
return ctz32(word);
} else if (sizeof(long) == 8) {
return ctz64(word);
} else {
abort();
}
#if LONG_MAX > 0x7FFFFFFF
if ((word & 0xffffffff) == 0) {
num += 32;
word >>= 32;
}
#endif
if ((word & 0xffff) == 0) {
num += 16;
word >>= 16;
}
if ((word & 0xff) == 0) {
num += 8;
word >>= 8;
}
if ((word & 0xf) == 0) {
num += 4;
word >>= 4;
}
if ((word & 0x3) == 0) {
num += 2;
word >>= 2;
}
if ((word & 0x1) == 0) {
num += 1;
}
return num;
}
/**
@@ -88,14 +99,14 @@ static inline unsigned long bitops_flsl(unsigned long word)
}
/**
* cto - count trailing ones in word.
* ffz - find first zero in word.
* @word: The word to search
*
* Returns -1 if all bit are set.
* Undefined if no zero exists, so code should check against ~0UL first.
*/
static inline unsigned long bitops_ctol(unsigned long word)
static inline unsigned long ffz(unsigned long word)
{
return bitops_ctzl(~word);
return bitops_ffsl(~word);
}
/**

View File

@@ -14,17 +14,16 @@
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "block_int.h"
#include "hw/hw.h"
#include "qemu/queue.h"
#include "qemu/timer.h"
#include "migration/block.h"
#include "migration/migration.h"
#include "sysemu/blockdev.h"
#include "qemu-queue.h"
#include "qemu-timer.h"
#include "block-migration.h"
#include "migration.h"
#include "blockdev.h"
#include <assert.h>
#define BLOCK_SIZE (1 << 20)
#define BDRV_SECTORS_PER_DIRTY_CHUNK (BLOCK_SIZE >> BDRV_SECTOR_BITS)
#define BLOCK_SIZE (BDRV_SECTORS_PER_DIRTY_CHUNK << BDRV_SECTOR_BITS)
#define BLK_MIG_FLAG_DEVICE_BLOCK 0x01
#define BLK_MIG_FLAG_EOS 0x02
@@ -78,7 +77,9 @@ typedef struct BlkMigState {
int64_t total_sector_sum;
int prev_progress;
int bulk_completed;
long double total_time;
long double prev_time_offset;
int reads;
} BlkMigState;
static BlkMigState block_mig_state;
@@ -131,6 +132,12 @@ uint64_t blk_mig_bytes_total(void)
return sum << BDRV_SECTOR_BITS;
}
static inline long double compute_read_bwidth(void)
{
assert(block_mig_state.total_time != 0);
return (block_mig_state.reads / block_mig_state.total_time) * BLOCK_SIZE;
}
static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
{
int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
@@ -184,6 +191,8 @@ static void blk_mig_read_cb(void *opaque, int ret)
blk->ret = ret;
block_mig_state.reads++;
block_mig_state.total_time += (curr_time - block_mig_state.prev_time_offset);
block_mig_state.prev_time_offset = curr_time;
QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
@@ -255,7 +264,7 @@ static void set_dirty_tracking(int enable)
BlkMigDevState *bmds;
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
bdrv_set_dirty_tracking(bmds->bs, enable ? BLOCK_SIZE : 0);
bdrv_set_dirty_tracking(bmds->bs, enable);
}
}
@@ -301,6 +310,8 @@ static void init_blk_migration(QEMUFile *f)
block_mig_state.total_sector_sum = 0;
block_mig_state.prev_progress = -1;
block_mig_state.bulk_completed = 0;
block_mig_state.total_time = 0;
block_mig_state.reads = 0;
bdrv_iterate(init_blk_migration_it, NULL);
}
@@ -412,23 +423,20 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
error:
DPRINTF("Error reading sector %" PRId64 "\n", sector);
qemu_file_set_error(f, ret);
g_free(blk->buf);
g_free(blk);
return ret;
return 0;
}
/* return value:
* 0: too much data for max_downtime
* 1: few enough data for max_downtime
*/
static int blk_mig_save_dirty_block(QEMUFile *f, int is_async)
{
BlkMigDevState *bmds;
int ret = 1;
int ret = 0;
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
ret = mig_save_device_dirty(f, bmds, is_async);
if (ret <= 0) {
if (mig_save_device_dirty(f, bmds, is_async) == 0) {
ret = 1;
break;
}
}
@@ -436,10 +444,9 @@ static int blk_mig_save_dirty_block(QEMUFile *f, int is_async)
return ret;
}
static int flush_blks(QEMUFile *f)
static void flush_blks(QEMUFile* f)
{
BlkMigBlock *blk;
int ret = 0;
DPRINTF("%s Enter submitted %d read_done %d transferred %d\n",
__FUNCTION__, block_mig_state.submitted, block_mig_state.read_done,
@@ -450,7 +457,7 @@ static int flush_blks(QEMUFile *f)
break;
}
if (blk->ret < 0) {
ret = blk->ret;
qemu_file_set_error(f, blk->ret);
break;
}
blk_send(f, blk);
@@ -467,7 +474,6 @@ static int flush_blks(QEMUFile *f)
DPRINTF("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__,
block_mig_state.submitted, block_mig_state.read_done,
block_mig_state.transferred);
return ret;
}
static int64_t get_remaining_dirty(void)
@@ -479,7 +485,33 @@ static int64_t get_remaining_dirty(void)
dirty += bdrv_get_dirty_count(bmds->bs);
}
return dirty << BDRV_SECTOR_BITS;
return dirty * BLOCK_SIZE;
}
static int is_stage2_completed(void)
{
int64_t remaining_dirty;
long double bwidth;
if (block_mig_state.bulk_completed == 1) {
remaining_dirty = get_remaining_dirty();
if (remaining_dirty == 0) {
return 1;
}
bwidth = compute_read_bwidth();
if ((remaining_dirty / bwidth) <=
migrate_max_downtime()) {
/* finish stage2 because we think that we can finish remaining work
below max_downtime */
return 1;
}
}
return 0;
}
static void blk_mig_cleanup(void)
@@ -487,8 +519,6 @@ static void blk_mig_cleanup(void)
BlkMigDevState *bmds;
BlkMigBlock *blk;
bdrv_drain_all();
set_dirty_tracking(0);
while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
@@ -523,7 +553,9 @@ static int block_save_setup(QEMUFile *f, void *opaque)
/* start track dirty blocks */
set_dirty_tracking(1);
ret = flush_blks(f);
flush_blks(f);
ret = qemu_file_get_error(f);
if (ret) {
blk_mig_cleanup();
return ret;
@@ -539,12 +571,13 @@ static int block_save_setup(QEMUFile *f, void *opaque)
static int block_save_iterate(QEMUFile *f, void *opaque)
{
int ret;
int64_t last_ftell = qemu_ftell(f);
DPRINTF("Enter save live iterate submitted %d transferred %d\n",
block_mig_state.submitted, block_mig_state.transferred);
ret = flush_blks(f);
flush_blks(f);
ret = qemu_file_get_error(f);
if (ret) {
blk_mig_cleanup();
return ret;
@@ -563,19 +596,16 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
block_mig_state.bulk_completed = 1;
}
} else {
ret = blk_mig_save_dirty_block(f, 1);
if (ret != 0) {
if (blk_mig_save_dirty_block(f, 1) == 0) {
/* no more dirty blocks */
break;
}
}
}
if (ret < 0) {
blk_mig_cleanup();
return ret;
}
ret = flush_blks(f);
flush_blks(f);
ret = qemu_file_get_error(f);
if (ret) {
blk_mig_cleanup();
return ret;
@@ -583,7 +613,7 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
return qemu_ftell(f) - last_ftell;
return is_stage2_completed();
}
static int block_save_complete(QEMUFile *f, void *opaque)
@@ -593,7 +623,9 @@ static int block_save_complete(QEMUFile *f, void *opaque)
DPRINTF("Enter save live complete submitted %d transferred %d\n",
block_mig_state.submitted, block_mig_state.transferred);
ret = flush_blks(f);
flush_blks(f);
ret = qemu_file_get_error(f);
if (ret) {
blk_mig_cleanup();
return ret;
@@ -605,17 +637,19 @@ static int block_save_complete(QEMUFile *f, void *opaque)
all async read completed */
assert(block_mig_state.submitted == 0);
do {
ret = blk_mig_save_dirty_block(f, 0);
} while (ret == 0);
blk_mig_cleanup();
if (ret < 0) {
return ret;
while (blk_mig_save_dirty_block(f, 0) != 0) {
/* Do nothing */
}
blk_mig_cleanup();
/* report completion */
qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);
ret = qemu_file_get_error(f);
if (ret) {
return ret;
}
DPRINTF("Block migration completed\n");
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
@@ -623,22 +657,6 @@ static int block_save_complete(QEMUFile *f, void *opaque)
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 = get_remaining_dirty() +
block_mig_state.submitted * BLOCK_SIZE +
block_mig_state.read_done * BLOCK_SIZE;
/* Report at least one block pending during bulk phase */
if (pending == 0 && !block_mig_state.bulk_completed) {
pending = BLOCK_SIZE;
}
DPRINTF("Enter save live pending %" PRIu64 "\n", pending);
return pending;
}
static int block_load(QEMUFile *f, void *opaque, int version_id)
{
static int banner_printed;
@@ -704,7 +722,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
(addr == 100) ? '\n' : '\r');
fflush(stdout);
} else if (!(flags & BLK_MIG_FLAG_EOS)) {
fprintf(stderr, "Unknown block migration flags: %#x\n", flags);
fprintf(stderr, "Unknown flags\n");
return -EINVAL;
}
ret = qemu_file_get_error(f);
@@ -735,7 +753,6 @@ SaveVMHandlers savevm_block_handlers = {
.save_live_setup = block_save_setup,
.save_live_iterate = block_save_iterate,
.save_live_complete = block_save_complete,
.save_live_pending = block_save_pending,
.load_state = block_load,
.cancel = block_migration_cancel,
.is_active = block_is_active,

1332
block.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,14 @@
#ifndef BLOCK_H
#define BLOCK_H
#include "block/aio.h"
#include "qemu-aio.h"
#include "qemu-common.h"
#include "qemu/option.h"
#include "block/coroutine.h"
#include "qapi/qmp/qobject.h"
#include "qapi-types.h"
#include "qemu-option.h"
#include "qemu-coroutine.h"
#include "qobject.h"
/* block.c */
typedef struct BlockDriver BlockDriver;
typedef struct BlockJob BlockJob;
typedef struct BlockDriverInfo {
/* in bytes, 0 if irrelevant */
@@ -91,23 +89,21 @@ typedef struct BlockDevOps {
#define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1)
typedef enum {
BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP
BLOCK_ERR_REPORT, BLOCK_ERR_IGNORE, BLOCK_ERR_STOP_ENOSPC,
BLOCK_ERR_STOP_ANY
} BlockErrorAction;
typedef QSIMPLEQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue;
typedef struct BDRVReopenState {
BlockDriverState *bs;
int flags;
void *opaque;
} BDRVReopenState;
typedef enum {
BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP
} BlockQMPEventAction;
void bdrv_iostatus_enable(BlockDriverState *bs);
void bdrv_iostatus_reset(BlockDriverState *bs);
void bdrv_iostatus_disable(BlockDriverState *bs);
bool bdrv_iostatus_is_enabled(const BlockDriverState *bs);
void bdrv_iostatus_set_err(BlockDriverState *bs, int error);
void bdrv_emit_qmp_error_event(const BlockDriverState *bdrv,
BlockQMPEventAction action, int is_read);
void bdrv_info_print(Monitor *mon, const QObject *data);
void bdrv_info(Monitor *mon, QObject **ret_data);
void bdrv_stats_print(Monitor *mon, const QObject *data);
@@ -133,19 +129,9 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
void bdrv_delete(BlockDriverState *bs);
int bdrv_parse_cache_flags(const char *mode, int *flags);
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
int bdrv_open_backing_file(BlockDriverState *bs);
int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
BlockDriver *drv);
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
BlockDriverState *bs, int flags);
int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp);
int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
BlockReopenQueue *queue, Error **errp);
void bdrv_reopen_commit(BDRVReopenState *reopen_state);
void bdrv_reopen_abort(BDRVReopenState *reopen_state);
void bdrv_close(BlockDriverState *bs);
void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify);
int bdrv_attach_dev(BlockDriverState *bs, void *dev);
void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev);
void bdrv_detach_dev(BlockDriverState *bs, void *dev);
@@ -200,11 +186,6 @@ int bdrv_commit_all(void);
int bdrv_change_backing_file(BlockDriverState *bs,
const char *backing_file, const char *backing_fmt);
void bdrv_register(BlockDriver *bdrv);
int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
BlockDriverState *base);
BlockDriverState *bdrv_find_overlay(BlockDriverState *active,
BlockDriverState *bs);
BlockDriverState *bdrv_find_base(BlockDriverState *bs);
typedef struct BdrvCheckResult {
@@ -279,12 +260,9 @@ int bdrv_has_zero_init(BlockDriverState *bs);
int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
int *pnum);
void bdrv_set_on_error(BlockDriverState *bs, BlockdevOnError on_read_error,
BlockdevOnError on_write_error);
BlockdevOnError bdrv_get_on_error(BlockDriverState *bs, bool is_read);
BlockErrorAction bdrv_get_error_action(BlockDriverState *bs, bool is_read, int error);
void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action,
bool is_read, int error);
void bdrv_set_on_error(BlockDriverState *bs, BlockErrorAction on_read_error,
BlockErrorAction on_write_error);
BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read);
int bdrv_is_read_only(BlockDriverState *bs);
int bdrv_is_sg(BlockDriverState *bs);
int bdrv_enable_write_cache(BlockDriverState *bs);
@@ -309,18 +287,12 @@ int bdrv_get_flags(BlockDriverState *bs);
int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
void bdrv_round_to_clusters(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
int64_t *cluster_sector_num,
int *cluster_nb_sectors);
const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
void bdrv_get_backing_filename(BlockDriverState *bs,
char *filename, int filename_size);
void bdrv_get_full_backing_filename(BlockDriverState *bs,
char *dest, size_t sz);
BlockInfo *bdrv_query_info(BlockDriverState *s);
BlockStats *bdrv_query_stats(const BlockDriverState *bs);
int bdrv_can_snapshot(BlockDriverState *bs);
int bdrv_is_snapshot(BlockDriverState *bs);
BlockDriverState *bdrv_snapshots(void);
@@ -347,20 +319,19 @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
int64_t pos, int size);
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);
int 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);
void bdrv_set_buffer_alignment(BlockDriverState *bs, int align);
void *qemu_blockalign(BlockDriverState *bs, size_t size);
bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov);
struct HBitmapIter;
void bdrv_set_dirty_tracking(BlockDriverState *bs, int granularity);
#define BDRV_SECTORS_PER_DIRTY_CHUNK 2048
void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
int bdrv_get_dirty(BlockDriverState *bs, int64_t sector);
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
void bdrv_dirty_iter_init(BlockDriverState *bs, struct HBitmapIter *hbi);
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
int nr_sectors);
int64_t bdrv_get_dirty_count(BlockDriverState *bs);
void bdrv_enable_copy_on_read(BlockDriverState *bs);
@@ -369,15 +340,6 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs);
void bdrv_set_in_use(BlockDriverState *bs, int in_use);
int bdrv_in_use(BlockDriverState *bs);
#ifdef CONFIG_LINUX_AIO
int raw_get_aio_fd(BlockDriverState *bs);
#else
static inline int raw_get_aio_fd(BlockDriverState *bs)
{
return -ENOTSUP;
}
#endif
enum BlockAcctType {
BDRV_ACCT_READ,
BDRV_ACCT_WRITE,
@@ -444,9 +406,4 @@ typedef enum {
#define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt)
void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event);
int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
const char *tag);
int bdrv_debug_resume(BlockDriverState *bs, const char *tag);
bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag);
#endif

View File

@@ -2,21 +2,10 @@ 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 += parallels.o blkdebug.o blkverify.o
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
block-obj-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
block-obj-y += stream.o
block-obj-$(CONFIG_WIN32) += raw-win32.o
block-obj-$(CONFIG_POSIX) += raw-posix.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
ifeq ($(CONFIG_POSIX),y)
block-obj-y += nbd.o sheepdog.o
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
block-obj-$(CONFIG_CURL) += curl.o
block-obj-$(CONFIG_RBD) += rbd.o
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
endif
common-obj-y += stream.o
common-obj-y += commit.o
common-obj-y += mirror.o
$(obj)/curl.o: QEMU_CFLAGS+=$(CURL_CFLAGS)

View File

@@ -23,17 +23,13 @@
*/
#include "qemu-common.h"
#include "qemu/config-file.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "block_int.h"
#include "module.h"
typedef struct BDRVBlkdebugState {
int state;
int new_state;
QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
} BDRVBlkdebugState;
typedef struct BlkdebugAIOCB {
@@ -42,15 +38,9 @@ typedef struct BlkdebugAIOCB {
int ret;
} BlkdebugAIOCB;
typedef struct BlkdebugSuspendedReq {
Coroutine *co;
char *tag;
QLIST_ENTRY(BlkdebugSuspendedReq) next;
} BlkdebugSuspendedReq;
static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb);
static const AIOCBInfo blkdebug_aiocb_info = {
static AIOPool blkdebug_aio_pool = {
.aiocb_size = sizeof(BlkdebugAIOCB),
.cancel = blkdebug_aio_cancel,
};
@@ -58,7 +48,6 @@ static const AIOCBInfo blkdebug_aiocb_info = {
enum {
ACTION_INJECT_ERROR,
ACTION_SET_STATE,
ACTION_SUSPEND,
};
typedef struct BlkdebugRule {
@@ -75,9 +64,6 @@ typedef struct BlkdebugRule {
struct {
int new_state;
} set_state;
struct {
char *tag;
} suspend;
} options;
QLIST_ENTRY(BlkdebugRule) next;
QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
@@ -239,11 +225,6 @@ static int add_rule(QemuOpts *opts, void *opaque)
rule->options.set_state.new_state =
qemu_opt_get_number(opts, "new_state", 0);
break;
case ACTION_SUSPEND:
rule->options.suspend.tag =
g_strdup(qemu_opt_get(opts, "tag"));
break;
};
/* Add the rule */
@@ -252,32 +233,12 @@ static int add_rule(QemuOpts *opts, void *opaque)
return 0;
}
static void remove_rule(BlkdebugRule *rule)
{
switch (rule->action) {
case ACTION_INJECT_ERROR:
case ACTION_SET_STATE:
break;
case ACTION_SUSPEND:
g_free(rule->options.suspend.tag);
break;
}
QLIST_REMOVE(rule, next);
g_free(rule);
}
static int read_config(BDRVBlkdebugState *s, const char *filename)
{
FILE *f;
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;
@@ -373,7 +334,7 @@ static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
return NULL;
}
acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque);
acb->ret = -error;
bh = qemu_bh_new(error_callback_bh, acb);
@@ -427,7 +388,6 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
}
static void blkdebug_close(BlockDriverState *bs)
{
BDRVBlkdebugState *s = bs->opaque;
@@ -436,39 +396,19 @@ static void blkdebug_close(BlockDriverState *bs)
for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
remove_rule(rule);
QLIST_REMOVE(rule, next);
g_free(rule);
}
}
}
static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
{
BDRVBlkdebugState *s = bs->opaque;
BlkdebugSuspendedReq r;
r = (BlkdebugSuspendedReq) {
.co = qemu_coroutine_self(),
.tag = g_strdup(rule->options.suspend.tag),
};
remove_rule(rule);
QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);
printf("blkdebug: Suspended request '%s'\n", r.tag);
qemu_coroutine_yield();
printf("blkdebug: Resuming request '%s'\n", r.tag);
QLIST_REMOVE(&r, next);
g_free(r.tag);
}
static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
bool injected)
int old_state, bool injected)
{
BDRVBlkdebugState *s = bs->opaque;
/* Only process rules for the current state */
if (rule->state && rule->state != s->state) {
if (rule->state && rule->state != old_state) {
return injected;
}
@@ -483,11 +423,7 @@ static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
break;
case ACTION_SET_STATE:
s->new_state = rule->options.set_state.new_state;
break;
case ACTION_SUSPEND:
suspend_request(bs, rule);
s->state = rule->options.set_state.new_state;
break;
}
return injected;
@@ -496,70 +432,16 @@ static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
{
BDRVBlkdebugState *s = bs->opaque;
struct BlkdebugRule *rule, *next;
struct BlkdebugRule *rule;
int old_state = s->state;
bool injected;
assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
injected = false;
s->new_state = s->state;
QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
injected = process_rule(bs, rule, injected);
QLIST_FOREACH(rule, &s->rules[event], next) {
injected = process_rule(bs, rule, old_state, injected);
}
s->state = s->new_state;
}
static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
const char *tag)
{
BDRVBlkdebugState *s = bs->opaque;
struct BlkdebugRule *rule;
BlkDebugEvent blkdebug_event;
if (get_event_by_name(event, &blkdebug_event) < 0) {
return -ENOENT;
}
rule = g_malloc(sizeof(*rule));
*rule = (struct BlkdebugRule) {
.event = blkdebug_event,
.action = ACTION_SUSPEND,
.state = 0,
.options.suspend.tag = g_strdup(tag),
};
QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);
return 0;
}
static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
{
BDRVBlkdebugState *s = bs->opaque;
BlkdebugSuspendedReq *r;
QLIST_FOREACH(r, &s->suspended_reqs, next) {
if (!strcmp(r->tag, tag)) {
qemu_coroutine_enter(r->co, NULL);
return 0;
}
}
return -ENOENT;
}
static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
{
BDRVBlkdebugState *s = bs->opaque;
BlkdebugSuspendedReq *r;
QLIST_FOREACH(r, &s->suspended_reqs, next) {
if (!strcmp(r->tag, tag)) {
return true;
}
}
return false;
}
static int64_t blkdebug_getlength(BlockDriverState *bs)
@@ -580,10 +462,7 @@ static BlockDriver bdrv_blkdebug = {
.bdrv_aio_readv = blkdebug_aio_readv,
.bdrv_aio_writev = blkdebug_aio_writev,
.bdrv_debug_event = blkdebug_debug_event,
.bdrv_debug_breakpoint = blkdebug_debug_breakpoint,
.bdrv_debug_resume = blkdebug_debug_resume,
.bdrv_debug_is_suspended = blkdebug_debug_is_suspended,
.bdrv_debug_event = blkdebug_debug_event,
};
static void bdrv_blkdebug_init(void)

View File

@@ -8,8 +8,8 @@
*/
#include <stdarg.h>
#include "qemu/sockets.h" /* for EINPROGRESS on Windows */
#include "block/block_int.h"
#include "qemu_socket.h" /* for EINPROGRESS on Windows */
#include "block_int.h"
typedef struct {
BlockDriverState *test_file;
@@ -48,7 +48,7 @@ static void blkverify_aio_cancel(BlockDriverAIOCB *blockacb)
}
}
static const AIOCBInfo blkverify_aiocb_info = {
static AIOPool blkverify_aio_pool = {
.aiocb_size = sizeof(BlkverifyAIOCB),
.cancel = blkverify_aio_cancel,
};
@@ -233,7 +233,7 @@ static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
BlockDriverCompletionFunc *cb,
void *opaque)
{
BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque);
BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aio_pool, bs, cb, opaque);
acb->bh = NULL;
acb->is_write = is_write;

View File

@@ -23,8 +23,8 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "block_int.h"
#include "module.h"
/**************************************************************/
@@ -114,13 +114,11 @@ static int bochs_open(BlockDriverState *bs, int flags)
int i;
struct bochs_header bochs;
struct bochs_header_v1 header_v1;
int ret;
bs->read_only = 1; // no write support yet
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
if (ret < 0) {
return ret;
if (bdrv_pread(bs->file, 0, &bochs, sizeof(bochs)) != sizeof(bochs)) {
goto fail;
}
if (strcmp(bochs.magic, HEADER_MAGIC) ||
@@ -128,7 +126,7 @@ static int bochs_open(BlockDriverState *bs, int flags)
strcmp(bochs.subtype, GROWING_TYPE) ||
((le32_to_cpu(bochs.version) != HEADER_VERSION) &&
(le32_to_cpu(bochs.version) != HEADER_V1))) {
return -EMEDIUMTYPE;
goto fail;
}
if (le32_to_cpu(bochs.version) == HEADER_V1) {
@@ -140,13 +138,9 @@ static int bochs_open(BlockDriverState *bs, int flags)
s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
s->catalog_size * 4);
if (ret < 0) {
goto fail;
}
if (bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
s->catalog_size * 4) != s->catalog_size * 4)
goto fail;
for (i = 0; i < s->catalog_size; i++)
le32_to_cpus(&s->catalog_bitmap[i]);
@@ -159,10 +153,8 @@ static int bochs_open(BlockDriverState *bs, int flags)
qemu_co_mutex_init(&s->lock);
return 0;
fail:
g_free(s->catalog_bitmap);
return ret;
fail:
return -1;
}
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)

View File

@@ -22,8 +22,8 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "block_int.h"
#include "module.h"
#include <zlib.h>
typedef struct BDRVCloopState {
@@ -57,32 +57,27 @@ static int cloop_open(BlockDriverState *bs, int flags)
{
BDRVCloopState *s = bs->opaque;
uint32_t offsets_size, max_compressed_block_size = 1, i;
int ret;
bs->read_only = 1;
/* read header */
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
if (ret < 0) {
return ret;
if (bdrv_pread(bs->file, 128, &s->block_size, 4) < 4) {
goto cloop_close;
}
s->block_size = be32_to_cpu(s->block_size);
ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
if (ret < 0) {
return ret;
if (bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4) < 4) {
goto cloop_close;
}
s->n_blocks = be32_to_cpu(s->n_blocks);
/* read offsets */
offsets_size = s->n_blocks * sizeof(uint64_t);
s->offsets = g_malloc(offsets_size);
ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
if (ret < 0) {
goto fail;
if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) <
offsets_size) {
goto cloop_close;
}
for(i=0;i<s->n_blocks;i++) {
s->offsets[i] = be64_to_cpu(s->offsets[i]);
if (i > 0) {
@@ -97,8 +92,7 @@ static int cloop_open(BlockDriverState *bs, int flags)
s->compressed_block = g_malloc(max_compressed_block_size + 1);
s->uncompressed_block = g_malloc(s->block_size);
if (inflateInit(&s->zstream) != Z_OK) {
ret = -EINVAL;
goto fail;
goto cloop_close;
}
s->current_block = s->n_blocks;
@@ -107,11 +101,8 @@ static int cloop_open(BlockDriverState *bs, int flags)
qemu_co_mutex_init(&s->lock);
return 0;
fail:
g_free(s->offsets);
g_free(s->compressed_block);
g_free(s->uncompressed_block);
return ret;
cloop_close:
return -1;
}
static inline int cloop_read_block(BlockDriverState *bs, int block_num)

View File

@@ -1,258 +0,0 @@
/*
* Live block commit
*
* Copyright Red Hat, Inc. 2012
*
* Authors:
* Jeff Cody <jcody@redhat.com>
* Based on stream.c by Stefan Hajnoczi
*
* 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 "trace.h"
#include "block/block_int.h"
#include "block/blockjob.h"
#include "qemu/ratelimit.h"
enum {
/*
* Size of data buffer for populating the image file. This should be large
* enough to process multiple clusters in a single call, so that populating
* contiguous regions of the image is efficient.
*/
COMMIT_BUFFER_SIZE = 512 * 1024, /* in bytes */
};
#define SLICE_TIME 100000000ULL /* ns */
typedef struct CommitBlockJob {
BlockJob common;
RateLimit limit;
BlockDriverState *active;
BlockDriverState *top;
BlockDriverState *base;
BlockdevOnError on_error;
int base_flags;
int orig_overlay_flags;
} CommitBlockJob;
static int coroutine_fn commit_populate(BlockDriverState *bs,
BlockDriverState *base,
int64_t sector_num, int nb_sectors,
void *buf)
{
int ret = 0;
ret = bdrv_read(bs, sector_num, buf, nb_sectors);
if (ret) {
return ret;
}
ret = bdrv_write(base, sector_num, buf, nb_sectors);
if (ret) {
return ret;
}
return 0;
}
static void coroutine_fn commit_run(void *opaque)
{
CommitBlockJob *s = opaque;
BlockDriverState *active = s->active;
BlockDriverState *top = s->top;
BlockDriverState *base = s->base;
BlockDriverState *overlay_bs;
int64_t sector_num, end;
int ret = 0;
int n = 0;
void *buf;
int bytes_written = 0;
int64_t base_len;
ret = s->common.len = bdrv_getlength(top);
if (s->common.len < 0) {
goto exit_restore_reopen;
}
ret = base_len = bdrv_getlength(base);
if (base_len < 0) {
goto exit_restore_reopen;
}
if (base_len < s->common.len) {
ret = bdrv_truncate(base, s->common.len);
if (ret) {
goto exit_restore_reopen;
}
}
end = s->common.len >> BDRV_SECTOR_BITS;
buf = qemu_blockalign(top, COMMIT_BUFFER_SIZE);
for (sector_num = 0; sector_num < end; sector_num += n) {
uint64_t delay_ns = 0;
bool copy;
wait:
/* Note that even when no rate limit is applied we need to yield
* with no pending I/O here so that bdrv_drain_all() returns.
*/
block_job_sleep_ns(&s->common, rt_clock, delay_ns);
if (block_job_is_cancelled(&s->common)) {
break;
}
/* Copy if allocated above the base */
ret = bdrv_co_is_allocated_above(top, base, sector_num,
COMMIT_BUFFER_SIZE / BDRV_SECTOR_SIZE,
&n);
copy = (ret == 1);
trace_commit_one_iteration(s, sector_num, n, ret);
if (copy) {
if (s->common.speed) {
delay_ns = ratelimit_calculate_delay(&s->limit, n);
if (delay_ns > 0) {
goto wait;
}
}
ret = commit_populate(top, base, sector_num, n, buf);
bytes_written += n * BDRV_SECTOR_SIZE;
}
if (ret < 0) {
if (s->on_error == BLOCKDEV_ON_ERROR_STOP ||
s->on_error == BLOCKDEV_ON_ERROR_REPORT||
(s->on_error == BLOCKDEV_ON_ERROR_ENOSPC && ret == -ENOSPC)) {
goto exit_free_buf;
} else {
n = 0;
continue;
}
}
/* Publish progress */
s->common.offset += n * BDRV_SECTOR_SIZE;
}
ret = 0;
if (!block_job_is_cancelled(&s->common) && sector_num == end) {
/* success */
ret = bdrv_drop_intermediate(active, top, base);
}
exit_free_buf:
qemu_vfree(buf);
exit_restore_reopen:
/* restore base open flags here if appropriate (e.g., change the base back
* to r/o). These reopens do not need to be atomic, since we won't abort
* even on failure here */
if (s->base_flags != bdrv_get_flags(base)) {
bdrv_reopen(base, s->base_flags, NULL);
}
overlay_bs = bdrv_find_overlay(active, top);
if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) {
bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL);
}
block_job_completed(&s->common, ret);
}
static void commit_set_speed(BlockJob *job, int64_t speed, Error **errp)
{
CommitBlockJob *s = container_of(job, CommitBlockJob, common);
if (speed < 0) {
error_set(errp, QERR_INVALID_PARAMETER, "speed");
return;
}
ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME);
}
static BlockJobType commit_job_type = {
.instance_size = sizeof(CommitBlockJob),
.job_type = "commit",
.set_speed = commit_set_speed,
};
void commit_start(BlockDriverState *bs, BlockDriverState *base,
BlockDriverState *top, int64_t speed,
BlockdevOnError on_error, BlockDriverCompletionFunc *cb,
void *opaque, Error **errp)
{
CommitBlockJob *s;
BlockReopenQueue *reopen_queue = NULL;
int orig_overlay_flags;
int orig_base_flags;
BlockDriverState *overlay_bs;
Error *local_err = NULL;
if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
on_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
!bdrv_iostatus_is_enabled(bs)) {
error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
return;
}
/* Once we support top == active layer, remove this check */
if (top == bs) {
error_setg(errp,
"Top image as the active layer is currently unsupported");
return;
}
if (top == base) {
error_setg(errp, "Invalid files for merge: top and base are the same");
return;
}
overlay_bs = bdrv_find_overlay(bs, top);
if (overlay_bs == NULL) {
error_setg(errp, "Could not find overlay image for %s:", top->filename);
return;
}
orig_base_flags = bdrv_get_flags(base);
orig_overlay_flags = bdrv_get_flags(overlay_bs);
/* convert base & overlay_bs to r/w, if necessary */
if (!(orig_base_flags & BDRV_O_RDWR)) {
reopen_queue = bdrv_reopen_queue(reopen_queue, base,
orig_base_flags | BDRV_O_RDWR);
}
if (!(orig_overlay_flags & BDRV_O_RDWR)) {
reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs,
orig_overlay_flags | BDRV_O_RDWR);
}
if (reopen_queue) {
bdrv_reopen_multiple(reopen_queue, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
}
s = block_job_create(&commit_job_type, bs, speed, cb, opaque, errp);
if (!s) {
return;
}
s->base = base;
s->top = top;
s->active = bs;
s->base_flags = orig_base_flags;
s->orig_overlay_flags = orig_overlay_flags;
s->on_error = on_error;
s->common.co = qemu_coroutine_create(commit_run);
trace_commit_start(bs, base, top, s, s->common.co, opaque);
qemu_coroutine_enter(s->common.co, s);
}

View File

@@ -22,8 +22,8 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "block_int.h"
#include "module.h"
/**************************************************************/
/* COW block driver using file system holes */
@@ -73,7 +73,7 @@ static int cow_open(BlockDriverState *bs, int flags)
}
if (be32_to_cpu(cow_header.magic) != COW_MAGIC) {
ret = -EMEDIUMTYPE;
ret = -EINVAL;
goto fail;
}

View File

@@ -22,7 +22,7 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "block_int.h"
#include <curl/curl.h>
// #define DEBUG
@@ -34,10 +34,6 @@
#define DPRINTF(fmt, ...) do { } while (0)
#endif
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
CURLPROTO_FTP | CURLPROTO_FTPS | \
CURLPROTO_TFTP)
#define CURL_NUM_STATES 8
#define CURL_NUM_ACB 8
#define SECTOR_SIZE 512
@@ -306,17 +302,6 @@ static CURLState *curl_init_state(BDRVCURLState *s)
curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
/* Restrict supported protocols to avoid security issues in the more
* obscure protocols. For example, do not allow POP3/SMTP/IMAP see
* CVE-2013-0249.
*
* Restricting protocols is only supported from 7.19.4 upwards.
*/
#if LIBCURL_VERSION_NUM >= 0x071304
curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
#endif
#ifdef DEBUG_VERBOSE
curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
#endif
@@ -453,7 +438,7 @@ static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
// Do we have to implement canceling? Seems to work without...
}
static const AIOCBInfo curl_aiocb_info = {
static AIOPool curl_aio_pool = {
.aiocb_size = sizeof(CURLAIOCB),
.cancel = curl_aio_cancel,
};
@@ -520,7 +505,7 @@ static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
{
CURLAIOCB *acb;
acb = qemu_aio_get(&curl_aiocb_info, bs, cb, opaque);
acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
acb->qiov = qiov;
acb->sector_num = sector_num;

View File

@@ -22,9 +22,9 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "qemu/bswap.h"
#include "qemu/module.h"
#include "block_int.h"
#include "bswap.h"
#include "module.h"
#include <zlib.h>
typedef struct BDRVDMGState {
@@ -57,42 +57,29 @@ static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result)
static off_t read_off(BlockDriverState *bs, int64_t offset)
{
uint64_t buffer;
int ret;
ret = bdrv_pread(bs->file, offset, &buffer, 8);
if (ret < 0) {
return ret;
}
*result = be64_to_cpu(buffer);
return 0;
uint64_t buffer;
if (bdrv_pread(bs->file, offset, &buffer, 8) < 8)
return 0;
return be64_to_cpu(buffer);
}
static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
static off_t read_uint32(BlockDriverState *bs, int64_t offset)
{
uint32_t buffer;
int ret;
ret = bdrv_pread(bs->file, offset, &buffer, 4);
if (ret < 0) {
return ret;
}
*result = be32_to_cpu(buffer);
return 0;
uint32_t buffer;
if (bdrv_pread(bs->file, offset, &buffer, 4) < 4)
return 0;
return be32_to_cpu(buffer);
}
static int dmg_open(BlockDriverState *bs, int flags)
{
BDRVDMGState *s = bs->opaque;
uint64_t info_begin,info_end,last_in_offset,last_out_offset;
uint32_t count, tmp;
off_t info_begin,info_end,last_in_offset,last_out_offset;
uint32_t count;
uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
int64_t offset;
int ret;
bs->read_only = 1;
s->n_chunks = 0;
@@ -101,32 +88,21 @@ static int dmg_open(BlockDriverState *bs, int flags)
/* read offset of info blocks */
offset = bdrv_getlength(bs->file);
if (offset < 0) {
ret = offset;
goto fail;
}
offset -= 0x1d8;
ret = read_uint64(bs, offset, &info_begin);
if (ret < 0) {
goto fail;
} else if (info_begin == 0) {
ret = -EINVAL;
info_begin = read_off(bs, offset);
if (info_begin == 0) {
goto fail;
}
if (read_uint32(bs, info_begin) != 0x100) {
goto fail;
}
ret = read_uint32(bs, info_begin, &tmp);
if (ret < 0) {
goto fail;
} else if (tmp != 0x100) {
ret = -EINVAL;
goto fail;
}
ret = read_uint32(bs, info_begin + 4, &count);
if (ret < 0) {
goto fail;
} else if (count == 0) {
ret = -EINVAL;
count = read_uint32(bs, info_begin + 4);
if (count == 0) {
goto fail;
}
info_end = info_begin + count;
@@ -138,20 +114,12 @@ static int dmg_open(BlockDriverState *bs, int flags)
while (offset < info_end) {
uint32_t type;
ret = read_uint32(bs, offset, &count);
if (ret < 0) {
goto fail;
} else if (count == 0) {
ret = -EINVAL;
goto fail;
}
count = read_uint32(bs, offset);
if(count==0)
goto fail;
offset += 4;
ret = read_uint32(bs, offset, &type);
if (ret < 0) {
goto fail;
}
type = read_uint32(bs, offset);
if (type == 0x6d697368 && count >= 244) {
int new_size, chunk_count;
@@ -166,11 +134,8 @@ static int dmg_open(BlockDriverState *bs, int flags)
s->sectors = g_realloc(s->sectors, new_size);
s->sectorcounts = g_realloc(s->sectorcounts, new_size);
for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) {
ret = read_uint32(bs, offset, &s->types[i]);
if (ret < 0) {
goto fail;
}
for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
s->types[i] = read_uint32(bs, offset);
offset += 4;
if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
if(s->types[i]==0xffffffff) {
@@ -184,31 +149,17 @@ static int dmg_open(BlockDriverState *bs, int flags)
}
offset += 4;
ret = read_uint64(bs, offset, &s->sectors[i]);
if (ret < 0) {
goto fail;
}
s->sectors[i] += last_out_offset;
offset += 8;
s->sectors[i] = last_out_offset+read_off(bs, offset);
offset += 8;
ret = read_uint64(bs, offset, &s->sectorcounts[i]);
if (ret < 0) {
goto fail;
}
offset += 8;
s->sectorcounts[i] = read_off(bs, offset);
offset += 8;
ret = read_uint64(bs, offset, &s->offsets[i]);
if (ret < 0) {
goto fail;
}
s->offsets[i] += last_in_offset;
offset += 8;
s->offsets[i] = last_in_offset+read_off(bs, offset);
offset += 8;
ret = read_uint64(bs, offset, &s->lengths[i]);
if (ret < 0) {
goto fail;
}
offset += 8;
s->lengths[i] = read_off(bs, offset);
offset += 8;
if(s->lengths[i]>max_compressed_size)
max_compressed_size = s->lengths[i];
@@ -222,25 +173,15 @@ static int dmg_open(BlockDriverState *bs, int flags)
/* initialize zlib engine */
s->compressed_chunk = g_malloc(max_compressed_size+1);
s->uncompressed_chunk = g_malloc(512*max_sectors_per_chunk);
if(inflateInit(&s->zstream) != Z_OK) {
ret = -EINVAL;
goto fail;
}
if(inflateInit(&s->zstream) != Z_OK)
goto fail;
s->current_chunk = s->n_chunks;
qemu_co_mutex_init(&s->lock);
return 0;
fail:
g_free(s->types);
g_free(s->offsets);
g_free(s->lengths);
g_free(s->sectors);
g_free(s->sectorcounts);
g_free(s->compressed_chunk);
g_free(s->uncompressed_chunk);
return ret;
return -1;
}
static inline int is_sector_in_chunk(BDRVDMGState* s,
@@ -355,15 +296,15 @@ static coroutine_fn int dmg_co_read(BlockDriverState *bs, int64_t sector_num,
static void dmg_close(BlockDriverState *bs)
{
BDRVDMGState *s = bs->opaque;
g_free(s->types);
g_free(s->offsets);
g_free(s->lengths);
g_free(s->sectors);
g_free(s->sectorcounts);
g_free(s->compressed_chunk);
g_free(s->uncompressed_chunk);
if(s->n_chunks>0) {
free(s->types);
free(s->offsets);
free(s->lengths);
free(s->sectors);
free(s->sectorcounts);
}
free(s->compressed_chunk);
free(s->uncompressed_chunk);
inflateEnd(&s->zstream);
}

View File

@@ -1,624 +0,0 @@
/*
* GlusterFS backend for QEMU
*
* Copyright (C) 2012 Bharata B Rao <bharata@linux.vnet.ibm.com>
*
* Pipe handling mechanism in AIO implementation is derived from
* block/rbd.c. Hence,
*
* Copyright (C) 2010-2011 Christian Brunner <chb@muc.de>,
* Josh Durgin <josh.durgin@dreamhost.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#include <glusterfs/api/glfs.h>
#include "block/block_int.h"
#include "qemu/sockets.h"
#include "qemu/uri.h"
typedef struct GlusterAIOCB {
BlockDriverAIOCB common;
int64_t size;
int ret;
bool *finished;
QEMUBH *bh;
} GlusterAIOCB;
typedef struct BDRVGlusterState {
struct glfs *glfs;
int fds[2];
struct glfs_fd *fd;
int qemu_aio_count;
int event_reader_pos;
GlusterAIOCB *event_acb;
} BDRVGlusterState;
#define GLUSTER_FD_READ 0
#define GLUSTER_FD_WRITE 1
typedef struct GlusterConf {
char *server;
int port;
char *volname;
char *image;
char *transport;
} GlusterConf;
static void qemu_gluster_gconf_free(GlusterConf *gconf)
{
g_free(gconf->server);
g_free(gconf->volname);
g_free(gconf->image);
g_free(gconf->transport);
g_free(gconf);
}
static int parse_volume_options(GlusterConf *gconf, char *path)
{
char *p, *q;
if (!path) {
return -EINVAL;
}
/* volume */
p = q = path + strspn(path, "/");
p += strcspn(p, "/");
if (*p == '\0') {
return -EINVAL;
}
gconf->volname = g_strndup(q, p - q);
/* image */
p += strspn(p, "/");
if (*p == '\0') {
return -EINVAL;
}
gconf->image = g_strdup(p);
return 0;
}
/*
* file=gluster[+transport]://[server[:port]]/volname/image[?socket=...]
*
* 'gluster' is the protocol.
*
* 'transport' specifies the transport type used to connect to gluster
* management daemon (glusterd). Valid transport types are
* tcp, unix and rdma. If a transport type isn't specified, then tcp
* type is assumed.
*
* 'server' specifies the server where the volume file specification for
* the given volume resides. This can be either hostname, ipv4 address
* or ipv6 address. ipv6 address needs to be within square brackets [ ].
* If transport type is 'unix', then 'server' field should not be specifed.
* The 'socket' field needs to be populated with the path to unix domain
* socket.
*
* 'port' is the port number on which glusterd is listening. This is optional
* and if not specified, QEMU will send 0 which will make gluster to use the
* default port. If the transport type is unix, then 'port' should not be
* specified.
*
* 'volname' is the name of the gluster volume which contains the VM image.
*
* 'image' is the path to the actual VM image that resides on gluster volume.
*
* Examples:
*
* file=gluster://1.2.3.4/testvol/a.img
* file=gluster+tcp://1.2.3.4/testvol/a.img
* file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img
* file=gluster+tcp://[1:2:3:4:5:6:7:8]/testvol/dir/a.img
* file=gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol/dir/a.img
* file=gluster+tcp://server.domain.com:24007/testvol/dir/a.img
* file=gluster+unix:///testvol/dir/a.img?socket=/tmp/glusterd.socket
* file=gluster+rdma://1.2.3.4:24007/testvol/a.img
*/
static int qemu_gluster_parseuri(GlusterConf *gconf, const char *filename)
{
URI *uri;
QueryParams *qp = NULL;
bool is_unix = false;
int ret = 0;
uri = uri_parse(filename);
if (!uri) {
return -EINVAL;
}
/* transport */
if (!strcmp(uri->scheme, "gluster")) {
gconf->transport = g_strdup("tcp");
} else if (!strcmp(uri->scheme, "gluster+tcp")) {
gconf->transport = g_strdup("tcp");
} else if (!strcmp(uri->scheme, "gluster+unix")) {
gconf->transport = g_strdup("unix");
is_unix = true;
} else if (!strcmp(uri->scheme, "gluster+rdma")) {
gconf->transport = g_strdup("rdma");
} else {
ret = -EINVAL;
goto out;
}
ret = parse_volume_options(gconf, uri->path);
if (ret < 0) {
goto out;
}
qp = query_params_parse(uri->query);
if (qp->n > 1 || (is_unix && !qp->n) || (!is_unix && qp->n)) {
ret = -EINVAL;
goto out;
}
if (is_unix) {
if (uri->server || uri->port) {
ret = -EINVAL;
goto out;
}
if (strcmp(qp->p[0].name, "socket")) {
ret = -EINVAL;
goto out;
}
gconf->server = g_strdup(qp->p[0].value);
} else {
gconf->server = g_strdup(uri->server);
gconf->port = uri->port;
}
out:
if (qp) {
query_params_free(qp);
}
uri_free(uri);
return ret;
}
static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename)
{
struct glfs *glfs = NULL;
int ret;
int old_errno;
ret = qemu_gluster_parseuri(gconf, filename);
if (ret < 0) {
error_report("Usage: file=gluster[+transport]://[server[:port]]/"
"volname/image[?socket=...]");
errno = -ret;
goto out;
}
glfs = glfs_new(gconf->volname);
if (!glfs) {
goto out;
}
ret = glfs_set_volfile_server(glfs, gconf->transport, gconf->server,
gconf->port);
if (ret < 0) {
goto out;
}
/*
* TODO: Use GF_LOG_ERROR instead of hard code value of 4 here when
* GlusterFS makes GF_LOG_* macros available to libgfapi users.
*/
ret = glfs_set_logging(glfs, "-", 4);
if (ret < 0) {
goto out;
}
ret = glfs_init(glfs);
if (ret) {
error_report("Gluster connection failed for server=%s port=%d "
"volume=%s image=%s transport=%s", gconf->server, gconf->port,
gconf->volname, gconf->image, gconf->transport);
goto out;
}
return glfs;
out:
if (glfs) {
old_errno = errno;
glfs_fini(glfs);
errno = old_errno;
}
return NULL;
}
static void qemu_gluster_complete_aio(GlusterAIOCB *acb, BDRVGlusterState *s)
{
int ret;
bool *finished = acb->finished;
BlockDriverCompletionFunc *cb = acb->common.cb;
void *opaque = acb->common.opaque;
if (!acb->ret || acb->ret == acb->size) {
ret = 0; /* Success */
} else if (acb->ret < 0) {
ret = acb->ret; /* Read/Write failed */
} else {
ret = -EIO; /* Partial read/write - fail it */
}
s->qemu_aio_count--;
qemu_aio_release(acb);
cb(opaque, ret);
if (finished) {
*finished = true;
}
}
static void qemu_gluster_aio_event_reader(void *opaque)
{
BDRVGlusterState *s = opaque;
ssize_t ret;
do {
char *p = (char *)&s->event_acb;
ret = read(s->fds[GLUSTER_FD_READ], p + s->event_reader_pos,
sizeof(s->event_acb) - s->event_reader_pos);
if (ret > 0) {
s->event_reader_pos += ret;
if (s->event_reader_pos == sizeof(s->event_acb)) {
s->event_reader_pos = 0;
qemu_gluster_complete_aio(s->event_acb, s);
}
}
} while (ret < 0 && errno == EINTR);
}
static int qemu_gluster_aio_flush_cb(void *opaque)
{
BDRVGlusterState *s = opaque;
return (s->qemu_aio_count > 0);
}
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));
s->glfs = qemu_gluster_init(gconf, filename);
if (!s->glfs) {
ret = -errno;
goto out;
}
if (bdrv_flags & BDRV_O_RDWR) {
open_flags |= O_RDWR;
} else {
open_flags |= O_RDONLY;
}
if ((bdrv_flags & BDRV_O_NOCACHE)) {
open_flags |= O_DIRECT;
}
s->fd = glfs_open(s->glfs, gconf->image, open_flags);
if (!s->fd) {
ret = -errno;
goto out;
}
ret = qemu_pipe(s->fds);
if (ret < 0) {
ret = -errno;
goto out;
}
fcntl(s->fds[GLUSTER_FD_READ], F_SETFL, O_NONBLOCK);
qemu_aio_set_fd_handler(s->fds[GLUSTER_FD_READ],
qemu_gluster_aio_event_reader, NULL, qemu_gluster_aio_flush_cb, s);
out:
qemu_gluster_gconf_free(gconf);
if (!ret) {
return ret;
}
if (s->fd) {
glfs_close(s->fd);
}
if (s->glfs) {
glfs_fini(s->glfs);
}
return ret;
}
static int qemu_gluster_create(const char *filename,
QEMUOptionParameter *options)
{
struct glfs *glfs;
struct glfs_fd *fd;
int ret = 0;
int64_t total_size = 0;
GlusterConf *gconf = g_malloc0(sizeof(GlusterConf));
glfs = qemu_gluster_init(gconf, filename);
if (!glfs) {
ret = -errno;
goto out;
}
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
total_size = options->value.n / BDRV_SECTOR_SIZE;
}
options++;
}
fd = glfs_creat(glfs, gconf->image,
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
if (!fd) {
ret = -errno;
} else {
if (glfs_ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
ret = -errno;
}
if (glfs_close(fd) != 0) {
ret = -errno;
}
}
out:
qemu_gluster_gconf_free(gconf);
if (glfs) {
glfs_fini(glfs);
}
return ret;
}
static void qemu_gluster_aio_cancel(BlockDriverAIOCB *blockacb)
{
GlusterAIOCB *acb = (GlusterAIOCB *)blockacb;
bool finished = false;
acb->finished = &finished;
while (!finished) {
qemu_aio_wait();
}
}
static const AIOCBInfo gluster_aiocb_info = {
.aiocb_size = sizeof(GlusterAIOCB),
.cancel = qemu_gluster_aio_cancel,
};
static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
{
GlusterAIOCB *acb = (GlusterAIOCB *)arg;
BlockDriverState *bs = acb->common.bs;
BDRVGlusterState *s = bs->opaque;
int retval;
acb->ret = ret;
retval = qemu_write_full(s->fds[GLUSTER_FD_WRITE], &acb, sizeof(acb));
if (retval != sizeof(acb)) {
/*
* Gluster AIO callback thread failed to notify the waiting
* QEMU thread about IO completion.
*
* Complete this IO request and make the disk inaccessible for
* subsequent reads and writes.
*/
error_report("Gluster failed to notify QEMU about IO completion");
qemu_mutex_lock_iothread(); /* We are in gluster thread context */
acb->common.cb(acb->common.opaque, -EIO);
qemu_aio_release(acb);
s->qemu_aio_count--;
close(s->fds[GLUSTER_FD_READ]);
close(s->fds[GLUSTER_FD_WRITE]);
qemu_aio_set_fd_handler(s->fds[GLUSTER_FD_READ], NULL, NULL, NULL,
NULL);
bs->drv = NULL; /* Make the disk inaccessible */
qemu_mutex_unlock_iothread();
}
}
static BlockDriverAIOCB *qemu_gluster_aio_rw(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int write)
{
int ret;
GlusterAIOCB *acb;
BDRVGlusterState *s = bs->opaque;
size_t size;
off_t offset;
offset = sector_num * BDRV_SECTOR_SIZE;
size = nb_sectors * BDRV_SECTOR_SIZE;
s->qemu_aio_count++;
acb = qemu_aio_get(&gluster_aiocb_info, bs, cb, opaque);
acb->size = size;
acb->ret = 0;
acb->finished = NULL;
if (write) {
ret = glfs_pwritev_async(s->fd, qiov->iov, qiov->niov, offset, 0,
&gluster_finish_aiocb, acb);
} else {
ret = glfs_preadv_async(s->fd, qiov->iov, qiov->niov, offset, 0,
&gluster_finish_aiocb, acb);
}
if (ret < 0) {
goto out;
}
return &acb->common;
out:
s->qemu_aio_count--;
qemu_aio_release(acb);
return NULL;
}
static BlockDriverAIOCB *qemu_gluster_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
return qemu_gluster_aio_rw(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
}
static BlockDriverAIOCB *qemu_gluster_aio_writev(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
return qemu_gluster_aio_rw(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
}
static BlockDriverAIOCB *qemu_gluster_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
int ret;
GlusterAIOCB *acb;
BDRVGlusterState *s = bs->opaque;
acb = qemu_aio_get(&gluster_aiocb_info, bs, cb, opaque);
acb->size = 0;
acb->ret = 0;
acb->finished = NULL;
s->qemu_aio_count++;
ret = glfs_fsync_async(s->fd, &gluster_finish_aiocb, acb);
if (ret < 0) {
goto out;
}
return &acb->common;
out:
s->qemu_aio_count--;
qemu_aio_release(acb);
return NULL;
}
static int64_t qemu_gluster_getlength(BlockDriverState *bs)
{
BDRVGlusterState *s = bs->opaque;
int64_t ret;
ret = glfs_lseek(s->fd, 0, SEEK_END);
if (ret < 0) {
return -errno;
} else {
return ret;
}
}
static int64_t qemu_gluster_allocated_file_size(BlockDriverState *bs)
{
BDRVGlusterState *s = bs->opaque;
struct stat st;
int ret;
ret = glfs_fstat(s->fd, &st);
if (ret < 0) {
return -errno;
} else {
return st.st_blocks * 512;
}
}
static void qemu_gluster_close(BlockDriverState *bs)
{
BDRVGlusterState *s = bs->opaque;
close(s->fds[GLUSTER_FD_READ]);
close(s->fds[GLUSTER_FD_WRITE]);
qemu_aio_set_fd_handler(s->fds[GLUSTER_FD_READ], NULL, NULL, NULL, NULL);
if (s->fd) {
glfs_close(s->fd);
s->fd = NULL;
}
glfs_fini(s->glfs);
}
static QEMUOptionParameter qemu_gluster_create_options[] = {
{
.name = BLOCK_OPT_SIZE,
.type = OPT_SIZE,
.help = "Virtual disk size"
},
{ NULL }
};
static BlockDriver bdrv_gluster = {
.format_name = "gluster",
.protocol_name = "gluster",
.instance_size = sizeof(BDRVGlusterState),
.bdrv_file_open = qemu_gluster_open,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
.bdrv_getlength = qemu_gluster_getlength,
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
.bdrv_aio_readv = qemu_gluster_aio_readv,
.bdrv_aio_writev = qemu_gluster_aio_writev,
.bdrv_aio_flush = qemu_gluster_aio_flush,
.create_options = qemu_gluster_create_options,
};
static BlockDriver bdrv_gluster_tcp = {
.format_name = "gluster",
.protocol_name = "gluster+tcp",
.instance_size = sizeof(BDRVGlusterState),
.bdrv_file_open = qemu_gluster_open,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
.bdrv_getlength = qemu_gluster_getlength,
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
.bdrv_aio_readv = qemu_gluster_aio_readv,
.bdrv_aio_writev = qemu_gluster_aio_writev,
.bdrv_aio_flush = qemu_gluster_aio_flush,
.create_options = qemu_gluster_create_options,
};
static BlockDriver bdrv_gluster_unix = {
.format_name = "gluster",
.protocol_name = "gluster+unix",
.instance_size = sizeof(BDRVGlusterState),
.bdrv_file_open = qemu_gluster_open,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
.bdrv_getlength = qemu_gluster_getlength,
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
.bdrv_aio_readv = qemu_gluster_aio_readv,
.bdrv_aio_writev = qemu_gluster_aio_writev,
.bdrv_aio_flush = qemu_gluster_aio_flush,
.create_options = qemu_gluster_create_options,
};
static BlockDriver bdrv_gluster_rdma = {
.format_name = "gluster",
.protocol_name = "gluster+rdma",
.instance_size = sizeof(BDRVGlusterState),
.bdrv_file_open = qemu_gluster_open,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
.bdrv_getlength = qemu_gluster_getlength,
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
.bdrv_aio_readv = qemu_gluster_aio_readv,
.bdrv_aio_writev = qemu_gluster_aio_writev,
.bdrv_aio_flush = qemu_gluster_aio_flush,
.create_options = qemu_gluster_create_options,
};
static void bdrv_gluster_init(void)
{
bdrv_register(&bdrv_gluster_rdma);
bdrv_register(&bdrv_gluster_unix);
bdrv_register(&bdrv_gluster_tcp);
bdrv_register(&bdrv_gluster);
}
block_init(bdrv_gluster_init);

View File

@@ -27,9 +27,8 @@
#include <poll.h>
#include <arpa/inet.h>
#include "qemu-common.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
#include "block/block_int.h"
#include "qemu-error.h"
#include "block_int.h"
#include "trace.h"
#include "hw/scsi-defs.h"
@@ -48,7 +47,6 @@ typedef struct IscsiLun {
int block_size;
uint64_t num_blocks;
int events;
QEMUTimer *nop_timer;
} IscsiLun;
typedef struct IscsiAIOCB {
@@ -67,9 +65,6 @@ typedef struct IscsiAIOCB {
#endif
} IscsiAIOCB;
#define NOP_INTERVAL 5000
#define MAX_NOP_FAILURES 3
static void
iscsi_bh_cb(void *p)
{
@@ -77,9 +72,6 @@ iscsi_bh_cb(void *p)
qemu_bh_delete(acb->bh);
g_free(acb->buf);
acb->buf = NULL;
if (acb->canceled == 0) {
acb->common.cb(acb->common.opaque, acb->status);
}
@@ -134,7 +126,7 @@ iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
}
}
static const AIOCBInfo iscsi_aiocb_info = {
static AIOPool iscsi_aio_pool = {
.aiocb_size = sizeof(IscsiAIOCB),
.cancel = iscsi_aio_cancel,
};
@@ -201,7 +193,6 @@ iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
trace_iscsi_aio_write16_cb(iscsi, status, acb, acb->canceled);
g_free(acb->buf);
acb->buf = NULL;
if (acb->canceled != 0) {
return;
@@ -234,12 +225,9 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
size_t size;
uint32_t num_sectors;
uint64_t lba;
#if !defined(LIBISCSI_FEATURE_IOVECTOR)
struct iscsi_data data;
#endif
int ret;
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
acb->iscsilun = iscsilun;
@@ -248,23 +236,12 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
/* XXX we should pass the iovec to write16 to avoid the extra copy */
/* this will allow us to get rid of 'buf' completely */
size = nb_sectors * BDRV_SECTOR_SIZE;
#if !defined(LIBISCSI_FEATURE_IOVECTOR)
data.size = MIN(size, acb->qiov->size);
/* if the iovec only contains one buffer we can pass it directly */
if (acb->qiov->niov == 1) {
data.data = acb->qiov->iov[0].iov_base;
} else {
acb->buf = g_malloc(data.size);
qemu_iovec_to_buf(acb->qiov, 0, acb->buf, data.size);
data.data = acb->buf;
}
#endif
acb->buf = g_malloc(size);
qemu_iovec_to_buf(acb->qiov, 0, acb->buf, size);
acb->task = malloc(sizeof(struct scsi_task));
if (acb->task == NULL) {
@@ -278,6 +255,10 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
acb->task->xfer_dir = SCSI_XFER_WRITE;
acb->task->cdb_size = 16;
acb->task->cdb[0] = 0x8a;
if (!(bs->open_flags & BDRV_O_CACHE_WB)) {
/* set FUA on writes when cache mode is write through */
acb->task->cdb[1] |= 0x04;
}
lba = sector_qemu2lun(sector_num, iscsilun);
*(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32);
*(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff);
@@ -285,28 +266,19 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
acb->task->expxferlen = size;
#if defined(LIBISCSI_FEATURE_IOVECTOR)
ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
iscsi_aio_write16_cb,
NULL,
acb);
#else
ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
iscsi_aio_write16_cb,
&data,
acb);
#endif
if (ret != 0) {
data.data = acb->buf;
data.size = size;
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
iscsi_aio_write16_cb,
&data,
acb) != 0) {
scsi_free_scsi_task(acb->task);
g_free(acb->buf);
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
iscsi_set_events(iscsilun);
return &acb->common;
@@ -344,16 +316,13 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
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);
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb);
acb->iscsilun = iscsilun;
@@ -409,25 +378,20 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
break;
}
ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
iscsi_aio_read16_cb,
NULL,
acb);
if (ret != 0) {
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
iscsi_aio_read16_cb,
NULL,
acb) != 0) {
scsi_free_scsi_task(acb->task);
qemu_aio_release(acb);
return NULL;
}
#if defined(LIBISCSI_FEATURE_IOVECTOR)
scsi_task_set_iov_in(acb->task, (struct scsi_iovec*) acb->qiov->iov, acb->qiov->niov);
#else
for (i = 0; i < acb->qiov->niov; i++) {
scsi_task_add_data_in_buffer(acb->task,
acb->qiov->iov[i].iov_len,
acb->qiov->iov[i].iov_base);
}
#endif
iscsi_set_events(iscsilun);
@@ -463,13 +427,12 @@ iscsi_aio_flush(BlockDriverState *bs,
struct iscsi_context *iscsi = iscsilun->iscsi;
IscsiAIOCB *acb;
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
acb->iscsilun = iscsilun;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun,
0, 0, 0, 0,
@@ -517,13 +480,12 @@ iscsi_aio_discard(BlockDriverState *bs,
IscsiAIOCB *acb;
struct unmap_list list[1];
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
acb->iscsilun = iscsilun;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
list[0].lba = sector_qemu2lun(sector_num, iscsilun);
list[0].num = nb_sectors * BDRV_SECTOR_SIZE / iscsilun->block_size;
@@ -593,7 +555,7 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
assert(req == SG_IO);
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
acb->iscsilun = iscsilun;
acb->canceled = 0;
@@ -803,26 +765,6 @@ static char *parse_initiator_name(const char *target)
}
}
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
static void iscsi_nop_timed_event(void *opaque)
{
IscsiLun *iscsilun = opaque;
if (iscsi_get_nops_in_flight(iscsilun->iscsi) > MAX_NOP_FAILURES) {
error_report("iSCSI: NOP timeout. Reconnecting...");
iscsi_reconnect(iscsilun->iscsi);
}
if (iscsi_nop_out_async(iscsilun->iscsi, NULL, NULL, 0, NULL) != 0) {
error_report("iSCSI: failed to sent NOP-Out. Disabling NOP messages.");
return;
}
qemu_mod_timer(iscsilun->nop_timer, qemu_get_clock_ms(rt_clock) + NOP_INTERVAL);
iscsi_set_events(iscsilun);
}
#endif
/*
* We support iscsi url's on the form
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
@@ -983,12 +925,6 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
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);
qemu_mod_timer(iscsilun->nop_timer, qemu_get_clock_ms(rt_clock) + NOP_INTERVAL);
#endif
out:
if (initiator_name != NULL) {
g_free(initiator_name);
@@ -1014,10 +950,6 @@ static void iscsi_close(BlockDriverState *bs)
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
if (iscsilun->nop_timer) {
qemu_del_timer(iscsilun->nop_timer);
qemu_free_timer(iscsilun->nop_timer);
}
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL);
iscsi_destroy_context(iscsi);
memset(iscsilun, 0, sizeof(IscsiLun));
@@ -1028,60 +960,6 @@ static int iscsi_has_zero_init(BlockDriverState *bs)
return 0;
}
static int iscsi_create(const char *filename, QEMUOptionParameter *options)
{
int ret = 0;
int64_t total_size = 0;
BlockDriverState bs;
IscsiLun *iscsilun = NULL;
memset(&bs, 0, sizeof(BlockDriverState));
/* Read out options */
while (options && options->name) {
if (!strcmp(options->name, "size")) {
total_size = options->value.n / BDRV_SECTOR_SIZE;
}
options++;
}
bs.opaque = g_malloc0(sizeof(struct IscsiLun));
iscsilun = bs.opaque;
ret = iscsi_open(&bs, filename, 0);
if (ret != 0) {
goto out;
}
if (iscsilun->nop_timer) {
qemu_del_timer(iscsilun->nop_timer);
qemu_free_timer(iscsilun->nop_timer);
}
if (iscsilun->type != TYPE_DISK) {
ret = -ENODEV;
goto out;
}
if (bs.total_sectors < total_size) {
ret = -ENOSPC;
}
ret = 0;
out:
if (iscsilun->iscsi != NULL) {
iscsi_destroy_context(iscsilun->iscsi);
}
g_free(bs.opaque);
return ret;
}
static QEMUOptionParameter iscsi_create_options[] = {
{
.name = BLOCK_OPT_SIZE,
.type = OPT_SIZE,
.help = "Virtual disk size"
},
{ NULL }
};
static BlockDriver bdrv_iscsi = {
.format_name = "iscsi",
.protocol_name = "iscsi",
@@ -1089,8 +967,6 @@ static BlockDriver bdrv_iscsi = {
.instance_size = sizeof(IscsiLun),
.bdrv_file_open = iscsi_open,
.bdrv_close = iscsi_close,
.bdrv_create = iscsi_create,
.create_options = iscsi_create_options,
.bdrv_getlength = iscsi_getlength,
@@ -1107,36 +983,9 @@ static BlockDriver bdrv_iscsi = {
#endif
};
static QemuOptsList qemu_iscsi_opts = {
.name = "iscsi",
.head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head),
.desc = {
{
.name = "user",
.type = QEMU_OPT_STRING,
.help = "username for CHAP authentication to target",
},{
.name = "password",
.type = QEMU_OPT_STRING,
.help = "password for CHAP authentication to target",
},{
.name = "header-digest",
.type = QEMU_OPT_STRING,
.help = "HeaderDigest setting. "
"{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}",
},{
.name = "initiator-name",
.type = QEMU_OPT_STRING,
.help = "Initiator iqn name to use when connecting",
},
{ /* end of list */ }
},
};
static void iscsi_block_init(void)
{
bdrv_register(&bdrv_iscsi);
qemu_add_opts(&qemu_iscsi_opts);
}
block_init(iscsi_block_init);

View File

@@ -1,584 +0,0 @@
/*
* Image mirroring
*
* Copyright Red Hat, Inc. 2012
*
* Authors:
* Paolo Bonzini <pbonzini@redhat.com>
*
* 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 "trace.h"
#include "block/blockjob.h"
#include "block/block_int.h"
#include "qemu/ratelimit.h"
#include "qemu/bitmap.h"
#define SLICE_TIME 100000000ULL /* ns */
#define MAX_IN_FLIGHT 16
/* The mirroring buffer is a list of granularity-sized chunks.
* Free chunks are organized in a list.
*/
typedef struct MirrorBuffer {
QSIMPLEQ_ENTRY(MirrorBuffer) next;
} MirrorBuffer;
typedef struct MirrorBlockJob {
BlockJob common;
RateLimit limit;
BlockDriverState *target;
MirrorSyncMode mode;
BlockdevOnError on_source_error, on_target_error;
bool synced;
bool should_complete;
int64_t sector_num;
int64_t granularity;
size_t buf_size;
unsigned long *cow_bitmap;
HBitmapIter hbi;
uint8_t *buf;
QSIMPLEQ_HEAD(, MirrorBuffer) buf_free;
int buf_free_count;
unsigned long *in_flight_bitmap;
int in_flight;
int ret;
} MirrorBlockJob;
typedef struct MirrorOp {
MirrorBlockJob *s;
QEMUIOVector qiov;
int64_t sector_num;
int nb_sectors;
} MirrorOp;
static BlockErrorAction mirror_error_action(MirrorBlockJob *s, bool read,
int error)
{
s->synced = false;
if (read) {
return block_job_error_action(&s->common, s->common.bs,
s->on_source_error, true, error);
} else {
return block_job_error_action(&s->common, s->target,
s->on_target_error, false, error);
}
}
static void mirror_iteration_done(MirrorOp *op, int ret)
{
MirrorBlockJob *s = op->s;
struct iovec *iov;
int64_t chunk_num;
int i, nb_chunks, sectors_per_chunk;
trace_mirror_iteration_done(s, op->sector_num, op->nb_sectors, ret);
s->in_flight--;
iov = op->qiov.iov;
for (i = 0; i < op->qiov.niov; i++) {
MirrorBuffer *buf = (MirrorBuffer *) iov[i].iov_base;
QSIMPLEQ_INSERT_TAIL(&s->buf_free, buf, next);
s->buf_free_count++;
}
sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS;
chunk_num = op->sector_num / sectors_per_chunk;
nb_chunks = op->nb_sectors / sectors_per_chunk;
bitmap_clear(s->in_flight_bitmap, chunk_num, nb_chunks);
if (s->cow_bitmap && ret >= 0) {
bitmap_set(s->cow_bitmap, chunk_num, nb_chunks);
}
g_slice_free(MirrorOp, op);
qemu_coroutine_enter(s->common.co, NULL);
}
static void mirror_write_complete(void *opaque, int ret)
{
MirrorOp *op = opaque;
MirrorBlockJob *s = op->s;
if (ret < 0) {
BlockDriverState *source = s->common.bs;
BlockErrorAction action;
bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
action = mirror_error_action(s, false, -ret);
if (action == BDRV_ACTION_REPORT && s->ret >= 0) {
s->ret = ret;
}
}
mirror_iteration_done(op, ret);
}
static void mirror_read_complete(void *opaque, int ret)
{
MirrorOp *op = opaque;
MirrorBlockJob *s = op->s;
if (ret < 0) {
BlockDriverState *source = s->common.bs;
BlockErrorAction action;
bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
action = mirror_error_action(s, true, -ret);
if (action == BDRV_ACTION_REPORT && s->ret >= 0) {
s->ret = ret;
}
mirror_iteration_done(op, ret);
return;
}
bdrv_aio_writev(s->target, op->sector_num, &op->qiov, op->nb_sectors,
mirror_write_complete, op);
}
static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
{
BlockDriverState *source = s->common.bs;
int nb_sectors, sectors_per_chunk, nb_chunks;
int64_t end, sector_num, next_chunk, next_sector, hbitmap_next_sector;
MirrorOp *op;
s->sector_num = hbitmap_iter_next(&s->hbi);
if (s->sector_num < 0) {
bdrv_dirty_iter_init(source, &s->hbi);
s->sector_num = hbitmap_iter_next(&s->hbi);
trace_mirror_restart_iter(s, bdrv_get_dirty_count(source));
assert(s->sector_num >= 0);
}
hbitmap_next_sector = s->sector_num;
sector_num = s->sector_num;
sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS;
end = s->common.len >> BDRV_SECTOR_BITS;
/* Extend the QEMUIOVector to include all adjacent blocks that will
* be copied in this operation.
*
* We have to do this if we have no backing file yet in the destination,
* and the cluster size is very large. Then we need to do COW ourselves.
* The first time a cluster is copied, copy it entirely. Note that,
* because both the granularity and the cluster size are powers of two,
* the number of sectors to copy cannot exceed one cluster.
*
* We also want to extend the QEMUIOVector to include more adjacent
* dirty blocks if possible, to limit the number of I/O operations and
* run efficiently even with a small granularity.
*/
nb_chunks = 0;
nb_sectors = 0;
next_sector = sector_num;
next_chunk = sector_num / sectors_per_chunk;
/* Wait for I/O to this cluster (from a previous iteration) to be done. */
while (test_bit(next_chunk, s->in_flight_bitmap)) {
trace_mirror_yield_in_flight(s, sector_num, s->in_flight);
qemu_coroutine_yield();
}
do {
int added_sectors, added_chunks;
if (!bdrv_get_dirty(source, next_sector) ||
test_bit(next_chunk, s->in_flight_bitmap)) {
assert(nb_sectors > 0);
break;
}
added_sectors = sectors_per_chunk;
if (s->cow_bitmap && !test_bit(next_chunk, s->cow_bitmap)) {
bdrv_round_to_clusters(s->target,
next_sector, added_sectors,
&next_sector, &added_sectors);
/* On the first iteration, the rounding may make us copy
* sectors before the first dirty one.
*/
if (next_sector < sector_num) {
assert(nb_sectors == 0);
sector_num = next_sector;
next_chunk = next_sector / sectors_per_chunk;
}
}
added_sectors = MIN(added_sectors, end - (sector_num + nb_sectors));
added_chunks = (added_sectors + sectors_per_chunk - 1) / sectors_per_chunk;
/* When doing COW, it may happen that there is not enough space for
* a full cluster. Wait if that is the case.
*/
while (nb_chunks == 0 && s->buf_free_count < added_chunks) {
trace_mirror_yield_buf_busy(s, nb_chunks, s->in_flight);
qemu_coroutine_yield();
}
if (s->buf_free_count < nb_chunks + added_chunks) {
trace_mirror_break_buf_busy(s, nb_chunks, s->in_flight);
break;
}
/* We have enough free space to copy these sectors. */
bitmap_set(s->in_flight_bitmap, next_chunk, added_chunks);
nb_sectors += added_sectors;
nb_chunks += added_chunks;
next_sector += added_sectors;
next_chunk += added_chunks;
} while (next_sector < end);
/* Allocate a MirrorOp that is used as an AIO callback. */
op = g_slice_new(MirrorOp);
op->s = s;
op->sector_num = sector_num;
op->nb_sectors = nb_sectors;
/* Now make a QEMUIOVector taking enough granularity-sized chunks
* from s->buf_free.
*/
qemu_iovec_init(&op->qiov, nb_chunks);
next_sector = sector_num;
while (nb_chunks-- > 0) {
MirrorBuffer *buf = QSIMPLEQ_FIRST(&s->buf_free);
QSIMPLEQ_REMOVE_HEAD(&s->buf_free, next);
s->buf_free_count--;
qemu_iovec_add(&op->qiov, buf, s->granularity);
/* Advance the HBitmapIter in parallel, so that we do not examine
* the same sector twice.
*/
if (next_sector > hbitmap_next_sector && bdrv_get_dirty(source, next_sector)) {
hbitmap_next_sector = hbitmap_iter_next(&s->hbi);
}
next_sector += sectors_per_chunk;
}
bdrv_reset_dirty(source, sector_num, nb_sectors);
/* Copy the dirty cluster. */
s->in_flight++;
trace_mirror_one_iteration(s, sector_num, nb_sectors);
bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors,
mirror_read_complete, op);
}
static void mirror_free_init(MirrorBlockJob *s)
{
int granularity = s->granularity;
size_t buf_size = s->buf_size;
uint8_t *buf = s->buf;
assert(s->buf_free_count == 0);
QSIMPLEQ_INIT(&s->buf_free);
while (buf_size != 0) {
MirrorBuffer *cur = (MirrorBuffer *)buf;
QSIMPLEQ_INSERT_TAIL(&s->buf_free, cur, next);
s->buf_free_count++;
buf_size -= granularity;
buf += granularity;
}
}
static void mirror_drain(MirrorBlockJob *s)
{
while (s->in_flight > 0) {
qemu_coroutine_yield();
}
}
static void coroutine_fn mirror_run(void *opaque)
{
MirrorBlockJob *s = opaque;
BlockDriverState *bs = s->common.bs;
int64_t sector_num, end, sectors_per_chunk, length;
uint64_t last_pause_ns;
BlockDriverInfo bdi;
char backing_filename[1024];
int ret = 0;
int n;
if (block_job_is_cancelled(&s->common)) {
goto immediate_exit;
}
s->common.len = bdrv_getlength(bs);
if (s->common.len <= 0) {
block_job_completed(&s->common, s->common.len);
return;
}
length = (bdrv_getlength(bs) + s->granularity - 1) / s->granularity;
s->in_flight_bitmap = bitmap_new(length);
/* If we have no backing file yet in the destination, we cannot let
* the destination do COW. Instead, we copy sectors around the
* dirty data if needed. We need a bitmap to do that.
*/
bdrv_get_backing_filename(s->target, backing_filename,
sizeof(backing_filename));
if (backing_filename[0] && !s->target->backing_hd) {
bdrv_get_info(s->target, &bdi);
if (s->granularity < bdi.cluster_size) {
s->buf_size = MAX(s->buf_size, bdi.cluster_size);
s->cow_bitmap = bitmap_new(length);
}
}
end = s->common.len >> BDRV_SECTOR_BITS;
s->buf = qemu_blockalign(bs, s->buf_size);
sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS;
mirror_free_init(s);
if (s->mode != MIRROR_SYNC_MODE_NONE) {
/* First part, loop on the sectors and initialize the dirty bitmap. */
BlockDriverState *base;
base = s->mode == MIRROR_SYNC_MODE_FULL ? NULL : bs->backing_hd;
for (sector_num = 0; sector_num < end; ) {
int64_t next = (sector_num | (sectors_per_chunk - 1)) + 1;
ret = bdrv_co_is_allocated_above(bs, base,
sector_num, next - sector_num, &n);
if (ret < 0) {
goto immediate_exit;
}
assert(n > 0);
if (ret == 1) {
bdrv_set_dirty(bs, sector_num, n);
sector_num = next;
} else {
sector_num += n;
}
}
}
bdrv_dirty_iter_init(bs, &s->hbi);
last_pause_ns = qemu_get_clock_ns(rt_clock);
for (;;) {
uint64_t delay_ns;
int64_t cnt;
bool should_complete;
if (s->ret < 0) {
ret = s->ret;
goto immediate_exit;
}
cnt = bdrv_get_dirty_count(bs);
/* Note that even when no rate limit is applied we need to yield
* periodically with no pending I/O so that qemu_aio_flush() returns.
* We do so every SLICE_TIME nanoseconds, or when there is an error,
* or when the source is clean, whichever comes first.
*/
if (qemu_get_clock_ns(rt_clock) - last_pause_ns < SLICE_TIME &&
s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
if (s->in_flight == MAX_IN_FLIGHT || s->buf_free_count == 0 ||
(cnt == 0 && s->in_flight > 0)) {
trace_mirror_yield(s, s->in_flight, s->buf_free_count, cnt);
qemu_coroutine_yield();
continue;
} else if (cnt != 0) {
mirror_iteration(s);
continue;
}
}
should_complete = false;
if (s->in_flight == 0 && cnt == 0) {
trace_mirror_before_flush(s);
ret = bdrv_flush(s->target);
if (ret < 0) {
if (mirror_error_action(s, false, -ret) == BDRV_ACTION_REPORT) {
goto immediate_exit;
}
} else {
/* We're out of the streaming phase. From now on, if the job
* is cancelled we will actually complete all pending I/O and
* report completion. This way, block-job-cancel will leave
* the target in a consistent state.
*/
s->common.offset = end * BDRV_SECTOR_SIZE;
if (!s->synced) {
block_job_ready(&s->common);
s->synced = true;
}
should_complete = s->should_complete ||
block_job_is_cancelled(&s->common);
cnt = bdrv_get_dirty_count(bs);
}
}
if (cnt == 0 && should_complete) {
/* The dirty bitmap is not updated while operations are pending.
* If we're about to exit, wait for pending operations before
* calling bdrv_get_dirty_count(bs), or we may exit while the
* source has dirty data to copy!
*
* Note that I/O can be submitted by the guest while
* mirror_populate runs.
*/
trace_mirror_before_drain(s, cnt);
bdrv_drain_all();
cnt = bdrv_get_dirty_count(bs);
}
ret = 0;
trace_mirror_before_sleep(s, cnt, s->synced);
if (!s->synced) {
/* Publish progress */
s->common.offset = (end - cnt) * BDRV_SECTOR_SIZE;
if (s->common.speed) {
delay_ns = ratelimit_calculate_delay(&s->limit, sectors_per_chunk);
} else {
delay_ns = 0;
}
block_job_sleep_ns(&s->common, rt_clock, delay_ns);
if (block_job_is_cancelled(&s->common)) {
break;
}
} else if (!should_complete) {
delay_ns = (s->in_flight == 0 && cnt == 0 ? SLICE_TIME : 0);
block_job_sleep_ns(&s->common, rt_clock, delay_ns);
} else if (cnt == 0) {
/* The two disks are in sync. Exit and report successful
* completion.
*/
assert(QLIST_EMPTY(&bs->tracked_requests));
s->common.cancelled = false;
break;
}
last_pause_ns = qemu_get_clock_ns(rt_clock);
}
immediate_exit:
if (s->in_flight > 0) {
/* We get here only if something went wrong. Either the job failed,
* or it was cancelled prematurely so that we do not guarantee that
* the target is a copy of the source.
*/
assert(ret < 0 || (!s->synced && block_job_is_cancelled(&s->common)));
mirror_drain(s);
}
assert(s->in_flight == 0);
qemu_vfree(s->buf);
g_free(s->cow_bitmap);
g_free(s->in_flight_bitmap);
bdrv_set_dirty_tracking(bs, 0);
bdrv_iostatus_disable(s->target);
if (s->should_complete && ret == 0) {
if (bdrv_get_flags(s->target) != bdrv_get_flags(s->common.bs)) {
bdrv_reopen(s->target, bdrv_get_flags(s->common.bs), NULL);
}
bdrv_swap(s->target, s->common.bs);
}
bdrv_close(s->target);
bdrv_delete(s->target);
block_job_completed(&s->common, ret);
}
static void mirror_set_speed(BlockJob *job, int64_t speed, Error **errp)
{
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
if (speed < 0) {
error_set(errp, QERR_INVALID_PARAMETER, "speed");
return;
}
ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME);
}
static void mirror_iostatus_reset(BlockJob *job)
{
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
bdrv_iostatus_reset(s->target);
}
static void mirror_complete(BlockJob *job, Error **errp)
{
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
int ret;
ret = bdrv_open_backing_file(s->target);
if (ret < 0) {
char backing_filename[PATH_MAX];
bdrv_get_full_backing_filename(s->target, backing_filename,
sizeof(backing_filename));
error_set(errp, QERR_OPEN_FILE_FAILED, backing_filename);
return;
}
if (!s->synced) {
error_set(errp, QERR_BLOCK_JOB_NOT_READY, job->bs->device_name);
return;
}
s->should_complete = true;
block_job_resume(job);
}
static BlockJobType mirror_job_type = {
.instance_size = sizeof(MirrorBlockJob),
.job_type = "mirror",
.set_speed = mirror_set_speed,
.iostatus_reset= mirror_iostatus_reset,
.complete = mirror_complete,
};
void mirror_start(BlockDriverState *bs, BlockDriverState *target,
int64_t speed, int64_t granularity, int64_t buf_size,
MirrorSyncMode mode, BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
BlockDriverCompletionFunc *cb,
void *opaque, Error **errp)
{
MirrorBlockJob *s;
if (granularity == 0) {
/* Choose the default granularity based on the target file's cluster
* size, clamped between 4k and 64k. */
BlockDriverInfo bdi;
if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) {
granularity = MAX(4096, bdi.cluster_size);
granularity = MIN(65536, granularity);
} else {
granularity = 65536;
}
}
assert ((granularity & (granularity - 1)) == 0);
if ((on_source_error == BLOCKDEV_ON_ERROR_STOP ||
on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
!bdrv_iostatus_is_enabled(bs)) {
error_set(errp, QERR_INVALID_PARAMETER, "on-source-error");
return;
}
s = block_job_create(&mirror_job_type, bs, speed, cb, opaque, errp);
if (!s) {
return;
}
s->on_source_error = on_source_error;
s->on_target_error = on_target_error;
s->target = target;
s->mode = mode;
s->granularity = granularity;
s->buf_size = MAX(buf_size, granularity);
bdrv_set_dirty_tracking(bs, granularity);
bdrv_set_enable_write_cache(s->target, true);
bdrv_set_on_error(s->target, on_target_error, on_target_error);
bdrv_iostatus_enable(s->target);
s->common.co = qemu_coroutine_create(mirror_run);
trace_mirror_start(bs, s, s->common.co, opaque);
qemu_coroutine_enter(s->common.co, s);
}

View File

@@ -27,11 +27,10 @@
*/
#include "qemu-common.h"
#include "block/nbd.h"
#include "qemu/uri.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "qemu/sockets.h"
#include "nbd.h"
#include "block_int.h"
#include "module.h"
#include "qemu_socket.h"
#include <sys/types.h>
#include <unistd.h>
@@ -56,6 +55,7 @@ typedef struct BDRVNBDState {
uint32_t nbdflags;
off_t size;
size_t blocksize;
char *export_name; /* An NBD server may export several devices */
CoMutex send_mutex;
CoMutex free_sema;
@@ -65,75 +65,13 @@ typedef struct BDRVNBDState {
Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
struct nbd_reply reply;
int is_unix;
/* If it begins with '/', this is a UNIX domain socket. Otherwise,
* it's a string of the form <hostname|ip4|\[ip6\]>:port
*/
char *host_spec;
char *export_name; /* An NBD server may export several devices */
} BDRVNBDState;
static int nbd_parse_uri(BDRVNBDState *s, const char *filename)
{
URI *uri;
const char *p;
QueryParams *qp = NULL;
int ret = 0;
uri = uri_parse(filename);
if (!uri) {
return -EINVAL;
}
/* transport */
if (!strcmp(uri->scheme, "nbd")) {
s->is_unix = false;
} else if (!strcmp(uri->scheme, "nbd+tcp")) {
s->is_unix = false;
} else if (!strcmp(uri->scheme, "nbd+unix")) {
s->is_unix = true;
} else {
ret = -EINVAL;
goto out;
}
p = uri->path ? uri->path : "/";
p += strspn(p, "/");
if (p[0]) {
s->export_name = g_strdup(p);
}
qp = query_params_parse(uri->query);
if (qp->n > 1 || (s->is_unix && !qp->n) || (!s->is_unix && qp->n)) {
ret = -EINVAL;
goto out;
}
if (s->is_unix) {
/* nbd+unix:///export?socket=path */
if (uri->server || uri->port || strcmp(qp->p[0].name, "socket")) {
ret = -EINVAL;
goto out;
}
s->host_spec = g_strdup(qp->p[0].value);
} else {
/* nbd[+tcp]://host:port/export */
if (!uri->server) {
ret = -EINVAL;
goto out;
}
if (!uri->port) {
uri->port = NBD_DEFAULT_PORT;
}
s->host_spec = g_strdup_printf("%s:%d", uri->server, uri->port);
}
out:
if (qp) {
query_params_free(qp);
}
uri_free(uri);
return ret;
}
static int nbd_config(BDRVNBDState *s, const char *filename)
static int nbd_config(BDRVNBDState *s, const char *filename, int flags)
{
char *file;
char *export_name;
@@ -141,10 +79,6 @@ static int nbd_config(BDRVNBDState *s, const char *filename)
const char *unixpath;
int err = -EINVAL;
if (strstr(filename, "://")) {
return nbd_parse_uri(s, filename);
}
file = g_strdup(filename);
export_name = strstr(file, EN_OPTSTR);
@@ -164,10 +98,11 @@ static int nbd_config(BDRVNBDState *s, const char *filename)
/* are we a UNIX or TCP socket? */
if (strstart(host_spec, "unix:", &unixpath)) {
s->is_unix = true;
if (unixpath[0] != '/') { /* We demand an absolute path*/
goto out;
}
s->host_spec = g_strdup(unixpath);
} else {
s->is_unix = false;
s->host_spec = g_strdup(host_spec);
}
@@ -327,7 +262,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
off_t size;
size_t blocksize;
if (s->is_unix) {
if (s->host_spec[0] == '/') {
sock = unix_socket_outgoing(s->host_spec);
} else {
sock = tcp_socket_outgoing_spec(s->host_spec);
@@ -350,7 +285,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
/* Now that we're connected, set the socket to be non-blocking and
* kick the reply mechanism. */
qemu_set_nonblock(sock);
socket_set_nonblock(sock);
qemu_aio_set_fd_handler(sock, nbd_reply_ready, NULL,
nbd_have_request, s);
@@ -385,7 +320,7 @@ static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
qemu_co_mutex_init(&s->free_sema);
/* Pop the config into our state object. Exit if invalid. */
result = nbd_config(s, filename);
result = nbd_config(s, filename, flags);
if (result != 0) {
return result;
}
@@ -563,48 +498,20 @@ static int64_t nbd_getlength(BlockDriverState *bs)
static BlockDriver bdrv_nbd = {
.format_name = "nbd",
.instance_size = sizeof(BDRVNBDState),
.bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv,
.bdrv_co_writev = nbd_co_writev,
.bdrv_close = nbd_close,
.bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_discard = nbd_co_discard,
.bdrv_getlength = nbd_getlength,
.protocol_name = "nbd",
.instance_size = sizeof(BDRVNBDState),
.bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv,
.bdrv_co_writev = nbd_co_writev,
.bdrv_close = nbd_close,
.bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_discard = nbd_co_discard,
.bdrv_getlength = nbd_getlength,
};
static BlockDriver bdrv_nbd_tcp = {
.format_name = "nbd",
.protocol_name = "nbd+tcp",
.instance_size = sizeof(BDRVNBDState),
.bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv,
.bdrv_co_writev = nbd_co_writev,
.bdrv_close = nbd_close,
.bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_discard = nbd_co_discard,
.bdrv_getlength = nbd_getlength,
};
static BlockDriver bdrv_nbd_unix = {
.format_name = "nbd",
.protocol_name = "nbd+unix",
.instance_size = sizeof(BDRVNBDState),
.bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv,
.bdrv_co_writev = nbd_co_writev,
.bdrv_close = nbd_close,
.bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_discard = nbd_co_discard,
.bdrv_getlength = nbd_getlength,
};
static void bdrv_nbd_init(void)
{
bdrv_register(&bdrv_nbd);
bdrv_register(&bdrv_nbd_tcp);
bdrv_register(&bdrv_nbd_unix);
}
block_init(bdrv_nbd_init);

View File

@@ -24,8 +24,8 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "block_int.h"
#include "module.h"
/**************************************************************/
@@ -73,18 +73,14 @@ static int parallels_open(BlockDriverState *bs, int flags)
BDRVParallelsState *s = bs->opaque;
int i;
struct parallels_header ph;
int ret;
bs->read_only = 1; // no write support yet
ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
if (ret < 0) {
if (bdrv_pread(bs->file, 0, &ph, sizeof(ph)) != sizeof(ph))
goto fail;
}
if (memcmp(ph.magic, HEADER_MAGIC, 16) ||
(le32_to_cpu(ph.version) != HEADER_VERSION)) {
ret = -EMEDIUMTYPE;
(le32_to_cpu(ph.version) != HEADER_VERSION)) {
goto fail;
}
@@ -94,21 +90,18 @@ static int parallels_open(BlockDriverState *bs, int flags)
s->catalog_size = le32_to_cpu(ph.catalog_entries);
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
ret = bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4);
if (ret < 0) {
goto fail;
}
if (bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4) !=
s->catalog_size * 4)
goto fail;
for (i = 0; i < s->catalog_size; i++)
le32_to_cpus(&s->catalog_bitmap[i]);
qemu_co_mutex_init(&s->lock);
return 0;
fail:
g_free(s->catalog_bitmap);
return ret;
if (s->catalog_bitmap)
g_free(s->catalog_bitmap);
return -1;
}
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)

View File

@@ -22,11 +22,11 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "block_int.h"
#include "module.h"
#include <zlib.h>
#include "block/aes.h"
#include "migration/migration.h"
#include "aes.h"
#include "migration.h"
/**************************************************************/
/* QEMU COW block driver with compression and encryption support */
@@ -112,7 +112,7 @@ static int qcow_open(BlockDriverState *bs, int flags)
be64_to_cpus(&header.l1_table_offset);
if (header.magic != QCOW_MAGIC) {
ret = -EMEDIUMTYPE;
ret = -EINVAL;
goto fail;
}
if (header.version != QCOW_VERSION) {
@@ -197,15 +197,6 @@ static int qcow_open(BlockDriverState *bs, int flags)
return ret;
}
/* We have nothing to do for QCOW reopen, stubs just return
* success */
static int qcow_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
return 0;
}
static int qcow_set_key(BlockDriverState *bs, const char *key)
{
BDRVQcowState *s = bs->opaque;
@@ -877,7 +868,6 @@ static BlockDriver bdrv_qcow = {
.bdrv_probe = qcow_probe,
.bdrv_open = qcow_open,
.bdrv_close = qcow_close,
.bdrv_reopen_prepare = qcow_reopen_prepare,
.bdrv_create = qcow_create,
.bdrv_co_readv = qcow_co_readv,

View File

@@ -22,7 +22,7 @@
* THE SOFTWARE.
*/
#include "block/block_int.h"
#include "block_int.h"
#include "qemu-common.h"
#include "qcow2.h"
#include "trace.h"

View File

@@ -25,7 +25,7 @@
#include <zlib.h>
#include "qemu-common.h"
#include "block/block_int.h"
#include "block_int.h"
#include "block/qcow2.h"
#include "trace.h"
@@ -454,9 +454,6 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
*cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
break;
case QCOW2_CLUSTER_ZERO:
if (s->qcow_version < 3) {
return -EIO;
}
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], 0,
QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
@@ -618,67 +615,57 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
return cluster_offset;
}
static int perform_cow(BlockDriverState *bs, QCowL2Meta *m, Qcow2COWRegion *r)
{
BDRVQcowState *s = bs->opaque;
int ret;
if (r->nb_sectors == 0) {
return 0;
}
qemu_co_mutex_unlock(&s->lock);
ret = copy_sectors(bs, m->offset / BDRV_SECTOR_SIZE, m->alloc_offset,
r->offset / BDRV_SECTOR_SIZE,
r->offset / BDRV_SECTOR_SIZE + r->nb_sectors);
qemu_co_mutex_lock(&s->lock);
if (ret < 0) {
return ret;
}
/*
* Before we update the L2 table to actually point to the new cluster, we
* need to be sure that the refcounts have been increased and COW was
* handled.
*/
qcow2_cache_depends_on_flush(s->l2_table_cache);
return 0;
}
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
{
BDRVQcowState *s = bs->opaque;
int i, j = 0, l2_index, ret;
uint64_t *old_cluster, *l2_table;
uint64_t *old_cluster, start_sect, *l2_table;
uint64_t cluster_offset = m->alloc_offset;
bool cow = false;
trace_qcow2_cluster_link_l2(qemu_coroutine_self(), m->nb_clusters);
assert(m->nb_clusters > 0);
if (m->nb_clusters == 0)
return 0;
old_cluster = g_malloc(m->nb_clusters * sizeof(uint64_t));
/* copy content of unmodified sectors */
ret = perform_cow(bs, m, &m->cow_start);
if (ret < 0) {
goto err;
start_sect = (m->offset & ~(s->cluster_size - 1)) >> 9;
if (m->n_start) {
cow = true;
qemu_co_mutex_unlock(&s->lock);
ret = copy_sectors(bs, start_sect, cluster_offset, 0, m->n_start);
qemu_co_mutex_lock(&s->lock);
if (ret < 0)
goto err;
}
ret = perform_cow(bs, m, &m->cow_end);
if (ret < 0) {
goto err;
if (m->nb_available & (s->cluster_sectors - 1)) {
cow = true;
qemu_co_mutex_unlock(&s->lock);
ret = copy_sectors(bs, start_sect, cluster_offset, m->nb_available,
align_offset(m->nb_available, s->cluster_sectors));
qemu_co_mutex_lock(&s->lock);
if (ret < 0)
goto err;
}
/* Update L2 table. */
if (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS) {
qcow2_mark_dirty(bs);
/*
* Update L2 table.
*
* Before we update the L2 table to actually point to the new cluster, we
* need to be sure that the refcounts have been increased and COW was
* handled.
*/
if (cow) {
qcow2_cache_depends_on_flush(s->l2_table_cache);
}
if (qcow2_need_accurate_refcounts(s)) {
qcow2_cache_set_dependency(bs, s->l2_table_cache,
s->refcount_block_cache);
}
ret = get_cluster_table(bs, m->offset, &l2_table, &l2_index);
if (ret < 0) {
goto err;
@@ -756,16 +743,38 @@ 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.
* Allocates new clusters for the given guest_offset.
*
* At most *nb_clusters are allocated, and on return *nb_clusters is updated to
* contain the number of clusters that have been allocated and are contiguous
* in the image file.
*
* If *host_offset is non-zero, it specifies the offset in the image file at
* which the new clusters must start. *nb_clusters can be 0 on return in this
* case if the cluster at host_offset is already in use. If *host_offset is
* zero, the clusters can be allocated anywhere in the image file.
*
* *host_offset is updated to contain the offset into the image file at which
* the first allocated cluster starts.
*
* Return 0 on success and -errno in error cases. -EAGAIN means that the
* function has been waiting for another request and the allocation must be
* restarted, but the whole request should not be failed.
*/
static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
unsigned int *nb_clusters)
static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
uint64_t *host_offset, unsigned int *nb_clusters)
{
BDRVQcowState *s = bs->opaque;
QCowL2Meta *old_alloc;
trace_qcow2_do_alloc_clusters_offset(qemu_coroutine_self(), guest_offset,
*host_offset, *nb_clusters);
/*
* 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.
*/
QLIST_FOREACH(old_alloc, &s->cluster_allocs, next_in_flight) {
uint64_t start = guest_offset >> s->cluster_bits;
@@ -798,42 +807,6 @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
abort();
}
return 0;
}
/*
* Allocates new clusters for the given guest_offset.
*
* At most *nb_clusters are allocated, and on return *nb_clusters is updated to
* contain the number of clusters that have been allocated and are contiguous
* in the image file.
*
* If *host_offset is non-zero, it specifies the offset in the image file at
* which the new clusters must start. *nb_clusters can be 0 on return in this
* case if the cluster at host_offset is already in use. If *host_offset is
* zero, the clusters can be allocated anywhere in the image file.
*
* *host_offset is updated to contain the offset into the image file at which
* the first allocated cluster starts.
*
* Return 0 on success and -errno in error cases. -EAGAIN means that the
* function has been waiting for another request and the allocation must be
* restarted, but the whole request should not be failed.
*/
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) {
@@ -845,7 +818,7 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
*host_offset = cluster_offset;
return 0;
} else {
ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters);
int ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters);
if (ret < 0) {
return ret;
}
@@ -874,7 +847,7 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
* Return 0 on success and -errno in error cases
*/
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
int n_start, int n_end, int *num, uint64_t *host_offset, QCowL2Meta **m)
int n_start, int n_end, int *num, QCowL2Meta *m)
{
BDRVQcowState *s = bs->opaque;
int l2_index, ret, sectors;
@@ -946,6 +919,12 @@ again:
}
/* If there is something left to allocate, do that now */
*m = (QCowL2Meta) {
.cluster_offset = cluster_offset,
.nb_clusters = 0,
};
qemu_co_queue_init(&m->dependent_requests);
if (nb_clusters > 0) {
uint64_t alloc_offset;
uint64_t alloc_cluster_offset;
@@ -978,40 +957,22 @@ again:
*
* 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)
*/
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;
}
*m = g_malloc0(sizeof(**m));
**m = (QCowL2Meta) {
*m = (QCowL2Meta) {
.cluster_offset = keep_clusters == 0 ?
alloc_cluster_offset : cluster_offset,
.alloc_offset = alloc_cluster_offset,
.offset = alloc_offset & ~(s->cluster_size - 1),
.offset = alloc_offset,
.n_start = keep_clusters == 0 ? n_start : 0,
.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,
},
.nb_available = MIN(requested_sectors, avail_sectors),
};
qemu_co_queue_init(&(*m)->dependent_requests);
QLIST_INSERT_HEAD(&s->cluster_allocs, *m, next_in_flight);
qemu_co_queue_init(&m->dependent_requests);
QLIST_INSERT_HEAD(&s->cluster_allocs, m, next_in_flight);
}
}
@@ -1023,13 +984,12 @@ again:
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);
if (m->nb_clusters > 0) {
QLIST_REMOVE(m, next_in_flight);
}
return ret;
}

View File

@@ -23,7 +23,7 @@
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "block_int.h"
#include "block/qcow2.h"
static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size);
@@ -201,10 +201,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
*refcount_block = NULL;
/* We write to the refcount table, so we might depend on L2 tables */
ret = qcow2_cache_flush(bs, s->l2_table_cache);
if (ret < 0) {
return ret;
}
qcow2_cache_flush(bs, s->l2_table_cache);
/* Allocate the refcount block itself and mark it as used */
int64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
@@ -240,10 +237,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
goto fail_block;
}
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
goto fail_block;
}
bdrv_flush(bs->file);
/* Initialize the new refcount block only after updating its refcount,
* update_refcount uses the refcount cache itself */
@@ -743,7 +737,11 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
* l1_table_offset when it is the current s->l1_table_offset! Be careful
* when changing this! */
if (l1_table_offset != s->l1_table_offset) {
l1_table = g_malloc0(align_offset(l1_size2, 512));
if (l1_size2 != 0) {
l1_table = g_malloc0(align_offset(l1_size2, 512));
} else {
l1_table = NULL;
}
l1_allocated = 1;
if (bdrv_pread(bs->file, l1_table_offset,
l1_table, l1_size2) != l1_size2)

View File

@@ -23,7 +23,7 @@
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "block_int.h"
#include "block/qcow2.h"
typedef struct QEMU_PACKED QCowSnapshotHeader {
@@ -180,14 +180,11 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
/* Allocate space for the new snapshot list */
snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
bdrv_flush(bs->file);
offset = snapshots_offset;
if (offset < 0) {
return offset;
}
ret = bdrv_flush(bs);
if (ret < 0) {
return ret;
}
/* Write all snapshots to the new list */
for(i = 0; i < s->nb_snapshots; i++) {

View File

@@ -22,13 +22,13 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "block_int.h"
#include "module.h"
#include <zlib.h>
#include "block/aes.h"
#include "aes.h"
#include "block/qcow2.h"
#include "qemu/error-report.h"
#include "qapi/qmp/qerror.h"
#include "qemu-error.h"
#include "qerror.h"
#include "trace.h"
/*
@@ -52,7 +52,6 @@ typedef struct {
uint32_t magic;
uint32_t len;
} QCowExtension;
#define QCOW2_EXT_MAGIC_END 0
#define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
#define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857
@@ -222,7 +221,7 @@ static void report_unsupported_feature(BlockDriverState *bs,
* updated successfully. Therefore it is not required to check the return
* value of this function.
*/
int qcow2_mark_dirty(BlockDriverState *bs)
static int qcow2_mark_dirty(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
uint64_t val;
@@ -311,7 +310,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
be32_to_cpus(&header.nb_snapshots);
if (header.magic != QCOW_MAGIC) {
ret = -EMEDIUMTYPE;
ret = -EINVAL;
goto fail;
}
if (header.version < 2 || header.version > 3) {
@@ -559,14 +558,6 @@ static int qcow2_set_key(BlockDriverState *bs, const char *key)
return 0;
}
/* We have nothing to do for QCOW2 reopen, stubs just return
* success */
static int qcow2_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
return 0;
}
static int coroutine_fn qcow2_co_is_allocated(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, int *pnum)
{
@@ -584,7 +575,7 @@ static int coroutine_fn qcow2_co_is_allocated(BlockDriverState *bs,
*pnum = 0;
}
return (cluster_offset != 0) || (ret == QCOW2_CLUSTER_ZERO);
return (cluster_offset != 0);
}
/* handle reading after the end of the backing file */
@@ -665,6 +656,10 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
break;
case QCOW2_CLUSTER_ZERO:
if (s->qcow_version < 3) {
ret = -EIO;
goto fail;
}
qemu_iovec_memset(&hd_qiov, 0, 0, 512 * cur_nr_sectors);
break;
@@ -741,6 +736,21 @@ fail:
return ret;
}
static void run_dependent_requests(BDRVQcowState *s, QCowL2Meta *m)
{
/* Take the request off the list of running requests */
if (m->nb_clusters != 0) {
QLIST_REMOVE(m, next_in_flight);
}
/* Restart all dependent requests */
if (!qemu_co_queue_empty(&m->dependent_requests)) {
qemu_co_mutex_unlock(&s->lock);
qemu_co_queue_restart_all(&m->dependent_requests);
qemu_co_mutex_lock(&s->lock);
}
}
static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
int64_t sector_num,
int remaining_sectors,
@@ -755,11 +765,15 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
QEMUIOVector hd_qiov;
uint64_t bytes_done = 0;
uint8_t *cluster_data = NULL;
QCowL2Meta *l2meta = NULL;
QCowL2Meta l2meta = {
.nb_clusters = 0,
};
trace_qcow2_writev_start_req(qemu_coroutine_self(), sector_num,
remaining_sectors);
qemu_co_queue_init(&l2meta.dependent_requests);
qemu_iovec_init(&hd_qiov, qiov->niov);
s->cluster_cache_offset = -1; /* disable compressed cache */
@@ -768,8 +782,6 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
while (remaining_sectors != 0) {
l2meta = NULL;
trace_qcow2_writev_start_part(qemu_coroutine_self());
index_in_cluster = sector_num & (s->cluster_sectors - 1);
n_end = index_in_cluster + remaining_sectors;
@@ -779,11 +791,17 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
}
ret = qcow2_alloc_cluster_offset(bs, sector_num << 9,
index_in_cluster, n_end, &cur_nr_sectors, &cluster_offset, &l2meta);
index_in_cluster, n_end, &cur_nr_sectors, &l2meta);
if (ret < 0) {
goto fail;
}
if (l2meta.nb_clusters > 0 &&
(s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS)) {
qcow2_mark_dirty(bs);
}
cluster_offset = l2meta.cluster_offset;
assert((cluster_offset & 511) == 0);
qemu_iovec_reset(&hd_qiov);
@@ -808,8 +826,8 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
cur_nr_sectors * 512);
}
qemu_co_mutex_unlock(&s->lock);
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
qemu_co_mutex_unlock(&s->lock);
trace_qcow2_writev_data(qemu_coroutine_self(),
(cluster_offset >> 9) + index_in_cluster);
ret = bdrv_co_writev(bs->file,
@@ -820,25 +838,13 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
goto fail;
}
if (l2meta != NULL) {
ret = qcow2_alloc_cluster_link_l2(bs, l2meta);
if (ret < 0) {
goto fail;
}
/* Take the request off the list of running requests */
if (l2meta->nb_clusters != 0) {
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);
g_free(l2meta);
l2meta = NULL;
ret = qcow2_alloc_cluster_link_l2(bs, &l2meta);
if (ret < 0) {
goto fail;
}
run_dependent_requests(s, &l2meta);
remaining_sectors -= cur_nr_sectors;
sector_num += cur_nr_sectors;
bytes_done += cur_nr_sectors * 512;
@@ -847,15 +853,9 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
ret = 0;
fail:
qemu_co_mutex_unlock(&s->lock);
run_dependent_requests(s, &l2meta);
if (l2meta != NULL) {
if (l2meta->nb_clusters != 0) {
QLIST_REMOVE(l2meta, next_in_flight);
}
qemu_co_queue_restart_all(&l2meta->dependent_requests);
g_free(l2meta);
}
qemu_co_mutex_unlock(&s->lock);
qemu_iovec_destroy(&hd_qiov);
qemu_vfree(cluster_data);
@@ -1087,7 +1087,6 @@ int qcow2_update_header(BlockDriverState *bs)
goto fail;
}
/* Using strncpy is ok here, since buf is not NUL-terminated. */
strncpy(buf, bs->backing_file, buflen);
header->backing_file_offset = cpu_to_be64(buf - ((char*) header));
@@ -1119,33 +1118,31 @@ static int preallocate(BlockDriverState *bs)
{
uint64_t nb_sectors;
uint64_t offset;
uint64_t host_offset = 0;
int num;
int ret;
QCowL2Meta *meta;
QCowL2Meta meta;
nb_sectors = bdrv_getlength(bs) >> 9;
offset = 0;
qemu_co_queue_init(&meta.dependent_requests);
meta.cluster_offset = 0;
while (nb_sectors) {
num = MIN(nb_sectors, INT_MAX >> 9);
ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num,
&host_offset, &meta);
ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num, &meta);
if (ret < 0) {
return ret;
}
ret = qcow2_alloc_cluster_link_l2(bs, meta);
ret = qcow2_alloc_cluster_link_l2(bs, &meta);
if (ret < 0) {
qcow2_free_any_clusters(bs, meta->alloc_offset, meta->nb_clusters);
qcow2_free_any_clusters(bs, meta.cluster_offset, meta.nb_clusters);
return ret;
}
/* There are no dependent requests, but we need to remove our request
* from the list of in-flight requests */
if (meta != NULL) {
QLIST_REMOVE(meta, next_in_flight);
}
run_dependent_requests(bs->opaque, &meta);
/* TODO Preallocate data if requested */
@@ -1158,10 +1155,10 @@ static int preallocate(BlockDriverState *bs)
* all of the allocated clusters (otherwise we get failing reads after
* EOF). Extend the image to the last allocated sector.
*/
if (host_offset != 0) {
if (meta.cluster_offset != 0) {
uint8_t buf[512];
memset(buf, 0, 512);
ret = bdrv_write(bs->file, (host_offset >> 9) + num - 1, buf, 1);
ret = bdrv_write(bs->file, (meta.cluster_offset >> 9) + num - 1, buf, 1);
if (ret < 0) {
return ret;
}
@@ -1682,7 +1679,6 @@ static BlockDriver bdrv_qcow2 = {
.bdrv_probe = qcow2_probe,
.bdrv_open = qcow2_open,
.bdrv_close = qcow2_close,
.bdrv_reopen_prepare = qcow2_reopen_prepare,
.bdrv_create = qcow2_create,
.bdrv_co_is_allocated = qcow2_co_is_allocated,
.bdrv_set_key = qcow2_set_key,

View File

@@ -25,8 +25,8 @@
#ifndef BLOCK_QCOW2_H
#define BLOCK_QCOW2_H
#include "block/aes.h"
#include "block/coroutine.h"
#include "aes.h"
#include "qemu-coroutine.h"
//#define DEBUG_ALLOC
//#define DEBUG_ALLOC2
@@ -196,56 +196,17 @@ typedef struct QCowCreateState {
struct QCowAIOCB;
typedef struct Qcow2COWRegion {
/**
* Offset of the COW region in bytes from the start of the first cluster
* touched by the request.
*/
uint64_t offset;
/** Number of sectors to copy */
int nb_sectors;
} Qcow2COWRegion;
/**
* Describes an in-flight (part of a) write request that writes to clusters
* that are not referenced in their L2 table yet.
*/
/* XXX This could be private for qcow2-cluster.c */
typedef struct QCowL2Meta
{
/** Guest offset of the first newly allocated cluster */
uint64_t offset;
/** Host offset of the first newly allocated cluster */
uint64_t cluster_offset;
uint64_t alloc_offset;
/**
* Number of sectors from the start of the first allocated cluster to
* the end of the (possibly shortened) request
*/
int n_start;
int nb_available;
/** Number of newly allocated clusters */
int nb_clusters;
/**
* Requests that overlap with this allocation and wait to be restarted
* when the allocating request has completed.
*/
CoQueue dependent_requests;
/**
* The COW Region between the start of the first allocated cluster and the
* area the guest actually writes to.
*/
Qcow2COWRegion cow_start;
/**
* The COW Region between the area the guest actually writes to and the
* end of the last allocated cluster.
*/
Qcow2COWRegion cow_end;
QLIST_ENTRY(QCowL2Meta) next_in_flight;
} QCowL2Meta;
@@ -303,8 +264,6 @@ static inline bool qcow2_need_accurate_refcounts(BDRVQcowState *s)
/* qcow2.c functions */
int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
int64_t sector_num, int nb_sectors);
int qcow2_mark_dirty(BlockDriverState *bs);
int qcow2_update_header(BlockDriverState *bs);
/* qcow2-refcount.c functions */
@@ -338,7 +297,7 @@ void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
int *num, uint64_t *cluster_offset);
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
int n_start, int n_end, int *num, uint64_t *host_offset, QCowL2Meta **m);
int n_start, int n_end, int *num, QCowL2Meta *m);
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
uint64_t offset,
int compressed_size);

View File

@@ -13,7 +13,7 @@
*/
#include "trace.h"
#include "qemu/sockets.h" /* for EINPROGRESS on Windows */
#include "qemu_socket.h" /* for EINPROGRESS on Windows */
#include "qed.h"
typedef struct {
@@ -103,6 +103,7 @@ static void qed_write_table_cb(void *opaque, int ret)
out:
qemu_vfree(write_table_cb->table);
gencb_complete(&write_table_cb->gencb, ret);
return;
}
/**

View File

@@ -12,11 +12,11 @@
*
*/
#include "qemu/timer.h"
#include "qemu-timer.h"
#include "trace.h"
#include "qed.h"
#include "qapi/qmp/qerror.h"
#include "migration/migration.h"
#include "qerror.h"
#include "migration.h"
static void qed_aio_cancel(BlockDriverAIOCB *blockacb)
{
@@ -30,7 +30,7 @@ static void qed_aio_cancel(BlockDriverAIOCB *blockacb)
}
}
static const AIOCBInfo qed_aiocb_info = {
static AIOPool qed_aio_pool = {
.aiocb_size = sizeof(QEDAIOCB),
.cancel = qed_aio_cancel,
};
@@ -390,7 +390,7 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
qed_header_le_to_cpu(&le_header, &s->header);
if (s->header.magic != QED_MAGIC) {
return -EMEDIUMTYPE;
return -EINVAL;
}
if (s->header.features & ~QED_FEATURE_MASK) {
/* image uses unsupported feature bits */
@@ -505,14 +505,6 @@ out:
return ret;
}
/* We have nothing to do for QED reopen, stubs just return
* success */
static int bdrv_qed_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
return 0;
}
static void bdrv_qed_close(BlockDriverState *bs)
{
BDRVQEDState *s = bs->opaque;
@@ -1311,7 +1303,7 @@ static BlockDriverAIOCB *qed_aio_setup(BlockDriverState *bs,
BlockDriverCompletionFunc *cb,
void *opaque, int flags)
{
QEDAIOCB *acb = qemu_aio_get(&qed_aiocb_info, bs, cb, opaque);
QEDAIOCB *acb = qemu_aio_get(&qed_aio_pool, bs, cb, opaque);
trace_qed_aio_setup(bs->opaque, acb, sector_num, nb_sectors,
opaque, flags);
@@ -1572,7 +1564,6 @@ static BlockDriver bdrv_qed = {
.bdrv_rebind = bdrv_qed_rebind,
.bdrv_open = bdrv_qed_open,
.bdrv_close = bdrv_qed_close,
.bdrv_reopen_prepare = bdrv_qed_reopen_prepare,
.bdrv_create = bdrv_qed_create,
.bdrv_co_is_allocated = bdrv_qed_co_is_allocated,
.bdrv_make_empty = bdrv_qed_make_empty,

View File

@@ -15,7 +15,7 @@
#ifndef BLOCK_QED_H
#define BLOCK_QED_H
#include "block/block_int.h"
#include "block_int.h"
/* The layout of a QED file is as follows:
*

View File

@@ -1,5 +1,5 @@
/*
* Declarations for AIO in the raw protocol
* QEMU Posix block I/O backend AIO support
*
* Copyright IBM, Corp. 2008
*
@@ -12,40 +12,34 @@
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#ifndef QEMU_RAW_AIO_H
#define QEMU_RAW_AIO_H
#ifndef QEMU_RAW_POSIX_AIO_H
#define QEMU_RAW_POSIX_AIO_H
/* AIO request types */
#define QEMU_AIO_READ 0x0001
#define QEMU_AIO_WRITE 0x0002
#define QEMU_AIO_IOCTL 0x0004
#define QEMU_AIO_FLUSH 0x0008
#define QEMU_AIO_DISCARD 0x0010
#define QEMU_AIO_TYPE_MASK \
(QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH| \
QEMU_AIO_DISCARD)
(QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH)
/* AIO flags */
#define QEMU_AIO_MISALIGNED 0x1000
#define QEMU_AIO_BLKDEV 0x2000
/* posix-aio-compat.c - thread pool based implementation */
int paio_init(void);
BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type);
BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
unsigned long int req, void *buf,
BlockDriverCompletionFunc *cb, void *opaque);
/* linux-aio.c - Linux native implementation */
#ifdef CONFIG_LINUX_AIO
void *laio_init(void);
BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type);
#endif
#ifdef _WIN32
typedef struct QEMUWin32AIOState QEMUWin32AIOState;
QEMUWin32AIOState *win32_aio_init(void);
int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile);
BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
QEMUWin32AIOState *aio, HANDLE hfile,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type);
#endif
#endif /* QEMU_RAW_AIO_H */
#endif /* QEMU_RAW_POSIX_AIO_H */

View File

@@ -22,14 +22,12 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "qemu/timer.h"
#include "qemu/log.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "trace.h"
#include "block/thread-pool.h"
#include "qemu/iov.h"
#include "raw-aio.h"
#include "qemu-timer.h"
#include "qemu-char.h"
#include "qemu-log.h"
#include "block_int.h"
#include "module.h"
#include "block/raw-posix-aio.h"
#if defined(__APPLE__) && (__MACH__)
#include <paths.h>
@@ -59,9 +57,6 @@
#ifdef CONFIG_FIEMAP
#include <linux/fiemap.h>
#endif
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
#include <linux/falloc.h>
#endif
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <sys/disk.h>
#include <sys/cdio.h>
@@ -138,37 +133,16 @@ typedef struct BDRVRawState {
int use_aio;
void *aio_ctx;
#endif
uint8_t *aligned_buf;
unsigned aligned_buf_size;
#ifdef CONFIG_XFS
bool is_xfs : 1;
#endif
bool has_discard : 1;
} BDRVRawState;
typedef struct BDRVRawReopenState {
int fd;
int open_flags;
#ifdef CONFIG_LINUX_AIO
int use_aio;
#endif
} BDRVRawReopenState;
static int fd_open(BlockDriverState *bs);
static int64_t raw_getlength(BlockDriverState *bs);
typedef struct RawPosixAIOData {
BlockDriverState *bs;
int aio_fildes;
union {
struct iovec *aio_iov;
void *aio_ioctl_buf;
};
int aio_niov;
uint64_t aio_nbytes;
#define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */
off_t aio_offset;
int aio_type;
} RawPosixAIOData;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
static int cdrom_reopen(BlockDriverState *bs);
#endif
@@ -211,57 +185,6 @@ static int raw_normalize_devicepath(const char **filename)
}
#endif
static void raw_parse_flags(int bdrv_flags, int *open_flags)
{
assert(open_flags != NULL);
*open_flags |= O_BINARY;
*open_flags &= ~O_ACCMODE;
if (bdrv_flags & BDRV_O_RDWR) {
*open_flags |= O_RDWR;
} else {
*open_flags |= O_RDONLY;
}
/* Use O_DSYNC for write-through caching, no flags for write-back caching,
* and O_DIRECT for no caching. */
if ((bdrv_flags & BDRV_O_NOCACHE)) {
*open_flags |= O_DIRECT;
}
}
#ifdef CONFIG_LINUX_AIO
static int raw_set_aio(void **aio_ctx, int *use_aio, int bdrv_flags)
{
int ret = -1;
assert(aio_ctx != NULL);
assert(use_aio != NULL);
/*
* Currently Linux do AIO only for files opened with O_DIRECT
* specified so check NOCACHE flag too
*/
if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) ==
(BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) {
/* if non-NULL, laio_init() has already been run */
if (*aio_ctx == NULL) {
*aio_ctx = laio_init();
if (!*aio_ctx) {
goto error;
}
}
*use_aio = 1;
} else {
*use_aio = 0;
}
ret = 0;
error:
return ret;
}
#endif
static int raw_open_common(BlockDriverState *bs, const char *filename,
int bdrv_flags, int open_flags)
{
@@ -273,8 +196,20 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
return ret;
}
s->open_flags = open_flags;
raw_parse_flags(bdrv_flags, &s->open_flags);
s->open_flags = open_flags | O_BINARY;
s->open_flags &= ~O_ACCMODE;
if (bdrv_flags & BDRV_O_RDWR) {
s->open_flags |= O_RDWR;
} else {
s->open_flags |= O_RDONLY;
}
/* Use O_DSYNC for write-through caching, no flags for write-back caching,
* and O_DIRECT for no caching. */
if ((bdrv_flags & BDRV_O_NOCACHE))
s->open_flags |= O_DIRECT;
if (!(bdrv_flags & BDRV_O_CACHE_WB))
s->open_flags |= O_DSYNC;
s->fd = -1;
fd = qemu_open(filename, s->open_flags, 0644);
@@ -285,15 +220,46 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
return ret;
}
s->fd = fd;
s->aligned_buf = NULL;
if ((bdrv_flags & BDRV_O_NOCACHE)) {
/*
* Allocate a buffer for read/modify/write cycles. Chose the size
* pessimistically as we don't know the block size yet.
*/
s->aligned_buf_size = 32 * MAX_BLOCKSIZE;
s->aligned_buf = qemu_memalign(MAX_BLOCKSIZE, s->aligned_buf_size);
if (s->aligned_buf == NULL) {
goto out_close;
}
}
/* We're falling back to POSIX AIO in some cases so init always */
if (paio_init() < 0) {
goto out_free_buf;
}
#ifdef CONFIG_LINUX_AIO
if (raw_set_aio(&s->aio_ctx, &s->use_aio, bdrv_flags)) {
qemu_close(fd);
return -errno;
}
#endif
/*
* Currently Linux do AIO only for files opened with O_DIRECT
* specified so check NOCACHE flag too
*/
if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) ==
(BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) {
s->aio_ctx = laio_init();
if (!s->aio_ctx) {
goto out_free_buf;
}
s->use_aio = 1;
} else
#endif
{
#ifdef CONFIG_LINUX_AIO
s->use_aio = 0;
#endif
}
s->has_discard = 1;
#ifdef CONFIG_XFS
if (platform_test_xfs_fd(s->fd)) {
s->is_xfs = 1;
@@ -301,6 +267,12 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
#endif
return 0;
out_free_buf:
qemu_vfree(s->aligned_buf);
out_close:
qemu_close(fd);
return -errno;
}
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
@@ -311,122 +283,6 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
return raw_open_common(bs, filename, flags, 0);
}
static int raw_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
BDRVRawState *s;
BDRVRawReopenState *raw_s;
int ret = 0;
assert(state != NULL);
assert(state->bs != NULL);
s = state->bs->opaque;
state->opaque = g_malloc0(sizeof(BDRVRawReopenState));
raw_s = state->opaque;
#ifdef CONFIG_LINUX_AIO
raw_s->use_aio = s->use_aio;
/* we can use s->aio_ctx instead of a copy, because the use_aio flag is
* valid in the 'false' condition even if aio_ctx is set, and raw_set_aio()
* won't override aio_ctx if aio_ctx is non-NULL */
if (raw_set_aio(&s->aio_ctx, &raw_s->use_aio, state->flags)) {
return -1;
}
#endif
if (s->type == FTYPE_FD || s->type == FTYPE_CD) {
raw_s->open_flags |= O_NONBLOCK;
}
raw_parse_flags(state->flags, &raw_s->open_flags);
raw_s->fd = -1;
int fcntl_flags = O_APPEND | O_NONBLOCK;
#ifdef O_NOATIME
fcntl_flags |= O_NOATIME;
#endif
#ifdef O_ASYNC
/* Not all operating systems have O_ASYNC, and those that don't
* will not let us track the state into raw_s->open_flags (typically
* you achieve the same effect with an ioctl, for example I_SETSIG
* on Solaris). But we do not use O_ASYNC, so that's fine.
*/
assert((s->open_flags & O_ASYNC) == 0);
#endif
if ((raw_s->open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) {
/* dup the original fd */
/* TODO: use qemu fcntl wrapper */
#ifdef F_DUPFD_CLOEXEC
raw_s->fd = fcntl(s->fd, F_DUPFD_CLOEXEC, 0);
#else
raw_s->fd = dup(s->fd);
if (raw_s->fd != -1) {
qemu_set_cloexec(raw_s->fd);
}
#endif
if (raw_s->fd >= 0) {
ret = fcntl_setfl(raw_s->fd, raw_s->open_flags);
if (ret) {
qemu_close(raw_s->fd);
raw_s->fd = -1;
}
}
}
/* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */
if (raw_s->fd == -1) {
assert(!(raw_s->open_flags & O_CREAT));
raw_s->fd = qemu_open(state->bs->filename, raw_s->open_flags);
if (raw_s->fd == -1) {
ret = -1;
}
}
return ret;
}
static void raw_reopen_commit(BDRVReopenState *state)
{
BDRVRawReopenState *raw_s = state->opaque;
BDRVRawState *s = state->bs->opaque;
s->open_flags = raw_s->open_flags;
qemu_close(s->fd);
s->fd = raw_s->fd;
#ifdef CONFIG_LINUX_AIO
s->use_aio = raw_s->use_aio;
#endif
g_free(state->opaque);
state->opaque = NULL;
}
static void raw_reopen_abort(BDRVReopenState *state)
{
BDRVRawReopenState *raw_s = state->opaque;
/* nothing to do if NULL, we didn't get far enough */
if (raw_s == NULL) {
return;
}
if (raw_s->fd >= 0) {
qemu_close(raw_s->fd);
raw_s->fd = -1;
}
g_free(state->opaque);
state->opaque = NULL;
}
/* XXX: use host sector size if necessary with:
#ifdef DIOCGSECTORSIZE
{
@@ -444,326 +300,20 @@ static void raw_reopen_abort(BDRVReopenState *state)
#endif
*/
static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb)
{
int ret;
ret = ioctl(aiocb->aio_fildes, aiocb->aio_ioctl_cmd, aiocb->aio_ioctl_buf);
if (ret == -1) {
return -errno;
}
return 0;
}
static ssize_t handle_aiocb_flush(RawPosixAIOData *aiocb)
{
int ret;
ret = qemu_fdatasync(aiocb->aio_fildes);
if (ret == -1) {
return -errno;
}
return 0;
}
#ifdef CONFIG_PREADV
static bool preadv_present = true;
static ssize_t
qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
{
return preadv(fd, iov, nr_iov, offset);
}
static ssize_t
qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
{
return pwritev(fd, iov, nr_iov, offset);
}
#else
static bool preadv_present = false;
static ssize_t
qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
{
return -ENOSYS;
}
static ssize_t
qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
{
return -ENOSYS;
}
#endif
static ssize_t handle_aiocb_rw_vector(RawPosixAIOData *aiocb)
{
ssize_t len;
do {
if (aiocb->aio_type & QEMU_AIO_WRITE)
len = qemu_pwritev(aiocb->aio_fildes,
aiocb->aio_iov,
aiocb->aio_niov,
aiocb->aio_offset);
else
len = qemu_preadv(aiocb->aio_fildes,
aiocb->aio_iov,
aiocb->aio_niov,
aiocb->aio_offset);
} while (len == -1 && errno == EINTR);
if (len == -1) {
return -errno;
}
return len;
}
/*
* Read/writes the data to/from a given linear buffer.
*
* Returns the number of bytes handles or -errno in case of an error. Short
* reads are only returned if the end of the file is reached.
* Check if all memory in this vector is sector aligned.
*/
static ssize_t handle_aiocb_rw_linear(RawPosixAIOData *aiocb, char *buf)
static int qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
{
ssize_t offset = 0;
ssize_t len;
int i;
while (offset < aiocb->aio_nbytes) {
if (aiocb->aio_type & QEMU_AIO_WRITE) {
len = pwrite(aiocb->aio_fildes,
(const char *)buf + offset,
aiocb->aio_nbytes - offset,
aiocb->aio_offset + offset);
} else {
len = pread(aiocb->aio_fildes,
buf + offset,
aiocb->aio_nbytes - offset,
aiocb->aio_offset + offset);
}
if (len == -1 && errno == EINTR) {
continue;
} else if (len == -1) {
offset = -errno;
break;
} else if (len == 0) {
break;
}
offset += len;
}
return offset;
}
static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb)
{
ssize_t nbytes;
char *buf;
if (!(aiocb->aio_type & QEMU_AIO_MISALIGNED)) {
/*
* If there is just a single buffer, and it is properly aligned
* we can just use plain pread/pwrite without any problems.
*/
if (aiocb->aio_niov == 1) {
return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base);
}
/*
* We have more than one iovec, and all are properly aligned.
*
* Try preadv/pwritev first and fall back to linearizing the
* buffer if it's not supported.
*/
if (preadv_present) {
nbytes = handle_aiocb_rw_vector(aiocb);
if (nbytes == aiocb->aio_nbytes ||
(nbytes < 0 && nbytes != -ENOSYS)) {
return nbytes;
}
preadv_present = false;
}
/*
* XXX(hch): short read/write. no easy way to handle the reminder
* using these interfaces. For now retry using plain
* pread/pwrite?
*/
}
/*
* Ok, we have to do it the hard way, copy all segments into
* a single aligned buffer.
*/
buf = qemu_blockalign(aiocb->bs, aiocb->aio_nbytes);
if (aiocb->aio_type & QEMU_AIO_WRITE) {
char *p = buf;
int i;
for (i = 0; i < aiocb->aio_niov; ++i) {
memcpy(p, aiocb->aio_iov[i].iov_base, aiocb->aio_iov[i].iov_len);
p += aiocb->aio_iov[i].iov_len;
for (i = 0; i < qiov->niov; i++) {
if ((uintptr_t) qiov->iov[i].iov_base % bs->buffer_alignment) {
return 0;
}
}
nbytes = handle_aiocb_rw_linear(aiocb, buf);
if (!(aiocb->aio_type & QEMU_AIO_WRITE)) {
char *p = buf;
size_t count = aiocb->aio_nbytes, copy;
int i;
for (i = 0; i < aiocb->aio_niov && count; ++i) {
copy = count;
if (copy > aiocb->aio_iov[i].iov_len) {
copy = aiocb->aio_iov[i].iov_len;
}
memcpy(aiocb->aio_iov[i].iov_base, p, copy);
p += copy;
count -= copy;
}
}
qemu_vfree(buf);
return nbytes;
}
#ifdef CONFIG_XFS
static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes)
{
struct xfs_flock64 fl;
memset(&fl, 0, sizeof(fl));
fl.l_whence = SEEK_SET;
fl.l_start = offset;
fl.l_len = bytes;
if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) {
DEBUG_BLOCK_PRINT("cannot punch hole (%s)\n", strerror(errno));
return -errno;
}
return 0;
}
#endif
static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb)
{
int ret = -EOPNOTSUPP;
BDRVRawState *s = aiocb->bs->opaque;
if (s->has_discard == 0) {
return 0;
}
if (aiocb->aio_type & QEMU_AIO_BLKDEV) {
#ifdef BLKDISCARD
do {
uint64_t range[2] = { aiocb->aio_offset, aiocb->aio_nbytes };
if (ioctl(aiocb->aio_fildes, BLKDISCARD, range) == 0) {
return 0;
}
} while (errno == EINTR);
ret = -errno;
#endif
} else {
#ifdef CONFIG_XFS
if (s->is_xfs) {
return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes);
}
#endif
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
do {
if (fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
aiocb->aio_offset, aiocb->aio_nbytes) == 0) {
return 0;
}
} while (errno == EINTR);
ret = -errno;
#endif
}
if (ret == -ENODEV || ret == -ENOSYS || ret == -EOPNOTSUPP ||
ret == -ENOTTY) {
s->has_discard = 0;
ret = 0;
}
return ret;
}
static int aio_worker(void *arg)
{
RawPosixAIOData *aiocb = arg;
ssize_t ret = 0;
switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
case QEMU_AIO_READ:
ret = handle_aiocb_rw(aiocb);
if (ret >= 0 && ret < aiocb->aio_nbytes && aiocb->bs->growable) {
iov_memset(aiocb->aio_iov, aiocb->aio_niov, ret,
0, aiocb->aio_nbytes - ret);
ret = aiocb->aio_nbytes;
}
if (ret == aiocb->aio_nbytes) {
ret = 0;
} else if (ret >= 0 && ret < aiocb->aio_nbytes) {
ret = -EINVAL;
}
break;
case QEMU_AIO_WRITE:
ret = handle_aiocb_rw(aiocb);
if (ret == aiocb->aio_nbytes) {
ret = 0;
} else if (ret >= 0 && ret < aiocb->aio_nbytes) {
ret = -EINVAL;
}
break;
case QEMU_AIO_FLUSH:
ret = handle_aiocb_flush(aiocb);
break;
case QEMU_AIO_IOCTL:
ret = handle_aiocb_ioctl(aiocb);
break;
case QEMU_AIO_DISCARD:
ret = handle_aiocb_discard(aiocb);
break;
default:
fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
ret = -EINVAL;
break;
}
g_slice_free(RawPosixAIOData, aiocb);
return ret;
}
static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type)
{
RawPosixAIOData *acb = g_slice_new(RawPosixAIOData);
acb->bs = bs;
acb->aio_type = type;
acb->aio_fildes = fd;
if (qiov) {
acb->aio_iov = qiov->iov;
acb->aio_niov = qiov->niov;
}
acb->aio_nbytes = nb_sectors * 512;
acb->aio_offset = sector_num * 512;
trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
return 1;
}
static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
@@ -780,8 +330,8 @@ static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
* boundary. Check if this is the case or tell the low-level
* driver that it needs to copy the buffer.
*/
if ((bs->open_flags & BDRV_O_NOCACHE)) {
if (!bdrv_qiov_is_aligned(bs, qiov)) {
if (s->aligned_buf) {
if (!qiov_is_aligned(bs, qiov)) {
type |= QEMU_AIO_MISALIGNED;
#ifdef CONFIG_LINUX_AIO
} else if (s->use_aio) {
@@ -828,6 +378,8 @@ static void raw_close(BlockDriverState *bs)
if (s->fd >= 0) {
qemu_close(s->fd);
s->fd = -1;
if (s->aligned_buf != NULL)
qemu_vfree(s->aligned_buf);
}
}
@@ -1135,14 +687,37 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs,
}
}
static coroutine_fn BlockDriverAIOCB *raw_aio_discard(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
#ifdef CONFIG_XFS
static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors)
{
struct xfs_flock64 fl;
memset(&fl, 0, sizeof(fl));
fl.l_whence = SEEK_SET;
fl.l_start = sector_num << 9;
fl.l_len = (int64_t)nb_sectors << 9;
if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) {
DEBUG_BLOCK_PRINT("cannot punch hole (%s)\n", strerror(errno));
return -errno;
}
return 0;
}
#endif
static coroutine_fn int raw_co_discard(BlockDriverState *bs,
int64_t sector_num, int nb_sectors)
{
#ifdef CONFIG_XFS
BDRVRawState *s = bs->opaque;
return paio_submit(bs, s->fd, sector_num, NULL, nb_sectors,
cb, opaque, QEMU_AIO_DISCARD);
if (s->is_xfs) {
return xfs_discard(s, sector_num, nb_sectors);
}
#endif
return 0;
}
static QEMUOptionParameter raw_create_options[] = {
@@ -1160,17 +735,14 @@ static BlockDriver bdrv_file = {
.instance_size = sizeof(BDRVRawState),
.bdrv_probe = NULL, /* no probe for protocols */
.bdrv_file_open = raw_open,
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
.bdrv_reopen_abort = raw_reopen_abort,
.bdrv_close = raw_close,
.bdrv_create = raw_create,
.bdrv_co_discard = raw_co_discard,
.bdrv_co_is_allocated = raw_co_is_allocated,
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
.bdrv_aio_discard = raw_aio_discard,
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
@@ -1257,43 +829,9 @@ static int hdev_probe_device(const char *filename)
return 0;
}
static int check_hdev_writable(BDRVRawState *s)
{
#if defined(BLKROGET)
/* Linux block devices can be configured "read-only" using blockdev(8).
* This is independent of device node permissions and therefore open(2)
* with O_RDWR succeeds. Actual writes fail with EPERM.
*
* bdrv_open() is supposed to fail if the disk is read-only. Explicitly
* check for read-only block devices so that Linux block devices behave
* properly.
*/
struct stat st;
int readonly = 0;
if (fstat(s->fd, &st)) {
return -errno;
}
if (!S_ISBLK(st.st_mode)) {
return 0;
}
if (ioctl(s->fd, BLKROGET, &readonly) < 0) {
return -errno;
}
if (readonly) {
return -EACCES;
}
#endif /* defined(BLKROGET) */
return 0;
}
static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
int ret;
#if defined(__APPLE__) && defined(__MACH__)
if (strstart(filename, "/dev/cdrom", NULL)) {
@@ -1334,20 +872,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
}
#endif
ret = raw_open_common(bs, filename, flags, 0);
if (ret < 0) {
return ret;
}
if (flags & BDRV_O_RDWR) {
ret = check_hdev_writable(s);
if (ret < 0) {
raw_close(bs);
return ret;
}
}
return ret;
return raw_open_common(bs, filename, flags, 0);
}
#if defined(__linux__)
@@ -1412,19 +937,10 @@ static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
RawPosixAIOData *acb;
if (fd_open(bs) < 0)
return NULL;
acb = g_slice_new(RawPosixAIOData);
acb->bs = bs;
acb->aio_type = QEMU_AIO_IOCTL;
acb->aio_fildes = s->fd;
acb->aio_offset = 0;
acb->aio_ioctl_buf = buf;
acb->aio_ioctl_cmd = req;
return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
return paio_ioctl(bs, s->fd, req, buf, cb, opaque);
}
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -1446,19 +962,6 @@ static int fd_open(BlockDriverState *bs)
#endif /* !linux && !FreeBSD */
static coroutine_fn BlockDriverAIOCB *hdev_aio_discard(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
if (fd_open(bs) < 0) {
return NULL;
}
return paio_submit(bs, s->fd, sector_num, NULL, nb_sectors,
cb, opaque, QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV);
}
static int hdev_create(const char *filename, QEMUOptionParameter *options)
{
int fd;
@@ -1501,9 +1004,6 @@ static BlockDriver bdrv_host_device = {
.bdrv_probe_device = hdev_probe_device,
.bdrv_file_open = hdev_open,
.bdrv_close = raw_close,
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
.bdrv_reopen_abort = raw_reopen_abort,
.bdrv_create = hdev_create,
.create_options = raw_create_options,
.bdrv_has_zero_init = hdev_has_zero_init,
@@ -1511,7 +1011,6 @@ static BlockDriver bdrv_host_device = {
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
.bdrv_aio_discard = hdev_aio_discard,
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
@@ -1626,9 +1125,6 @@ static BlockDriver bdrv_host_floppy = {
.bdrv_probe_device = floppy_probe_device,
.bdrv_file_open = floppy_open,
.bdrv_close = raw_close,
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
.bdrv_reopen_abort = raw_reopen_abort,
.bdrv_create = hdev_create,
.create_options = raw_create_options,
.bdrv_has_zero_init = hdev_has_zero_init,
@@ -1728,9 +1224,6 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_probe_device = cdrom_probe_device,
.bdrv_file_open = cdrom_open,
.bdrv_close = raw_close,
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
.bdrv_reopen_abort = raw_reopen_abort,
.bdrv_create = hdev_create,
.create_options = raw_create_options,
.bdrv_has_zero_init = hdev_has_zero_init,
@@ -1850,9 +1343,6 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_probe_device = cdrom_probe_device,
.bdrv_file_open = cdrom_open,
.bdrv_close = raw_close,
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
.bdrv_reopen_abort = raw_reopen_abort,
.bdrv_create = hdev_create,
.create_options = raw_create_options,
.bdrv_has_zero_init = hdev_has_zero_init,
@@ -1873,40 +1363,6 @@ static BlockDriver bdrv_host_cdrom = {
};
#endif /* __FreeBSD__ */
#ifdef CONFIG_LINUX_AIO
/**
* Return the file descriptor for Linux AIO
*
* This function is a layering violation and should be removed when it becomes
* possible to call the block layer outside the global mutex. It allows the
* caller to hijack the file descriptor so I/O can be performed outside the
* block layer.
*/
int raw_get_aio_fd(BlockDriverState *bs)
{
BDRVRawState *s;
if (!bs->drv) {
return -ENOMEDIUM;
}
if (bs->drv == bdrv_find_format("raw")) {
bs = bs->file;
}
/* raw-posix has several protocols so just check for raw_aio_readv */
if (bs->drv->bdrv_aio_readv != raw_aio_readv) {
return -ENOTSUP;
}
s = bs->opaque;
if (!s->use_aio) {
return -ENOTSUP;
}
return s->fd;
}
#endif /* CONFIG_LINUX_AIO */
static void bdrv_file_init(void)
{
/*

View File

@@ -22,13 +22,9 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "qemu/timer.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "raw-aio.h"
#include "trace.h"
#include "block/thread-pool.h"
#include "qemu/iov.h"
#include "qemu-timer.h"
#include "block_int.h"
#include "module.h"
#include <windows.h>
#include <winioctl.h>
@@ -36,130 +32,12 @@
#define FTYPE_CD 1
#define FTYPE_HARDDISK 2
static QEMUWin32AIOState *aio;
typedef struct RawWin32AIOData {
BlockDriverState *bs;
HANDLE hfile;
struct iovec *aio_iov;
int aio_niov;
size_t aio_nbytes;
off64_t aio_offset;
int aio_type;
} RawWin32AIOData;
typedef struct BDRVRawState {
HANDLE hfile;
int type;
char drive_path[16]; /* format: "d:\" */
QEMUWin32AIOState *aio;
} BDRVRawState;
/*
* Read/writes the data to/from a given linear buffer.
*
* Returns the number of bytes handles or -errno in case of an error. Short
* reads are only returned if the end of the file is reached.
*/
static size_t handle_aiocb_rw(RawWin32AIOData *aiocb)
{
size_t offset = 0;
int i;
for (i = 0; i < aiocb->aio_niov; i++) {
OVERLAPPED ov;
DWORD ret, ret_count, len;
memset(&ov, 0, sizeof(ov));
ov.Offset = (aiocb->aio_offset + offset);
ov.OffsetHigh = (aiocb->aio_offset + offset) >> 32;
len = aiocb->aio_iov[i].iov_len;
if (aiocb->aio_type & QEMU_AIO_WRITE) {
ret = WriteFile(aiocb->hfile, aiocb->aio_iov[i].iov_base,
len, &ret_count, &ov);
} else {
ret = ReadFile(aiocb->hfile, aiocb->aio_iov[i].iov_base,
len, &ret_count, &ov);
}
if (!ret) {
ret_count = 0;
}
if (ret_count != len) {
break;
}
offset += len;
}
return offset;
}
static int aio_worker(void *arg)
{
RawWin32AIOData *aiocb = arg;
ssize_t ret = 0;
size_t count;
switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
case QEMU_AIO_READ:
count = handle_aiocb_rw(aiocb);
if (count < aiocb->aio_nbytes && aiocb->bs->growable) {
/* A short read means that we have reached EOF. Pad the buffer
* with zeros for bytes after EOF. */
iov_memset(aiocb->aio_iov, aiocb->aio_niov, count,
0, aiocb->aio_nbytes - count);
count = aiocb->aio_nbytes;
}
if (count == aiocb->aio_nbytes) {
ret = 0;
} else {
ret = -EINVAL;
}
break;
case QEMU_AIO_WRITE:
count = handle_aiocb_rw(aiocb);
if (count == aiocb->aio_nbytes) {
count = 0;
} else {
count = -EINVAL;
}
break;
case QEMU_AIO_FLUSH:
if (!FlushFileBuffers(aiocb->hfile)) {
return -EIO;
}
break;
default:
fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
ret = -EINVAL;
break;
}
g_slice_free(RawWin32AIOData, aiocb);
return ret;
}
static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type)
{
RawWin32AIOData *acb = g_slice_new(RawWin32AIOData);
acb->bs = bs;
acb->hfile = hfile;
acb->aio_type = type;
if (qiov) {
acb->aio_iov = qiov->iov;
acb->aio_niov = qiov->niov;
}
acb->aio_nbytes = nb_sectors * 512;
acb->aio_offset = sector_num * 512;
trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
}
int qemu_ftruncate64(int fd, int64_t length)
{
LARGE_INTEGER li;
@@ -199,26 +77,6 @@ static int set_sparse(int fd)
NULL, 0, NULL, 0, &returned, NULL);
}
static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped)
{
assert(access_flags != NULL);
assert(overlapped != NULL);
if (flags & BDRV_O_RDWR) {
*access_flags = GENERIC_READ | GENERIC_WRITE;
} else {
*access_flags = GENERIC_READ;
}
*overlapped = FILE_ATTRIBUTE_NORMAL;
if (flags & BDRV_O_NATIVE_AIO) {
*overlapped |= FILE_FLAG_OVERLAPPED;
}
if (flags & BDRV_O_NOCACHE) {
*overlapped |= FILE_FLAG_NO_BUFFERING;
}
}
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
@@ -227,15 +85,17 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
s->type = FTYPE_FILE;
raw_parse_flags(flags, &access_flags, &overlapped);
if ((flags & BDRV_O_NATIVE_AIO) && aio == NULL) {
aio = win32_aio_init();
if (aio == NULL) {
return -EINVAL;
}
if (flags & BDRV_O_RDWR) {
access_flags = GENERIC_READ | GENERIC_WRITE;
} else {
access_flags = GENERIC_READ;
}
overlapped = FILE_ATTRIBUTE_NORMAL;
if (flags & BDRV_O_NOCACHE)
overlapped |= FILE_FLAG_NO_BUFFERING;
if (!(flags & BDRV_O_CACHE_WB))
overlapped |= FILE_FLAG_WRITE_THROUGH;
s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
OPEN_EXISTING, overlapped, NULL);
@@ -244,53 +104,64 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
if (err == ERROR_ACCESS_DENIED)
return -EACCES;
return -EINVAL;
}
if (flags & BDRV_O_NATIVE_AIO) {
int ret = win32_aio_attach(aio, s->hfile);
if (ret < 0) {
CloseHandle(s->hfile);
return ret;
}
s->aio = aio;
return -1;
}
return 0;
}
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
static int raw_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVRawState *s = bs->opaque;
if (s->aio) {
return win32_aio_submit(bs, s->aio, s->hfile, sector_num, qiov,
nb_sectors, cb, opaque, QEMU_AIO_READ);
} else {
return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors,
cb, opaque, QEMU_AIO_READ);
}
OVERLAPPED ov;
DWORD ret_count;
int ret;
int64_t offset = sector_num * 512;
int count = nb_sectors * 512;
memset(&ov, 0, sizeof(ov));
ov.Offset = offset;
ov.OffsetHigh = offset >> 32;
ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
if (!ret)
return ret_count;
if (ret_count == count)
ret_count = 0;
return ret_count;
}
static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
static int raw_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVRawState *s = bs->opaque;
if (s->aio) {
return win32_aio_submit(bs, s->aio, s->hfile, sector_num, qiov,
nb_sectors, cb, opaque, QEMU_AIO_WRITE);
} else {
return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors,
cb, opaque, QEMU_AIO_WRITE);
}
OVERLAPPED ov;
DWORD ret_count;
int ret;
int64_t offset = sector_num * 512;
int count = nb_sectors * 512;
memset(&ov, 0, sizeof(ov));
ov.Offset = offset;
ov.OffsetHigh = offset >> 32;
ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
if (!ret)
return ret_count;
if (ret_count == count)
ret_count = 0;
return ret_count;
}
static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
static int raw_flush(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
return paio_submit(bs, s->hfile, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);
int ret;
ret = FlushFileBuffers(s->hfile);
if (ret == 0) {
return -EIO;
}
return 0;
}
static void raw_close(BlockDriverState *bs)
@@ -303,24 +174,13 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset)
{
BDRVRawState *s = bs->opaque;
LONG low, high;
DWORD dwPtrLow;
low = offset;
high = offset >> 32;
/*
* An error has occurred if the return value is INVALID_SET_FILE_POINTER
* and GetLastError doesn't return NO_ERROR.
*/
dwPtrLow = SetFilePointer(s->hfile, low, &high, FILE_BEGIN);
if (dwPtrLow == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
fprintf(stderr, "SetFilePointer error: %lu\n", GetLastError());
if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
return -EIO;
if (!SetEndOfFile(s->hfile))
return -EIO;
}
if (SetEndOfFile(s->hfile) == 0) {
fprintf(stderr, "SetEndOfFile error: %lu\n", GetLastError());
return -EIO;
}
return 0;
}
@@ -422,9 +282,9 @@ static BlockDriver bdrv_file = {
.bdrv_close = raw_close,
.bdrv_create = raw_create,
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
.bdrv_read = raw_read,
.bdrv_write = raw_write,
.bdrv_co_flush_to_disk = raw_flush,
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
@@ -514,10 +374,18 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
}
s->type = find_device_type(bs, filename);
raw_parse_flags(flags, &access_flags, &overlapped);
if (flags & BDRV_O_RDWR) {
access_flags = GENERIC_READ | GENERIC_WRITE;
} else {
access_flags = GENERIC_READ;
}
create_flags = OPEN_EXISTING;
overlapped = FILE_ATTRIBUTE_NORMAL;
if (flags & BDRV_O_NOCACHE)
overlapped |= FILE_FLAG_NO_BUFFERING;
if (!(flags & BDRV_O_CACHE_WB))
overlapped |= FILE_FLAG_WRITE_THROUGH;
s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
create_flags, overlapped, NULL);
@@ -545,9 +413,9 @@ static BlockDriver bdrv_host_device = {
.bdrv_close = raw_close,
.bdrv_has_zero_init = hdev_has_zero_init,
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
.bdrv_read = raw_read,
.bdrv_write = raw_write,
.bdrv_co_flush_to_disk = raw_flush,
.bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size

View File

@@ -1,7 +1,7 @@
#include "qemu-common.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "block_int.h"
#include "module.h"
static int raw_open(BlockDriverState *bs, int flags)
{
@@ -9,14 +9,6 @@ static int raw_open(BlockDriverState *bs, int flags)
return 0;
}
/* We have nothing to do for raw reopen, stubs just return
* success */
static int raw_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
return 0;
}
static int coroutine_fn raw_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
@@ -123,8 +115,6 @@ static BlockDriver bdrv_raw = {
.bdrv_open = raw_open,
.bdrv_close = raw_close,
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_co_readv = raw_co_readv,
.bdrv_co_writev = raw_co_writev,
.bdrv_co_is_allocated = raw_co_is_allocated,

View File

@@ -14,8 +14,8 @@
#include <inttypes.h>
#include "qemu-common.h"
#include "qemu/error-report.h"
#include "block/block_int.h"
#include "qemu-error.h"
#include "block_int.h"
#include <rbd/librbd.h>
@@ -69,7 +69,7 @@ typedef enum {
typedef struct RBDAIOCB {
BlockDriverAIOCB common;
QEMUBH *bh;
int64_t ret;
int ret;
QEMUIOVector *qiov;
char *bounce;
RBDAIOCmd cmd;
@@ -77,7 +77,6 @@ typedef struct RBDAIOCB {
int error;
struct BDRVRBDState *s;
int cancelled;
int status;
} RBDAIOCB;
typedef struct RADOSCB {
@@ -87,7 +86,7 @@ typedef struct RADOSCB {
int done;
int64_t size;
char *buf;
int64_t ret;
int ret;
} RADOSCB;
#define RBD_FD_READ 0
@@ -377,6 +376,12 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
RBDAIOCB *acb = rcb->acb;
int64_t r;
if (acb->cancelled) {
qemu_vfree(acb->bounce);
qemu_aio_release(acb);
goto done;
}
r = rcb->ret;
if (acb->cmd == RBD_AIO_WRITE ||
@@ -404,6 +409,7 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
/* Note that acb->bh can be NULL in case where the aio was cancelled */
acb->bh = qemu_bh_new(rbd_aio_bh_cb, acb);
qemu_bh_schedule(acb->bh);
done:
g_free(rcb);
}
@@ -481,6 +487,12 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
rados_conf_set(s->cluster, "rbd_cache", "false");
} else {
rados_conf_set(s->cluster, "rbd_cache", "true");
if (!(flags & BDRV_O_CACHE_WB)) {
r = rados_conf_set(s->cluster, "rbd_cache_max_dirty", "0");
if (r < 0) {
rados_conf_set(s->cluster, "rbd_cache", "false");
}
}
}
if (strstr(conf, "conf=") == NULL) {
@@ -562,15 +574,9 @@ static void qemu_rbd_aio_cancel(BlockDriverAIOCB *blockacb)
{
RBDAIOCB *acb = (RBDAIOCB *) blockacb;
acb->cancelled = 1;
while (acb->status == -EINPROGRESS) {
qemu_aio_wait();
}
qemu_aio_release(acb);
}
static const AIOCBInfo rbd_aiocb_info = {
static AIOPool rbd_aio_pool = {
.aiocb_size = sizeof(RBDAIOCB),
.cancel = qemu_rbd_aio_cancel,
};
@@ -639,11 +645,8 @@ static void rbd_aio_bh_cb(void *opaque)
acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
qemu_bh_delete(acb->bh);
acb->bh = NULL;
acb->status = 0;
if (!acb->cancelled) {
qemu_aio_release(acb);
}
qemu_aio_release(acb);
}
static int rbd_aio_discard_wrapper(rbd_image_t image,
@@ -675,7 +678,7 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
BDRVRBDState *s = bs->opaque;
acb = qemu_aio_get(&rbd_aiocb_info, bs, cb, opaque);
acb = qemu_aio_get(&rbd_aio_pool, bs, cb, opaque);
acb->cmd = cmd;
acb->qiov = qiov;
if (cmd == RBD_AIO_DISCARD) {
@@ -688,7 +691,6 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
acb->s = s;
acb->cancelled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
if (cmd == RBD_AIO_WRITE) {
qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);

View File

@@ -13,10 +13,10 @@
*/
#include "qemu-common.h"
#include "qemu/error-report.h"
#include "qemu/sockets.h"
#include "block/block_int.h"
#include "qemu/bitops.h"
#include "qemu-error.h"
#include "qemu_socket.h"
#include "block_int.h"
#include "bitops.h"
#define SD_PROTO_VER 0x01
@@ -36,8 +36,7 @@
#define SD_FLAG_CMD_WRITE 0x01
#define SD_FLAG_CMD_COW 0x02
#define SD_FLAG_CMD_CACHE 0x04 /* Writeback mode for cache */
#define SD_FLAG_CMD_DIRECT 0x08 /* Don't use cache */
#define SD_FLAG_CMD_CACHE 0x04
#define SD_RES_SUCCESS 0x00 /* Success */
#define SD_RES_UNKNOWN 0x01 /* Unknown error */
@@ -145,7 +144,7 @@ typedef struct SheepdogVdiReq {
uint32_t id;
uint32_t data_length;
uint64_t vdi_size;
uint32_t vdi_id;
uint32_t base_vdi_id;
uint32_t copies;
uint32_t snapid;
uint32_t pad[3];
@@ -202,12 +201,12 @@ static inline uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval)
return hval;
}
static inline bool is_data_obj_writable(SheepdogInode *inode, unsigned int idx)
static inline int is_data_obj_writable(SheepdogInode *inode, unsigned int idx)
{
return inode->vdi_id == inode->data_vdi_id[idx];
}
static inline bool is_data_obj(uint64_t oid)
static inline int is_data_obj(uint64_t oid)
{
return !(VDI_BIT & oid);
}
@@ -232,7 +231,7 @@ static inline uint64_t vid_to_data_oid(uint32_t vid, uint32_t idx)
return ((uint64_t)vid << VDI_SPACE_SHIFT) | idx;
}
static inline bool is_snapshot(struct SheepdogInode *inode)
static inline int is_snapshot(struct SheepdogInode *inode)
{
return !!inode->snap_ctime;
}
@@ -266,7 +265,6 @@ typedef struct AIOReq {
enum AIOCBState {
AIOCB_WRITE_UDATA,
AIOCB_READ_UDATA,
AIOCB_FLUSH_CACHE,
};
struct SheepdogAIOCB {
@@ -283,7 +281,7 @@ struct SheepdogAIOCB {
Coroutine *coroutine;
void (*aio_done_func)(SheepdogAIOCB *);
bool canceled;
int canceled;
int nr_pending;
};
@@ -294,12 +292,13 @@ typedef struct BDRVSheepdogState {
uint32_t max_dirty_data_idx;
char name[SD_MAX_VDI_LEN];
bool is_snapshot;
uint32_t cache_flags;
int is_snapshot;
uint8_t cache_enabled;
char *addr;
char *port;
int fd;
int flush_fd;
CoMutex lock;
Coroutine *co_send;
@@ -418,20 +417,21 @@ static void sd_aio_cancel(BlockDriverAIOCB *blockacb)
*/
acb->ret = -EIO;
qemu_coroutine_enter(acb->coroutine, NULL);
acb->canceled = true;
acb->canceled = 1;
}
static const AIOCBInfo sd_aiocb_info = {
static AIOPool sd_aio_pool = {
.aiocb_size = sizeof(SheepdogAIOCB),
.cancel = sd_aio_cancel,
};
static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
int64_t sector_num, int nb_sectors)
int64_t sector_num, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
SheepdogAIOCB *acb;
acb = qemu_aio_get(&sd_aiocb_info, bs, NULL, NULL);
acb = qemu_aio_get(&sd_aio_pool, bs, cb, opaque);
acb->qiov = qiov;
@@ -439,7 +439,7 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
acb->nb_sectors = nb_sectors;
acb->aio_done_func = NULL;
acb->canceled = false;
acb->canceled = 0;
acb->coroutine = qemu_coroutine_self();
acb->ret = 0;
acb->nr_pending = 0;
@@ -549,7 +549,7 @@ static coroutine_fn void do_co_req(void *opaque)
co = qemu_coroutine_self();
qemu_aio_set_fd_handler(sockfd, NULL, restart_co_req, NULL, co);
qemu_set_block(sockfd);
socket_set_block(sockfd);
ret = send_co_req(sockfd, hdr, data, wlen);
if (ret < 0) {
goto out;
@@ -579,7 +579,7 @@ static coroutine_fn void do_co_req(void *opaque)
ret = 0;
out:
qemu_aio_set_fd_handler(sockfd, NULL, NULL, NULL, NULL);
qemu_set_nonblock(sockfd);
socket_set_nonblock(sockfd);
srco->ret = ret;
srco->finished = true;
@@ -613,7 +613,7 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data,
}
static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
struct iovec *iov, int niov, bool create,
struct iovec *iov, int niov, int create,
enum AIOCBState aiocb_type);
@@ -646,7 +646,7 @@ static void coroutine_fn send_pending_req(BDRVSheepdogState *s, uint64_t oid)
QLIST_REMOVE(aio_req, aio_siblings);
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
ret = add_aio_request(s, aio_req, acb->qiov->iov,
acb->qiov->niov, false, acb->aiocb_type);
acb->qiov->niov, 0, acb->aiocb_type);
if (ret < 0) {
error_report("add_aio_request is failed");
free_aio_req(s, aio_req);
@@ -714,17 +714,16 @@ static void coroutine_fn aio_read_response(void *opaque)
* and max_dirty_data_idx are changed to include updated
* index between them.
*/
if (rsp.result == SD_RES_SUCCESS) {
s->inode.data_vdi_id[idx] = s->inode.vdi_id;
s->max_dirty_data_idx = MAX(idx, s->max_dirty_data_idx);
s->min_dirty_data_idx = MIN(idx, s->min_dirty_data_idx);
}
s->inode.data_vdi_id[idx] = s->inode.vdi_id;
s->max_dirty_data_idx = MAX(idx, s->max_dirty_data_idx);
s->min_dirty_data_idx = MIN(idx, s->min_dirty_data_idx);
/*
* Some requests may be blocked because simultaneous
* create requests are not allowed, so we search the
* pending requests here.
*/
send_pending_req(s, aio_req->oid);
send_pending_req(s, vid_to_data_oid(s->inode.vdi_id, idx));
}
break;
case AIOCB_READ_UDATA:
@@ -735,13 +734,6 @@ static void coroutine_fn aio_read_response(void *opaque)
goto out;
}
break;
case AIOCB_FLUSH_CACHE:
if (rsp.result == SD_RES_INVALID_PARMS) {
dprintf("disable cache since the server doesn't support it\n");
s->cache_flags = SD_FLAG_CMD_DIRECT;
rsp.result = SD_RES_SUCCESS;
}
break;
}
if (rsp.result != SD_RES_SUCCESS) {
@@ -812,7 +804,7 @@ static int get_sheep_fd(BDRVSheepdogState *s)
return fd;
}
qemu_set_nonblock(fd);
socket_set_nonblock(fd);
ret = set_nodelay(fd);
if (ret) {
@@ -874,14 +866,14 @@ static int parse_vdiname(BDRVSheepdogState *s, const char *filename,
s->port = 0;
}
pstrcpy(vdi, SD_MAX_VDI_LEN, p);
strncpy(vdi, p, SD_MAX_VDI_LEN);
p = strchr(vdi, ':');
if (p) {
*p++ = '\0';
*snapid = strtoul(p, NULL, 10);
if (*snapid == 0) {
pstrcpy(tag, SD_MAX_VDI_TAG_LEN, p);
strncpy(tag, p, SD_MAX_VDI_TAG_LEN);
}
} else {
*snapid = CURRENT_VDI_ID; /* search current vdi */
@@ -908,10 +900,7 @@ static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid,
return fd;
}
/* This pair of strncpy calls ensures that the buffer is zero-filled,
* which is desirable since we'll soon be sending those bytes, and
* don't want the send_req to read uninitialized data.
*/
memset(buf, 0, sizeof(buf));
strncpy(buf, filename, SD_MAX_VDI_LEN);
strncpy(buf + SD_MAX_VDI_LEN, tag, SD_MAX_VDI_TAG_LEN);
@@ -951,12 +940,12 @@ out:
}
static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
struct iovec *iov, int niov, bool create,
struct iovec *iov, int niov, int create,
enum AIOCBState aiocb_type)
{
int nr_copies = s->inode.nr_copies;
SheepdogObjReq hdr;
unsigned int wlen = 0;
unsigned int wlen;
int ret;
uint64_t oid = aio_req->oid;
unsigned int datalen = aio_req->data_len;
@@ -970,27 +959,22 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
memset(&hdr, 0, sizeof(hdr));
switch (aiocb_type) {
case AIOCB_FLUSH_CACHE:
hdr.opcode = SD_OP_FLUSH_VDI;
break;
case AIOCB_READ_UDATA:
if (aiocb_type == AIOCB_READ_UDATA) {
wlen = 0;
hdr.opcode = SD_OP_READ_OBJ;
hdr.flags = flags;
break;
case AIOCB_WRITE_UDATA:
if (create) {
hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ;
} else {
hdr.opcode = SD_OP_WRITE_OBJ;
}
} else if (create) {
wlen = datalen;
hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ;
hdr.flags = SD_FLAG_CMD_WRITE | flags;
} else {
wlen = datalen;
hdr.opcode = SD_OP_WRITE_OBJ;
hdr.flags = SD_FLAG_CMD_WRITE | flags;
break;
}
if (s->cache_flags) {
hdr.flags |= s->cache_flags;
if (s->cache_enabled) {
hdr.flags |= SD_FLAG_CMD_CACHE;
}
hdr.oid = oid;
@@ -1035,7 +1019,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
unsigned int datalen, uint64_t offset,
bool write, bool create, uint32_t cache_flags)
int write, int create, uint8_t cache)
{
SheepdogObjReq hdr;
SheepdogObjRsp *rsp = (SheepdogObjRsp *)&hdr;
@@ -1059,7 +1043,9 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
hdr.opcode = SD_OP_READ_OBJ;
}
hdr.flags |= cache_flags;
if (cache) {
hdr.flags |= SD_FLAG_CMD_CACHE;
}
hdr.oid = oid;
hdr.data_length = datalen;
@@ -1082,19 +1068,18 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
}
static int read_object(int fd, char *buf, uint64_t oid, int copies,
unsigned int datalen, uint64_t offset,
uint32_t cache_flags)
unsigned int datalen, uint64_t offset, uint8_t cache)
{
return read_write_object(fd, buf, oid, copies, datalen, offset, false,
false, cache_flags);
return read_write_object(fd, buf, oid, copies, datalen, offset, 0, 0,
cache);
}
static int write_object(int fd, char *buf, uint64_t oid, int copies,
unsigned int datalen, uint64_t offset, bool create,
uint32_t cache_flags)
unsigned int datalen, uint64_t offset, int create,
uint8_t cache)
{
return read_write_object(fd, buf, oid, copies, datalen, offset, true,
create, cache_flags);
return read_write_object(fd, buf, oid, copies, datalen, offset, 1, create,
cache);
}
static int sd_open(BlockDriverState *bs, const char *filename, int flags)
@@ -1129,18 +1114,19 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
goto out;
}
/*
* QEMU block layer emulates writethrough cache as 'writeback + flush', so
* we always set SD_FLAG_CMD_CACHE (writeback cache) as default.
*/
s->cache_flags = SD_FLAG_CMD_CACHE;
if (flags & BDRV_O_NOCACHE) {
s->cache_flags = SD_FLAG_CMD_DIRECT;
if (flags & BDRV_O_CACHE_WB) {
s->cache_enabled = 1;
s->flush_fd = connect_to_sdog(s->addr, s->port);
if (s->flush_fd < 0) {
error_report("failed to connect");
ret = s->flush_fd;
goto out;
}
}
if (snapid || tag[0] != '\0') {
dprintf("%" PRIx32 " snapshot inode was open.\n", vid);
s->is_snapshot = true;
s->is_snapshot = 1;
}
fd = connect_to_sdog(s->addr, s->port);
@@ -1152,7 +1138,7 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
buf = g_malloc(SD_INODE_SIZE);
ret = read_object(fd, buf, vid_to_vdi_oid(vid), 0, SD_INODE_SIZE, 0,
s->cache_flags);
s->cache_enabled);
closesocket(fd);
@@ -1165,7 +1151,7 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
s->max_dirty_data_idx = 0;
bs->total_sectors = s->inode.vdi_size / SECTOR_SIZE;
pstrcpy(s->name, sizeof(s->name), vdi);
strncpy(s->name, vdi, sizeof(s->name));
qemu_co_mutex_init(&s->lock);
g_free(buf);
return 0;
@@ -1193,15 +1179,12 @@ static int do_sd_create(char *filename, int64_t vdi_size,
return fd;
}
/* FIXME: would it be better to fail (e.g., return -EIO) when filename
* does not fit in buf? For now, just truncate and avoid buffer overrun.
*/
memset(buf, 0, sizeof(buf));
pstrcpy(buf, sizeof(buf), filename);
strncpy(buf, filename, SD_MAX_VDI_LEN);
memset(&hdr, 0, sizeof(hdr));
hdr.opcode = SD_OP_NEW_VDI;
hdr.vdi_id = base_vid;
hdr.base_vdi_id = base_vid;
wlen = SD_MAX_VDI_LEN;
@@ -1283,7 +1266,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
BDRVSheepdogState *s;
char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
uint32_t snapid;
bool prealloc = false;
int prealloc = 0;
const char *vdiname;
s = g_malloc0(sizeof(BDRVSheepdogState));
@@ -1305,9 +1288,9 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
backing_file = options->value.s;
} else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
if (!options->value.s || !strcmp(options->value.s, "off")) {
prealloc = false;
prealloc = 0;
} else if (!strcmp(options->value.s, "full")) {
prealloc = true;
prealloc = 1;
} else {
error_report("Invalid preallocation mode: '%s'",
options->value.s);
@@ -1384,7 +1367,6 @@ static void sd_close(BlockDriverState *bs)
memset(&hdr, 0, sizeof(hdr));
hdr.opcode = SD_OP_RELEASE_VDI;
hdr.vdi_id = s->inode.vdi_id;
wlen = strlen(s->name) + 1;
hdr.data_length = wlen;
hdr.flags = SD_FLAG_CMD_WRITE;
@@ -1400,6 +1382,9 @@ static void sd_close(BlockDriverState *bs)
qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL);
closesocket(s->fd);
if (s->cache_enabled) {
closesocket(s->flush_fd);
}
g_free(s->addr);
}
@@ -1433,7 +1418,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id);
s->inode.vdi_size = offset;
ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
s->inode.nr_copies, datalen, 0, false, s->cache_flags);
s->inode.nr_copies, datalen, 0, 0, s->cache_enabled);
close(fd);
if (ret < 0) {
@@ -1472,7 +1457,7 @@ static void coroutine_fn sd_write_done(SheepdogAIOCB *acb)
aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id),
data_len, offset, 0, 0, offset);
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
ret = add_aio_request(s, aio_req, &iov, 1, false, AIOCB_WRITE_UDATA);
ret = add_aio_request(s, aio_req, &iov, 1, 0, AIOCB_WRITE_UDATA);
if (ret) {
free_aio_req(s, aio_req);
acb->ret = -EIO;
@@ -1516,7 +1501,7 @@ static int sd_create_branch(BDRVSheepdogState *s)
}
ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies,
SD_INODE_SIZE, 0, s->cache_flags);
SD_INODE_SIZE, 0, s->cache_enabled);
closesocket(fd);
@@ -1526,7 +1511,7 @@ static int sd_create_branch(BDRVSheepdogState *s)
memcpy(&s->inode, buf, sizeof(s->inode));
s->is_snapshot = false;
s->is_snapshot = 0;
ret = 0;
dprintf("%" PRIx32 " was newly created.\n", s->inode.vdi_id);
@@ -1581,7 +1566,7 @@ static int coroutine_fn sd_co_rw_vector(void *p)
while (done != total) {
uint8_t flags = 0;
uint64_t old_oid = 0;
bool create = false;
int create = 0;
oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
@@ -1596,10 +1581,10 @@ static int coroutine_fn sd_co_rw_vector(void *p)
break;
case AIOCB_WRITE_UDATA:
if (!inode->data_vdi_id[idx]) {
create = true;
create = 1;
} else if (!is_data_obj_writable(inode, idx)) {
/* Copy-On-Write */
create = true;
create = 1;
old_oid = oid;
flags = SD_FLAG_CMD_COW;
}
@@ -1672,7 +1657,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
bs->total_sectors = sector_num + nb_sectors;
}
acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors);
acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, NULL, NULL);
acb->aio_done_func = sd_write_done;
acb->aiocb_type = AIOCB_WRITE_UDATA;
@@ -1693,7 +1678,7 @@ static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num,
SheepdogAIOCB *acb;
int ret;
acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors);
acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, NULL, NULL);
acb->aiocb_type = AIOCB_READ_UDATA;
acb->aio_done_func = sd_finish_aiocb;
@@ -1711,31 +1696,39 @@ static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num,
static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs)
{
BDRVSheepdogState *s = bs->opaque;
SheepdogAIOCB *acb;
AIOReq *aio_req;
SheepdogObjReq hdr = { 0 };
SheepdogObjRsp *rsp = (SheepdogObjRsp *)&hdr;
SheepdogInode *inode = &s->inode;
int ret;
unsigned int wlen = 0, rlen = 0;
if (s->cache_flags != SD_FLAG_CMD_CACHE) {
if (!s->cache_enabled) {
return 0;
}
acb = sd_aio_setup(bs, NULL, 0, 0);
acb->aiocb_type = AIOCB_FLUSH_CACHE;
acb->aio_done_func = sd_finish_aiocb;
hdr.opcode = SD_OP_FLUSH_VDI;
hdr.oid = vid_to_vdi_oid(inode->vdi_id);
aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id),
0, 0, 0, 0, 0);
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
ret = add_aio_request(s, aio_req, NULL, 0, false, acb->aiocb_type);
if (ret < 0) {
error_report("add_aio_request is failed");
free_aio_req(s, aio_req);
qemu_aio_release(acb);
ret = do_req(s->flush_fd, (SheepdogReq *)&hdr, NULL, &wlen, &rlen);
if (ret) {
error_report("failed to send a request to the sheep");
return ret;
}
qemu_coroutine_yield();
return acb->ret;
if (rsp->result == SD_RES_INVALID_PARMS) {
dprintf("disable write cache since the server doesn't support it\n");
s->cache_enabled = 0;
closesocket(s->flush_fd);
return 0;
}
if (rsp->result != SD_RES_SUCCESS) {
error_report("%s", sd_strerror(rsp->result));
return -EIO;
}
return 0;
}
static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
@@ -1761,9 +1754,6 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
s->inode.vm_state_size = sn_info->vm_state_size;
s->inode.vm_clock_nsec = sn_info->vm_clock_nsec;
/* It appears that inode.tag does not require a NUL terminator,
* which means this use of strncpy is ok.
*/
strncpy(s->inode.tag, sn_info->name, sizeof(s->inode.tag));
/* we don't need to update entire object */
datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id);
@@ -1776,7 +1766,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
}
ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
s->inode.nr_copies, datalen, 0, false, s->cache_flags);
s->inode.nr_copies, datalen, 0, 0, s->cache_enabled);
if (ret < 0) {
error_report("failed to write snapshot's inode.");
goto cleanup;
@@ -1793,7 +1783,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
inode = (SheepdogInode *)g_malloc(datalen);
ret = read_object(fd, (char *)inode, vid_to_vdi_oid(new_vid),
s->inode.nr_copies, datalen, 0, s->cache_flags);
s->inode.nr_copies, datalen, 0, s->cache_enabled);
if (ret < 0) {
error_report("failed to read new inode info. %s", strerror(errno));
@@ -1823,13 +1813,13 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
memcpy(old_s, s, sizeof(BDRVSheepdogState));
pstrcpy(vdi, sizeof(vdi), s->name);
memset(vdi, 0, sizeof(vdi));
strncpy(vdi, s->name, sizeof(vdi));
memset(tag, 0, sizeof(tag));
snapid = strtoul(snapshot_id, NULL, 10);
if (snapid) {
tag[0] = 0;
} else {
pstrcpy(tag, sizeof(tag), s->name);
if (!snapid) {
strncpy(tag, s->name, sizeof(tag));
}
ret = find_vdi_name(s, vdi, snapid, tag, &vid, 1);
@@ -1847,7 +1837,7 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
buf = g_malloc(SD_INODE_SIZE);
ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies,
SD_INODE_SIZE, 0, s->cache_flags);
SD_INODE_SIZE, 0, s->cache_enabled);
closesocket(fd);
@@ -1863,7 +1853,7 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
goto out;
}
s->is_snapshot = true;
s->is_snapshot = 1;
g_free(buf);
g_free(old_s);
@@ -1944,7 +1934,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
/* we don't need to read entire object */
ret = read_object(fd, (char *)&inode, vid_to_vdi_oid(vid),
0, SD_INODE_SIZE - sizeof(inode.data_vdi_id), 0,
s->cache_flags);
s->cache_enabled);
if (ret) {
continue;
@@ -1958,9 +1948,8 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str), "%u",
inode.snap_id);
pstrcpy(sn_tab[found].name,
MIN(sizeof(sn_tab[found].name), sizeof(inode.tag)),
inode.tag);
strncpy(sn_tab[found].name, inode.tag,
MIN(sizeof(sn_tab[found].name), sizeof(inode.tag)));
found++;
}
}
@@ -1981,8 +1970,8 @@ out:
static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
int64_t pos, int size, int load)
{
bool create;
int fd, ret = 0, remaining = size;
int fd, create;
int ret = 0, remaining = size;
unsigned int data_len;
uint64_t vmstate_oid;
uint32_t vdi_index;
@@ -2005,11 +1994,11 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
if (load) {
ret = read_object(fd, (char *)data, vmstate_oid,
s->inode.nr_copies, data_len, offset,
s->cache_flags);
s->cache_enabled);
} else {
ret = write_object(fd, (char *)data, vmstate_oid,
s->inode.nr_copies, data_len, offset, create,
s->cache_flags);
s->cache_enabled);
}
if (ret < 0) {

View File

@@ -12,8 +12,7 @@
*/
#include "trace.h"
#include "block/block_int.h"
#include "block/blockjob.h"
#include "block_int.h"
#include "qemu/ratelimit.h"
enum {
@@ -31,7 +30,6 @@ typedef struct StreamBlockJob {
BlockJob common;
RateLimit limit;
BlockDriverState *base;
BlockdevOnError on_error;
char backing_file_id[1024];
} StreamBlockJob;
@@ -79,14 +77,13 @@ static void coroutine_fn stream_run(void *opaque)
BlockDriverState *bs = s->common.bs;
BlockDriverState *base = s->base;
int64_t sector_num, end;
int error = 0;
int ret = 0;
int n = 0;
void *buf;
s->common.len = bdrv_getlength(bs);
if (s->common.len < 0) {
block_job_completed(&s->common, s->common.len);
block_job_complete(&s->common, s->common.len);
return;
}
@@ -108,7 +105,7 @@ static void coroutine_fn stream_run(void *opaque)
wait:
/* Note that even when no rate limit is applied we need to yield
* with no pending I/O here so that bdrv_drain_all() returns.
* with no pending I/O here so that qemu_aio_flush() returns.
*/
block_job_sleep_ns(&s->common, rt_clock, delay_ns);
if (block_job_is_cancelled(&s->common)) {
@@ -144,19 +141,7 @@ wait:
ret = stream_populate(bs, sector_num, n, buf);
}
if (ret < 0) {
BlockErrorAction action =
block_job_error_action(&s->common, s->common.bs, s->on_error,
true, -ret);
if (action == BDRV_ACTION_STOP) {
n = 0;
continue;
}
if (error == 0) {
error = ret;
}
if (action == BDRV_ACTION_REPORT) {
break;
}
break;
}
ret = 0;
@@ -168,9 +153,6 @@ wait:
bdrv_disable_copy_on_read(bs);
}
/* Do not remove the backing file if an error was there but ignored. */
ret = error;
if (!block_job_is_cancelled(&s->common) && sector_num == end && ret == 0) {
const char *base_id = NULL, *base_fmt = NULL;
if (base) {
@@ -184,7 +166,7 @@ wait:
}
qemu_vfree(buf);
block_job_completed(&s->common, ret);
block_job_complete(&s->common, ret);
}
static void stream_set_speed(BlockJob *job, int64_t speed, Error **errp)
@@ -206,19 +188,11 @@ static BlockJobType stream_job_type = {
void stream_start(BlockDriverState *bs, BlockDriverState *base,
const char *base_id, int64_t speed,
BlockdevOnError on_error,
BlockDriverCompletionFunc *cb,
void *opaque, Error **errp)
{
StreamBlockJob *s;
if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
on_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
!bdrv_iostatus_is_enabled(bs)) {
error_set(errp, QERR_INVALID_PARAMETER, "on-error");
return;
}
s = block_job_create(&stream_job_type, bs, speed, cb, opaque, errp);
if (!s) {
return;
@@ -229,7 +203,6 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base,
pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id);
}
s->on_error = on_error;
s->common.co = qemu_coroutine_create(stream_run);
trace_stream_start(bs, base, s, s->common.co, opaque);
qemu_coroutine_enter(s->common.co, s);

View File

@@ -50,16 +50,19 @@
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "migration/migration.h"
#include "block_int.h"
#include "module.h"
#include "migration.h"
#if defined(CONFIG_UUID)
#include <uuid/uuid.h>
#else
/* TODO: move uuid emulation to some central place in QEMU. */
#include "sysemu/sysemu.h" /* UUID_FMT */
#include "sysemu.h" /* UUID_FMT */
typedef unsigned char uuid_t[16];
void uuid_generate(uuid_t out);
int uuid_is_null(const uuid_t uu);
void uuid_unparse(const uuid_t uu, char *out);
#endif
/* Code configuration options. */
@@ -121,18 +124,18 @@ typedef unsigned char uuid_t[16];
#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
#if !defined(CONFIG_UUID)
static inline void uuid_generate(uuid_t out)
void uuid_generate(uuid_t out)
{
memset(out, 0, sizeof(uuid_t));
}
static inline int uuid_is_null(const uuid_t uu)
int uuid_is_null(const uuid_t uu)
{
uuid_t null_uuid = { 0 };
return memcmp(uu, null_uuid, sizeof(uuid_t)) == 0;
}
static inline void uuid_unparse(const uuid_t uu, char *out)
void uuid_unparse(const uuid_t uu, char *out)
{
snprintf(out, 37, UUID_FMT,
uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7],
@@ -246,7 +249,7 @@ static void vdi_header_print(VdiHeader *header)
{
char uuid[37];
logout("text %s", header->text);
logout("signature 0x%08x\n", header->signature);
logout("signature 0x%04x\n", header->signature);
logout("header size 0x%04x\n", header->header_size);
logout("image type 0x%04x\n", header->image_type);
logout("image flags 0x%04x\n", header->image_flags);
@@ -369,12 +372,10 @@ static int vdi_open(BlockDriverState *bs, int flags)
BDRVVdiState *s = bs->opaque;
VdiHeader header;
size_t bmap_size;
int ret;
logout("\n");
ret = bdrv_read(bs->file, 0, (uint8_t *)&header, 1);
if (ret < 0) {
if (bdrv_read(bs->file, 0, (uint8_t *)&header, 1) < 0) {
goto fail;
}
@@ -392,45 +393,33 @@ static int vdi_open(BlockDriverState *bs, int flags)
header.disk_size &= ~(SECTOR_SIZE - 1);
}
if (header.signature != VDI_SIGNATURE) {
logout("bad vdi signature %08x\n", header.signature);
ret = -EMEDIUMTYPE;
goto fail;
} else if (header.version != VDI_VERSION_1_1) {
if (header.version != VDI_VERSION_1_1) {
logout("unsupported version %u.%u\n",
header.version >> 16, header.version & 0xffff);
ret = -ENOTSUP;
goto fail;
} else if (header.offset_bmap % SECTOR_SIZE != 0) {
/* We only support block maps which start on a sector boundary. */
logout("unsupported block map offset 0x%x B\n", header.offset_bmap);
ret = -ENOTSUP;
goto fail;
} else if (header.offset_data % SECTOR_SIZE != 0) {
/* We only support data blocks which start on a sector boundary. */
logout("unsupported data offset 0x%x B\n", header.offset_data);
ret = -ENOTSUP;
goto fail;
} else if (header.sector_size != SECTOR_SIZE) {
logout("unsupported sector size %u B\n", header.sector_size);
ret = -ENOTSUP;
goto fail;
} else if (header.block_size != 1 * MiB) {
logout("unsupported block size %u B\n", header.block_size);
ret = -ENOTSUP;
goto fail;
} else if (header.disk_size >
(uint64_t)header.blocks_in_image * header.block_size) {
logout("unsupported disk size %" PRIu64 " B\n", header.disk_size);
ret = -ENOTSUP;
goto fail;
} else if (!uuid_is_null(header.uuid_link)) {
logout("link uuid != 0, unsupported\n");
ret = -ENOTSUP;
goto fail;
} else if (!uuid_is_null(header.uuid_parent)) {
logout("parent uuid != 0, unsupported\n");
ret = -ENOTSUP;
goto fail;
}
@@ -443,9 +432,10 @@ static int vdi_open(BlockDriverState *bs, int flags)
bmap_size = header.blocks_in_image * sizeof(uint32_t);
bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
s->bmap = g_malloc(bmap_size * SECTOR_SIZE);
ret = bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size);
if (ret < 0) {
if (bmap_size > 0) {
s->bmap = g_malloc(bmap_size * SECTOR_SIZE);
}
if (bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
goto fail_free_bmap;
}
@@ -461,13 +451,7 @@ static int vdi_open(BlockDriverState *bs, int flags)
g_free(s->bmap);
fail:
return ret;
}
static int vdi_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
return 0;
return -1;
}
static int coroutine_fn vdi_co_is_allocated(BlockDriverState *bs,
@@ -777,7 +761,6 @@ static BlockDriver bdrv_vdi = {
.bdrv_probe = vdi_probe,
.bdrv_open = vdi_open,
.bdrv_close = vdi_close,
.bdrv_reopen_prepare = vdi_reopen_prepare,
.bdrv_create = vdi_create,
.bdrv_co_is_allocated = vdi_co_is_allocated,
.bdrv_make_empty = vdi_make_empty,

View File

@@ -24,9 +24,9 @@
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "migration/migration.h"
#include "block_int.h"
#include "module.h"
#include "migration.h"
#include <zlib.h>
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
@@ -300,40 +300,6 @@ static int vmdk_is_cid_valid(BlockDriverState *bs)
return 1;
}
/* Queue extents, if any, for reopen() */
static int vmdk_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
BDRVVmdkState *s;
int ret = -1;
int i;
VmdkExtent *e;
assert(state != NULL);
assert(state->bs != NULL);
if (queue == NULL) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"No reopen queue for VMDK extents");
goto exit;
}
s = state->bs->opaque;
assert(s != NULL);
for (i = 0; i < s->num_extents; i++) {
e = &s->extents[i];
if (e->file != state->bs->file) {
bdrv_reopen_queue(queue, e->file, state->flags);
}
}
ret = 0;
exit:
return ret;
}
static int vmdk_parent_open(BlockDriverState *bs)
{
char *p_name;
@@ -616,7 +582,7 @@ static int vmdk_open_sparse(BlockDriverState *bs,
return vmdk_open_vmdk4(bs, file, flags);
break;
default:
return -EMEDIUMTYPE;
return -EINVAL;
break;
}
}
@@ -641,7 +607,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
* RW [size in sectors] SPARSE "file-name.vmdk"
*/
flat_offset = -1;
ret = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64,
ret = sscanf(p, "%10s %" SCNd64 " %10s %511s %" SCNd64,
access, &sectors, type, fname, &flat_offset);
if (ret < 4 || strcmp(access, "RW")) {
goto next_line;
@@ -653,6 +619,14 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
return -EINVAL;
}
/* trim the quotation marks around */
if (fname[0] == '"') {
memmove(fname, fname + 1, strlen(fname));
if (strlen(fname) <= 1 || fname[strlen(fname) - 1] != '"') {
return -EINVAL;
}
fname[strlen(fname) - 1] = '\0';
}
if (sectors <= 0 ||
(strcmp(type, "FLAT") && strcmp(type, "SPARSE")) ||
(strcmp(access, "RW"))) {
@@ -710,7 +684,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
}
buf[2047] = '\0';
if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) {
return -EMEDIUMTYPE;
return -EINVAL;
}
if (strcmp(ct, "monolithicFlat") &&
strcmp(ct, "twoGbMaxExtentSparse") &&
@@ -1084,7 +1058,6 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
BDRVVmdkState *s = bs->opaque;
int ret;
uint64_t n, index_in_cluster;
uint64_t extent_begin_sector, extent_relative_sector_num;
VmdkExtent *extent = NULL;
uint64_t cluster_offset;
@@ -1096,9 +1069,7 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
ret = get_cluster_offset(
bs, extent, NULL,
sector_num << 9, 0, &cluster_offset);
extent_begin_sector = extent->end_sector - extent->sectors;
extent_relative_sector_num = sector_num - extent_begin_sector;
index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;
index_in_cluster = sector_num % extent->cluster_sectors;
n = extent->cluster_sectors - index_in_cluster;
if (n > nb_sectors) {
n = nb_sectors;
@@ -1149,7 +1120,6 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
VmdkExtent *extent = NULL;
int n, ret;
int64_t index_in_cluster;
uint64_t extent_begin_sector, extent_relative_sector_num;
uint64_t cluster_offset;
VmdkMetaData m_data;
@@ -1192,9 +1162,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
if (ret) {
return -EINVAL;
}
extent_begin_sector = extent->end_sector - extent->sectors;
extent_relative_sector_num = sector_num - extent_begin_sector;
index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;
index_in_cluster = sector_num % extent->cluster_sectors;
n = extent->cluster_sectors - index_in_cluster;
if (n > nb_sectors) {
n = nb_sectors;
@@ -1406,7 +1374,8 @@ static int relative_path(char *dest, int dest_size,
return -1;
}
if (path_is_absolute(target)) {
pstrcpy(dest, dest_size, target);
dest[dest_size - 1] = '\0';
strncpy(dest, target, dest_size - 1);
return 0;
}
while (base[i] == target[i]) {
@@ -1434,7 +1403,6 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
int fd, idx = 0;
char desc[BUF_SIZE];
int64_t total_size = 0, filesize;
const char *adapter_type = NULL;
const char *backing_file = NULL;
const char *fmt = NULL;
int flags = 0;
@@ -1446,7 +1414,6 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
const char *desc_extent_line;
char parent_desc_line[BUF_SIZE] = "";
uint32_t parent_cid = 0xffffffff;
uint32_t number_heads = 16;
const char desc_template[] =
"# Disk DescriptorFile\n"
"version=1\n"
@@ -1463,9 +1430,9 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
"\n"
"ddb.virtualHWVersion = \"%d\"\n"
"ddb.geometry.cylinders = \"%" PRId64 "\"\n"
"ddb.geometry.heads = \"%d\"\n"
"ddb.geometry.heads = \"16\"\n"
"ddb.geometry.sectors = \"63\"\n"
"ddb.adapterType = \"%s\"\n";
"ddb.adapterType = \"ide\"\n";
if (filename_decompose(filename, path, prefix, postfix, PATH_MAX)) {
return -EINVAL;
@@ -1474,8 +1441,6 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
total_size = options->value.n;
} else if (!strcmp(options->name, BLOCK_OPT_ADAPTER_TYPE)) {
adapter_type = options->value.s;
} else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
backing_file = options->value.s;
} else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
@@ -1485,20 +1450,6 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
}
options++;
}
if (!adapter_type) {
adapter_type = "ide";
} else if (strcmp(adapter_type, "ide") &&
strcmp(adapter_type, "buslogic") &&
strcmp(adapter_type, "lsilogic") &&
strcmp(adapter_type, "legacyESX")) {
fprintf(stderr, "VMDK: Unknown adapter type: '%s'.\n", adapter_type);
return -EINVAL;
}
if (strcmp(adapter_type, "ide") != 0) {
/* that's the number of heads with which vmware operates when
creating, exporting, etc. vmdk files with a non-ide adapter type */
number_heads = 255;
}
if (!fmt) {
/* Default format to monolithicSparse */
fmt = "monolithicSparse";
@@ -1586,8 +1537,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
parent_desc_line,
ext_desc_lines,
(flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
total_size / (int64_t)(63 * number_heads * 512), number_heads,
adapter_type);
total_size / (int64_t)(63 * 16 * 512));
if (split || flat) {
fd = qemu_open(filename,
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
@@ -1671,12 +1621,6 @@ static QEMUOptionParameter vmdk_create_options[] = {
.type = OPT_SIZE,
.help = "Virtual disk size"
},
{
.name = BLOCK_OPT_ADAPTER_TYPE,
.type = OPT_STRING,
.help = "Virtual adapter type, can be one of "
"ide (default), lsilogic, buslogic or legacyESX"
},
{
.name = BLOCK_OPT_BACKING_FILE,
.type = OPT_STRING,
@@ -1702,7 +1646,6 @@ static BlockDriver bdrv_vmdk = {
.instance_size = sizeof(BDRVVmdkState),
.bdrv_probe = vmdk_probe,
.bdrv_open = vmdk_open,
.bdrv_reopen_prepare = vmdk_reopen_prepare,
.bdrv_read = vmdk_co_read,
.bdrv_write = vmdk_co_write,
.bdrv_close = vmdk_close,

View File

@@ -23,12 +23,9 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "migration/migration.h"
#if defined(CONFIG_UUID)
#include <uuid/uuid.h>
#endif
#include "block_int.h"
#include "module.h"
#include "migration.h"
/**************************************************************/
@@ -163,33 +160,24 @@ static int vpc_open(BlockDriverState *bs, int flags)
struct vhd_dyndisk_header* dyndisk_header;
uint8_t buf[HEADER_SIZE];
uint32_t checksum;
int err = -1;
int disk_type = VHD_DYNAMIC;
int ret;
ret = bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE);
if (ret < 0) {
if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
goto fail;
}
footer = (struct vhd_footer*) s->footer_buf;
if (strncmp(footer->creator, "conectix", 8)) {
int64_t offset = bdrv_getlength(bs->file);
if (offset < 0) {
ret = offset;
goto fail;
} else if (offset < HEADER_SIZE) {
ret = -EINVAL;
if (offset < HEADER_SIZE) {
goto fail;
}
/* If a fixed disk, the footer is found only at the end of the file */
ret = bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf,
HEADER_SIZE);
if (ret < 0) {
if (bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf, HEADER_SIZE)
!= HEADER_SIZE) {
goto fail;
}
if (strncmp(footer->creator, "conectix", 8)) {
ret = -EMEDIUMTYPE;
goto fail;
}
disk_type = VHD_FIXED;
@@ -210,23 +198,20 @@ static int vpc_open(BlockDriverState *bs, int flags)
bs->total_sectors = (int64_t)
be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
/* Allow a maximum disk size of approximately 2 TB */
if (bs->total_sectors >= 65535LL * 255 * 255) {
ret = -EFBIG;
if (bs->total_sectors >= 65535 * 16 * 255) {
err = -EFBIG;
goto fail;
}
if (disk_type == VHD_DYNAMIC) {
ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
HEADER_SIZE);
if (ret < 0) {
if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
HEADER_SIZE) != HEADER_SIZE) {
goto fail;
}
dyndisk_header = (struct vhd_dyndisk_header *) buf;
if (strncmp(dyndisk_header->magic, "cxsparse", 8)) {
ret = -EINVAL;
goto fail;
}
@@ -237,10 +222,8 @@ static int vpc_open(BlockDriverState *bs, int flags)
s->pagetable = g_malloc(s->max_table_entries * 4);
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable,
s->max_table_entries * 4);
if (ret < 0) {
if (bdrv_pread(bs->file, s->bat_offset, s->pagetable,
s->max_table_entries * 4) != s->max_table_entries * 4) {
goto fail;
}
@@ -278,19 +261,8 @@ static int vpc_open(BlockDriverState *bs, int flags)
migrate_add_blocker(s->migration_blocker);
return 0;
fail:
g_free(s->pagetable);
#ifdef CACHE
g_free(s->pageentry_u8);
#endif
return ret;
}
static int vpc_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
return 0;
fail:
return err;
}
/*
@@ -546,27 +518,19 @@ static coroutine_fn int vpc_co_write(BlockDriverState *bs, int64_t sector_num,
* Note that the geometry doesn't always exactly match total_sectors but
* may round it down.
*
* Returns 0 on success, -EFBIG if the size is larger than ~2 TB. Override
* the hardware EIDE and ATA-2 limit of 16 heads (max disk size of 127 GB)
* and instead allow up to 255 heads.
* Returns 0 on success, -EFBIG if the size is larger than 127 GB
*/
static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
uint8_t* heads, uint8_t* secs_per_cyl)
{
uint32_t cyls_times_heads;
/* Allow a maximum disk size of approximately 2 TB */
if (total_sectors > 65535LL * 255 * 255) {
if (total_sectors > 65535 * 16 * 255)
return -EFBIG;
}
if (total_sectors > 65535 * 16 * 63) {
*secs_per_cyl = 255;
if (total_sectors > 65535 * 16 * 255) {
*heads = 255;
} else {
*heads = 16;
}
*heads = 16;
cyls_times_heads = total_sectors / *secs_per_cyl;
} else {
*secs_per_cyl = 17;
@@ -769,9 +733,7 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
footer->type = be32_to_cpu(disk_type);
#if defined(CONFIG_UUID)
uuid_generate(footer->uuid);
#endif
/* TODO uuid is missing */
footer->checksum = be32_to_cpu(vpc_checksum(buf, HEADER_SIZE));
@@ -821,7 +783,6 @@ static BlockDriver bdrv_vpc = {
.bdrv_probe = vpc_probe,
.bdrv_open = vpc_open,
.bdrv_close = vpc_close,
.bdrv_reopen_prepare = vpc_reopen_prepare,
.bdrv_create = vpc_create,
.bdrv_read = vpc_co_read,

View File

@@ -25,9 +25,9 @@
#include <sys/stat.h>
#include <dirent.h>
#include "qemu-common.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "migration/migration.h"
#include "block_int.h"
#include "module.h"
#include "migration.h"
#ifndef S_IWGRP
#define S_IWGRP 0
@@ -529,9 +529,13 @@ static inline uint8_t fat_chksum(const direntry_t* entry)
/* if return_time==0, this returns the fat_date, else the fat_time */
static uint16_t fat_datetime(time_t time,int return_time) {
struct tm* t;
#ifdef _WIN32
t=localtime(&time); /* this is not thread safe */
#else
struct tm t1;
t = &t1;
localtime_r(&time,t);
#endif
if(return_time)
return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));

View File

@@ -1,215 +0,0 @@
/*
* Block driver for RAW files (win32)
*
* Copyright (c) 2006 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 "qemu-common.h"
#include "qemu/timer.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "qemu-common.h"
#include "block/aio.h"
#include "raw-aio.h"
#include "qemu/event_notifier.h"
#include "qemu/iov.h"
#include <windows.h>
#include <winioctl.h>
#define FTYPE_FILE 0
#define FTYPE_CD 1
#define FTYPE_HARDDISK 2
struct QEMUWin32AIOState {
HANDLE hIOCP;
EventNotifier e;
int count;
};
typedef struct QEMUWin32AIOCB {
BlockDriverAIOCB common;
struct QEMUWin32AIOState *ctx;
int nbytes;
OVERLAPPED ov;
QEMUIOVector *qiov;
void *buf;
bool is_read;
bool is_linear;
} QEMUWin32AIOCB;
/*
* Completes an AIO request (calls the callback and frees the ACB).
*/
static void win32_aio_process_completion(QEMUWin32AIOState *s,
QEMUWin32AIOCB *waiocb, DWORD count)
{
int ret;
s->count--;
if (waiocb->ov.Internal != 0) {
ret = -EIO;
} else {
ret = 0;
if (count < waiocb->nbytes) {
/* Short reads mean EOF, pad with zeros. */
if (waiocb->is_read) {
qemu_iovec_memset(waiocb->qiov, count, 0,
waiocb->qiov->size - count);
} else {
ret = -EINVAL;
}
}
}
if (!waiocb->is_linear) {
if (ret == 0 && waiocb->is_read) {
QEMUIOVector *qiov = waiocb->qiov;
iov_from_buf(qiov->iov, qiov->niov, 0, waiocb->buf, qiov->size);
}
qemu_vfree(waiocb->buf);
}
waiocb->common.cb(waiocb->common.opaque, ret);
qemu_aio_release(waiocb);
}
static void win32_aio_completion_cb(EventNotifier *e)
{
QEMUWin32AIOState *s = container_of(e, QEMUWin32AIOState, e);
DWORD count;
ULONG_PTR key;
OVERLAPPED *ov;
event_notifier_test_and_clear(&s->e);
while (GetQueuedCompletionStatus(s->hIOCP, &count, &key, &ov, 0)) {
QEMUWin32AIOCB *waiocb = container_of(ov, QEMUWin32AIOCB, ov);
win32_aio_process_completion(s, waiocb, count);
}
}
static int win32_aio_flush_cb(EventNotifier *e)
{
QEMUWin32AIOState *s = container_of(e, QEMUWin32AIOState, e);
return (s->count > 0) ? 1 : 0;
}
static void win32_aio_cancel(BlockDriverAIOCB *blockacb)
{
QEMUWin32AIOCB *waiocb = (QEMUWin32AIOCB *)blockacb;
/*
* CancelIoEx is only supported in Vista and newer. For now, just
* wait for completion.
*/
while (!HasOverlappedIoCompleted(&waiocb->ov)) {
qemu_aio_wait();
}
}
static const AIOCBInfo win32_aiocb_info = {
.aiocb_size = sizeof(QEMUWin32AIOCB),
.cancel = win32_aio_cancel,
};
BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
QEMUWin32AIOState *aio, HANDLE hfile,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type)
{
struct QEMUWin32AIOCB *waiocb;
uint64_t offset = sector_num * 512;
DWORD rc;
waiocb = qemu_aio_get(&win32_aiocb_info, bs, cb, opaque);
waiocb->nbytes = nb_sectors * 512;
waiocb->qiov = qiov;
waiocb->is_read = (type == QEMU_AIO_READ);
if (qiov->niov > 1) {
waiocb->buf = qemu_blockalign(bs, qiov->size);
if (type & QEMU_AIO_WRITE) {
iov_to_buf(qiov->iov, qiov->niov, 0, waiocb->buf, qiov->size);
}
waiocb->is_linear = false;
} else {
waiocb->buf = qiov->iov[0].iov_base;
waiocb->is_linear = true;
}
memset(&waiocb->ov, 0, sizeof(waiocb->ov));
waiocb->ov.Offset = (DWORD)offset;
waiocb->ov.OffsetHigh = (DWORD)(offset >> 32);
waiocb->ov.hEvent = event_notifier_get_handle(&aio->e);
aio->count++;
if (type & QEMU_AIO_READ) {
rc = ReadFile(hfile, waiocb->buf, waiocb->nbytes, NULL, &waiocb->ov);
} else {
rc = WriteFile(hfile, waiocb->buf, waiocb->nbytes, NULL, &waiocb->ov);
}
if(rc == 0 && GetLastError() != ERROR_IO_PENDING) {
goto out_dec_count;
}
return &waiocb->common;
out_dec_count:
aio->count--;
qemu_aio_release(waiocb);
return NULL;
}
int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile)
{
if (CreateIoCompletionPort(hfile, aio->hIOCP, (ULONG_PTR) 0, 0) == NULL) {
return -EINVAL;
} else {
return 0;
}
}
QEMUWin32AIOState *win32_aio_init(void)
{
QEMUWin32AIOState *s;
s = g_malloc0(sizeof(*s));
if (event_notifier_init(&s->e, false) < 0) {
goto out_free_state;
}
s->hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (s->hIOCP == NULL) {
goto out_close_efd;
}
qemu_aio_set_event_notifier(&s->e, win32_aio_completion_cb,
win32_aio_flush_cb);
return s;
out_close_efd:
event_notifier_cleanup(&s->e);
out_free_state:
g_free(s);
return NULL;
}

View File

@@ -24,15 +24,13 @@
#ifndef BLOCK_INT_H
#define BLOCK_INT_H
#include "block/block.h"
#include "qemu/option.h"
#include "qemu/queue.h"
#include "block/coroutine.h"
#include "qemu/timer.h"
#include "block.h"
#include "qemu-option.h"
#include "qemu-queue.h"
#include "qemu-coroutine.h"
#include "qemu-timer.h"
#include "qapi-types.h"
#include "qapi/qmp/qerror.h"
#include "monitor/monitor.h"
#include "qemu/hbitmap.h"
#include "qerror.h"
#define BLOCK_FLAG_ENCRYPT 1
#define BLOCK_FLAG_COMPAT6 4
@@ -56,7 +54,6 @@
#define BLOCK_OPT_SUBFMT "subformat"
#define BLOCK_OPT_COMPAT_LEVEL "compat"
#define BLOCK_OPT_LAZY_REFCOUNTS "lazy_refcounts"
#define BLOCK_OPT_ADAPTER_TYPE "adapter_type"
typedef struct BdrvTrackedRequest BdrvTrackedRequest;
@@ -70,18 +67,78 @@ typedef struct BlockIOBaseValue {
uint64_t ios[2];
} BlockIOBaseValue;
typedef struct BlockJob BlockJob;
/**
* BlockJobType:
*
* A class type for block job objects.
*/
typedef struct BlockJobType {
/** Derived BlockJob struct size */
size_t instance_size;
/** String describing the operation, part of query-block-jobs QMP API */
const char *job_type;
/** Optional callback for job types that support setting a speed limit */
void (*set_speed)(BlockJob *job, int64_t speed, Error **errp);
} BlockJobType;
/**
* BlockJob:
*
* Long-running operation on a BlockDriverState.
*/
struct BlockJob {
/** The job type, including the job vtable. */
const BlockJobType *job_type;
/** The block device on which the job is operating. */
BlockDriverState *bs;
/**
* The coroutine that executes the job. If not NULL, it is
* reentered when busy is false and the job is cancelled.
*/
Coroutine *co;
/**
* Set to true if the job should cancel itself. The flag must
* always be tested just before toggling the busy flag from false
* to true. After a job has been cancelled, it should only yield
* if #qemu_aio_wait will ("sooner or later") reenter the coroutine.
*/
bool cancelled;
/**
* Set to false by the job while it is in a quiescent state, where
* no I/O is pending and the job has yielded on any condition
* that is not detected by #qemu_aio_wait, such as a timer.
*/
bool busy;
/** Offset that is published by the query-block-jobs QMP API */
int64_t offset;
/** Length that is published by the query-block-jobs QMP API */
int64_t len;
/** Speed that was set with @block_job_set_speed. */
int64_t speed;
/** The completion function that will be called when the job completes. */
BlockDriverCompletionFunc *cb;
/** The opaque value that is passed to the completion function. */
void *opaque;
};
struct BlockDriver {
const char *format_name;
int instance_size;
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
int (*bdrv_probe_device)(const char *filename);
/* For handling image reopen for split or non-split files */
int (*bdrv_reopen_prepare)(BDRVReopenState *reopen_state,
BlockReopenQueue *queue, Error **errp);
void (*bdrv_reopen_commit)(BDRVReopenState *reopen_state);
void (*bdrv_reopen_abort)(BDRVReopenState *reopen_state);
int (*bdrv_open)(BlockDriverState *bs, int flags);
int (*bdrv_file_open)(BlockDriverState *bs, const char *filename, int flags);
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
@@ -192,12 +249,6 @@ struct BlockDriver {
void (*bdrv_debug_event)(BlockDriverState *bs, BlkDebugEvent event);
/* TODO Better pass a option string/QDict/QemuOpts to add any rule? */
int (*bdrv_debug_breakpoint)(BlockDriverState *bs, const char *event,
const char *tag);
int (*bdrv_debug_resume)(BlockDriverState *bs, const char *tag);
bool (*bdrv_debug_is_suspended)(BlockDriverState *bs, const char *tag);
/*
* Returns 1 if newly created images are guaranteed to contain only
* zeros, 0 otherwise.
@@ -217,6 +268,7 @@ struct BlockDriverState {
int64_t total_sectors; /* if we are reading a disk image, give its
size in sectors */
int read_only; /* if true, the media is read only */
int keep_read_only; /* if true, the media was requested to stay read only */
int open_flags; /* flags used to open the file, re-used for re-open */
int encrypted; /* if true, the media is encrypted */
int valid_key; /* if true, a valid encryption key has been set */
@@ -241,8 +293,6 @@ struct BlockDriverState {
BlockDriverState *backing_hd;
BlockDriverState *file;
NotifierList close_notifiers;
/* number of in-flight copy-on-read requests */
unsigned int copy_on_read_in_flight;
@@ -273,11 +323,12 @@ struct BlockDriverState {
/* NOTE: the following infos are only hints for real hardware
drivers. They are not used by the block driver */
BlockdevOnError on_read_error, on_write_error;
BlockErrorAction on_read_error, on_write_error;
bool iostatus_enabled;
BlockDeviceIoStatus iostatus;
char device_name[32];
HBitmap *dirty_bitmap;
unsigned long *dirty_bitmap;
int64_t dirty_count;
int in_use; /* users other than guest access, eg. block migration */
QTAILQ_ENTRY(BlockDriverState) list;
@@ -285,7 +336,6 @@ struct BlockDriverState {
/* long-running background operation */
BlockJob *job;
};
int get_tmp_filename(char *filename, int size);
@@ -296,9 +346,92 @@ void bdrv_set_io_limits(BlockDriverState *bs,
#ifdef _WIN32
int is_windows_drive(const char *filename);
#endif
void bdrv_emit_qmp_error_event(const BlockDriverState *bdrv,
enum MonitorEvent ev,
BlockErrorAction action, bool is_read);
/**
* block_job_create:
* @job_type: The class object for the newly-created job.
* @bs: The block
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
* @cb: Completion function for the job.
* @opaque: Opaque pointer value passed to @cb.
* @errp: Error object.
*
* Create a new long-running block device job and return it. The job
* will call @cb asynchronously when the job completes. Note that
* @bs may have been closed at the time the @cb it is called. If
* this is the case, the job may be reported as either cancelled or
* completed.
*
* This function is not part of the public job interface; it should be
* called from a wrapper that is specific to the job type.
*/
void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs,
int64_t speed, BlockDriverCompletionFunc *cb,
void *opaque, Error **errp);
/**
* block_job_sleep_ns:
* @job: The job that calls the function.
* @clock: The clock to sleep on.
* @ns: How many nanoseconds to stop for.
*
* Put the job to sleep (assuming that it wasn't canceled) for @ns
* nanoseconds. Canceling the job will interrupt the wait immediately.
*/
void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns);
/**
* block_job_complete:
* @job: The job being completed.
* @ret: The status code.
*
* Call the completion function that was registered at creation time, and
* free @job.
*/
void block_job_complete(BlockJob *job, int ret);
/**
* block_job_set_speed:
* @job: The job to set the speed for.
* @speed: The new value
* @errp: Error object.
*
* Set a rate-limiting parameter for the job; the actual meaning may
* vary depending on the job type.
*/
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp);
/**
* block_job_cancel:
* @job: The job to be canceled.
*
* Asynchronously cancel the specified job.
*/
void block_job_cancel(BlockJob *job);
/**
* block_job_is_cancelled:
* @job: The job being queried.
*
* Returns whether the job is scheduled for cancellation.
*/
bool block_job_is_cancelled(BlockJob *job);
/**
* block_job_cancel:
* @job: The job to be canceled.
*
* Asynchronously cancel the job and wait for it to reach a quiescent
* state. Note that the completion callback will still be called
* asynchronously, hence it is *not* valid to call #bdrv_delete
* immediately after #block_job_cancel_sync. Users of block jobs
* will usually protect the BlockDriverState objects with a reference
* count, should this be a concern.
*
* Returns the return value from the job if the job actually completed
* during the call, or -ECANCELED if it was canceled.
*/
int block_job_cancel_sync(BlockJob *job);
/**
* stream_start:
@@ -308,7 +441,6 @@ void bdrv_emit_qmp_error_event(const BlockDriverState *bdrv,
* @base_id: The file name that will be written to @bs as the new
* backing file if the job completes. Ignored if @base is %NULL.
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
* @on_error: The action to take upon error.
* @cb: Completion function for the job.
* @opaque: Opaque pointer value passed to @cb.
* @errp: Error object.
@@ -320,49 +452,7 @@ void bdrv_emit_qmp_error_event(const BlockDriverState *bdrv,
* @base_id in the written image and to @base in the live BlockDriverState.
*/
void stream_start(BlockDriverState *bs, BlockDriverState *base,
const char *base_id, int64_t speed, BlockdevOnError on_error,
BlockDriverCompletionFunc *cb,
void *opaque, Error **errp);
/**
* commit_start:
* @bs: Top Block device
* @base: Block device that will be written into, and become the new top
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
* @on_error: The action to take upon error.
* @cb: Completion function for the job.
* @opaque: Opaque pointer value passed to @cb.
* @errp: Error object.
*
*/
void commit_start(BlockDriverState *bs, BlockDriverState *base,
BlockDriverState *top, int64_t speed,
BlockdevOnError on_error, BlockDriverCompletionFunc *cb,
void *opaque, Error **errp);
/*
* mirror_start:
* @bs: Block device to operate on.
* @target: Block device to write to.
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
* @granularity: The chosen granularity for the dirty bitmap.
* @buf_size: The amount of data that can be in flight at one time.
* @mode: Whether to collapse all images in the chain to the target.
* @on_source_error: The action to take upon error reading from the source.
* @on_target_error: The action to take upon error writing to the target.
* @cb: Completion function for the job.
* @opaque: Opaque pointer value passed to @cb.
* @errp: Error object.
*
* Start a mirroring operation on @bs. Clusters that are allocated
* in @bs will be written to @bs until the job is cancelled or
* manually completed. At the end of a successful mirroring job,
* @bs will be switched to read from @target.
*/
void mirror_start(BlockDriverState *bs, BlockDriverState *target,
int64_t speed, int64_t granularity, int64_t buf_size,
MirrorSyncMode mode, BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
const char *base_id, int64_t speed,
BlockDriverCompletionFunc *cb,
void *opaque, Error **errp);

View File

@@ -1,133 +0,0 @@
/*
* Serving QEMU block devices via NBD
*
* Copyright (c) 2012 Red Hat, Inc.
*
* Author: Paolo Bonzini <pbonzini@redhat.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.
*/
#include "sysemu/blockdev.h"
#include "hw/block-common.h"
#include "monitor/monitor.h"
#include "qapi/qmp/qerror.h"
#include "sysemu/sysemu.h"
#include "qmp-commands.h"
#include "trace.h"
#include "block/nbd.h"
#include "qemu/sockets.h"
static int server_fd = -1;
static void nbd_accept(void *opaque)
{
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
if (fd >= 0) {
nbd_client_new(NULL, fd, nbd_client_put);
}
}
void qmp_nbd_server_start(SocketAddress *addr, Error **errp)
{
if (server_fd != -1) {
error_setg(errp, "NBD server already running");
return;
}
server_fd = socket_listen(addr, errp);
if (server_fd != -1) {
qemu_set_fd_handler2(server_fd, NULL, nbd_accept, NULL, NULL);
}
}
/* Hook into the BlockDriverState notifiers to close the export when
* the file is closed.
*/
typedef struct NBDCloseNotifier {
Notifier n;
NBDExport *exp;
QTAILQ_ENTRY(NBDCloseNotifier) next;
} NBDCloseNotifier;
static QTAILQ_HEAD(, NBDCloseNotifier) close_notifiers =
QTAILQ_HEAD_INITIALIZER(close_notifiers);
static void nbd_close_notifier(Notifier *n, void *data)
{
NBDCloseNotifier *cn = DO_UPCAST(NBDCloseNotifier, n, n);
notifier_remove(&cn->n);
QTAILQ_REMOVE(&close_notifiers, cn, next);
nbd_export_close(cn->exp);
nbd_export_put(cn->exp);
g_free(cn);
}
static void nbd_server_put_ref(NBDExport *exp)
{
BlockDriverState *bs = nbd_export_get_blockdev(exp);
drive_put_ref(drive_get_by_blockdev(bs));
}
void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
Error **errp)
{
BlockDriverState *bs;
NBDExport *exp;
NBDCloseNotifier *n;
if (server_fd == -1) {
error_setg(errp, "NBD server not running");
return;
}
if (nbd_export_find(device)) {
error_setg(errp, "NBD server already exporting device '%s'", device);
return;
}
bs = bdrv_find(device);
if (!bs) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return;
}
if (!has_writable) {
writable = false;
}
if (bdrv_is_read_only(bs)) {
writable = false;
}
exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY,
nbd_server_put_ref);
nbd_export_set_name(exp, device);
drive_get_ref(drive_get_by_blockdev(bs));
n = g_malloc0(sizeof(NBDCloseNotifier));
n->n.notify = nbd_close_notifier;
n->exp = exp;
bdrv_add_close_notifier(bs, &n->n);
QTAILQ_INSERT_TAIL(&close_notifiers, n, next);
}
void qmp_nbd_server_stop(Error **errp)
{
while (!QTAILQ_EMPTY(&close_notifiers)) {
NBDCloseNotifier *cn = QTAILQ_FIRST(&close_notifiers);
nbd_close_notifier(&cn->n, nbd_export_get_blockdev(cn->exp));
}
if (server_fd != -1) {
qemu_set_fd_handler2(server_fd, NULL, NULL, NULL, NULL);
close(server_fd);
server_fd = -1;
}
}

View File

@@ -7,19 +7,18 @@
* later. See the COPYING file in the top-level directory.
*/
#include "sysemu/blockdev.h"
#include "blockdev.h"
#include "hw/block-common.h"
#include "block/blockjob.h"
#include "monitor/monitor.h"
#include "qapi/qmp/qerror.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "qapi/qmp/types.h"
#include "sysemu/sysemu.h"
#include "block/block_int.h"
#include "monitor.h"
#include "qerror.h"
#include "qemu-option.h"
#include "qemu-config.h"
#include "qemu-objects.h"
#include "sysemu.h"
#include "block_int.h"
#include "qmp-commands.h"
#include "trace.h"
#include "sysemu/arch_init.h"
#include "arch_init.h"
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
@@ -238,16 +237,16 @@ static void drive_put_ref_bh_schedule(DriveInfo *dinfo)
qemu_bh_schedule(s->bh);
}
static int parse_block_error_action(const char *buf, bool is_read)
static int parse_block_error_action(const char *buf, int is_read)
{
if (!strcmp(buf, "ignore")) {
return BLOCKDEV_ON_ERROR_IGNORE;
return BLOCK_ERR_IGNORE;
} else if (!is_read && !strcmp(buf, "enospc")) {
return BLOCKDEV_ON_ERROR_ENOSPC;
return BLOCK_ERR_STOP_ENOSPC;
} else if (!strcmp(buf, "stop")) {
return BLOCKDEV_ON_ERROR_STOP;
return BLOCK_ERR_STOP_ANY;
} else if (!strcmp(buf, "report")) {
return BLOCKDEV_ON_ERROR_REPORT;
return BLOCK_ERR_REPORT;
} else {
error_report("'%s' invalid %s error action",
buf, is_read ? "read" : "write");
@@ -275,7 +274,7 @@ static bool do_check_io_limits(BlockIOLimit *io_limits)
return true;
}
DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
{
const char *buf;
const char *file = NULL;
@@ -325,7 +324,7 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
return NULL;
}
} else {
type = block_default_type;
type = default_to_scsi ? IF_SCSI : IF_IDE;
}
max_devs = if_max_devs[type];
@@ -433,13 +432,7 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
return NULL;
}
if (qemu_opt_get(opts, "boot") != NULL) {
fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
"ignored. Future versions will reject this parameter. Please "
"update your scripts.\n");
}
on_write_error = BLOCKDEV_ON_ERROR_ENOSPC;
on_write_error = BLOCK_ERR_STOP_ENOSPC;
if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
error_report("werror is not supported by this bus type");
@@ -452,7 +445,7 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
}
}
on_read_error = BLOCKDEV_ON_ERROR_REPORT;
on_read_error = BLOCK_ERR_REPORT;
if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) {
error_report("rerror is not supported by this bus type");
@@ -568,7 +561,7 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
break;
case IF_VIRTIO:
/* add virtio block device */
opts = qemu_opts_create_nofail(qemu_find_opts("device"));
opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0, NULL);
if (arch_type == QEMU_ARCH_S390X) {
qemu_opt_set(opts, "driver", "virtio-blk-s390");
} else {
@@ -617,13 +610,8 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
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, drv->format_name);
} else {
error_report("could not open disk image %s: %s",
file, strerror(-ret));
}
error_report("could not open disk image %s: %s",
file, strerror(-ret));
goto err;
}
@@ -647,17 +635,21 @@ void do_commit(Monitor *mon, const QDict *qdict)
if (!strcmp(device, "all")) {
ret = bdrv_commit_all();
if (ret == -EBUSY) {
qerror_report(QERR_DEVICE_IN_USE, device);
return;
}
} else {
bs = bdrv_find(device);
if (!bs) {
monitor_printf(mon, "Device '%s' not found\n", device);
qerror_report(QERR_DEVICE_NOT_FOUND, device);
return;
}
ret = bdrv_commit(bs);
}
if (ret < 0) {
monitor_printf(mon, "'commit' error for '%s': %s\n", device,
strerror(-ret));
if (ret == -EBUSY) {
qerror_report(QERR_DEVICE_IN_USE, device);
return;
}
}
}
@@ -708,7 +700,6 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp)
int ret = 0;
BlockdevActionList *dev_entry = dev_list;
BlkTransactionStates *states, *next;
Error *local_err = NULL;
QSIMPLEQ_HEAD(snap_bdrv_states, BlkTransactionStates) snap_bdrv_states;
QSIMPLEQ_INIT(&snap_bdrv_states);
@@ -788,12 +779,12 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp)
/* create new image w/backing file */
if (mode != NEW_IMAGE_MODE_EXISTING) {
bdrv_img_create(new_image_file, format,
states->old_bs->filename,
states->old_bs->drv->format_name,
NULL, -1, flags, &local_err);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
ret = bdrv_img_create(new_image_file, format,
states->old_bs->filename,
states->old_bs->drv->format_name,
NULL, -1, flags);
if (ret) {
error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file);
goto delete_and_fail;
}
}
@@ -814,11 +805,6 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp)
QSIMPLEQ_FOREACH(states, &snap_bdrv_states, entry) {
/* This removes our old bs from the bdrv_states, and adds the new bs */
bdrv_append(states->new_bs, states->old_bs);
/* We don't need (or want) to use the transactional
* bdrv_reopen_multiple() across all the entries at once, because we
* don't want to abort all of them if one of them fails the reopen */
bdrv_reopen(states->new_bs, states->new_bs->open_flags & ~BDRV_O_RDWR,
NULL);
}
/* success */
@@ -838,6 +824,7 @@ exit:
QSIMPLEQ_FOREACH_SAFE(states, &snap_bdrv_states, entry, next) {
g_free(states);
}
return;
}
@@ -1043,9 +1030,6 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
return;
}
/* complete all in-flight operations before resizing the device */
bdrv_drain_all();
switch (bdrv_truncate(bs, size)) {
case 0:
break;
@@ -1067,12 +1051,26 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
}
}
static void block_job_cb(void *opaque, int ret)
static QObject *qobject_from_block_job(BlockJob *job)
{
return qobject_from_jsonf("{ 'type': %s,"
"'device': %s,"
"'len': %" PRId64 ","
"'offset': %" PRId64 ","
"'speed': %" PRId64 " }",
job->job_type->job_type,
bdrv_get_device_name(job->bs),
job->len,
job->offset,
job->speed);
}
static void block_stream_cb(void *opaque, int ret)
{
BlockDriverState *bs = opaque;
QObject *obj;
trace_block_job_cb(bs, bs->job, ret);
trace_block_stream_cb(bs, bs->job, ret);
assert(bs->job);
obj = qobject_from_block_job(bs->job);
@@ -1092,18 +1090,13 @@ static void block_job_cb(void *opaque, int ret)
}
void qmp_block_stream(const char *device, bool has_base,
const char *base, bool has_speed, int64_t speed,
bool has_on_error, BlockdevOnError on_error,
Error **errp)
const char *base, bool has_speed,
int64_t speed, Error **errp)
{
BlockDriverState *bs;
BlockDriverState *base_bs = NULL;
Error *local_err = NULL;
if (!has_on_error) {
on_error = BLOCKDEV_ON_ERROR_REPORT;
}
bs = bdrv_find(device);
if (!bs) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
@@ -1119,7 +1112,7 @@ void qmp_block_stream(const char *device, bool has_base,
}
stream_start(bs, base_bs, base, has_speed ? speed : 0,
on_error, block_job_cb, bs, &local_err);
block_stream_cb, bs, &local_err);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
return;
@@ -1133,210 +1126,6 @@ void qmp_block_stream(const char *device, bool has_base,
trace_qmp_block_stream(bs, bs->job);
}
void qmp_block_commit(const char *device,
bool has_base, const char *base, const char *top,
bool has_speed, int64_t speed,
Error **errp)
{
BlockDriverState *bs;
BlockDriverState *base_bs, *top_bs;
Error *local_err = NULL;
/* This will be part of the QMP command, if/when the
* BlockdevOnError change for blkmirror makes it in
*/
BlockdevOnError on_error = BLOCKDEV_ON_ERROR_REPORT;
/* drain all i/o before commits */
bdrv_drain_all();
bs = bdrv_find(device);
if (!bs) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return;
}
/* default top_bs is the active layer */
top_bs = bs;
if (top) {
if (strcmp(bs->filename, top) != 0) {
top_bs = bdrv_find_backing_image(bs, top);
}
}
if (top_bs == NULL) {
error_setg(errp, "Top image file %s not found", top ? top : "NULL");
return;
}
if (has_base && base) {
base_bs = bdrv_find_backing_image(top_bs, base);
} else {
base_bs = bdrv_find_base(top_bs);
}
if (base_bs == NULL) {
error_set(errp, QERR_BASE_NOT_FOUND, base ? base : "NULL");
return;
}
commit_start(bs, base_bs, top_bs, speed, on_error, block_job_cb, bs,
&local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
/* Grab a reference so hotplug does not delete the BlockDriverState from
* underneath us.
*/
drive_get_ref(drive_get_by_blockdev(bs));
}
#define DEFAULT_MIRROR_BUF_SIZE (10 << 20)
void qmp_drive_mirror(const char *device, const char *target,
bool has_format, const char *format,
enum MirrorSyncMode sync,
bool has_mode, enum NewImageMode mode,
bool has_speed, int64_t speed,
bool has_granularity, uint32_t granularity,
bool has_buf_size, int64_t buf_size,
bool has_on_source_error, BlockdevOnError on_source_error,
bool has_on_target_error, BlockdevOnError on_target_error,
Error **errp)
{
BlockDriverState *bs;
BlockDriverState *source, *target_bs;
BlockDriver *proto_drv;
BlockDriver *drv = NULL;
Error *local_err = NULL;
int flags;
uint64_t size;
int ret;
if (!has_speed) {
speed = 0;
}
if (!has_on_source_error) {
on_source_error = BLOCKDEV_ON_ERROR_REPORT;
}
if (!has_on_target_error) {
on_target_error = BLOCKDEV_ON_ERROR_REPORT;
}
if (!has_mode) {
mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
}
if (!has_granularity) {
granularity = 0;
}
if (!has_buf_size) {
buf_size = DEFAULT_MIRROR_BUF_SIZE;
}
if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) {
error_set(errp, QERR_INVALID_PARAMETER, device);
return;
}
if (granularity & (granularity - 1)) {
error_set(errp, QERR_INVALID_PARAMETER, device);
return;
}
bs = bdrv_find(device);
if (!bs) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return;
}
if (!bdrv_is_inserted(bs)) {
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
return;
}
if (!has_format) {
format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;
}
if (format) {
drv = bdrv_find_format(format);
if (!drv) {
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
return;
}
}
if (bdrv_in_use(bs)) {
error_set(errp, QERR_DEVICE_IN_USE, device);
return;
}
flags = bs->open_flags | BDRV_O_RDWR;
source = bs->backing_hd;
if (!source && sync == MIRROR_SYNC_MODE_TOP) {
sync = MIRROR_SYNC_MODE_FULL;
}
proto_drv = bdrv_find_protocol(target);
if (!proto_drv) {
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
return;
}
bdrv_get_geometry(bs, &size);
size *= 512;
if (sync == MIRROR_SYNC_MODE_FULL && mode != NEW_IMAGE_MODE_EXISTING) {
/* create new image w/o backing file */
assert(format && drv);
bdrv_img_create(target, format,
NULL, NULL, NULL, size, flags, &local_err);
} else {
switch (mode) {
case NEW_IMAGE_MODE_EXISTING:
ret = 0;
break;
case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
/* create new image with backing file */
bdrv_img_create(target, format,
source->filename,
source->drv->format_name,
NULL, size, flags, &local_err);
break;
default:
abort();
}
}
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
return;
}
/* Mirroring takes care of copy-on-write using the source's backing
* file.
*/
target_bs = bdrv_new("");
ret = bdrv_open(target_bs, target, flags | BDRV_O_NO_BACKING, drv);
if (ret < 0) {
bdrv_delete(target_bs);
error_set(errp, QERR_OPEN_FILE_FAILED, target);
return;
}
mirror_start(bs, target_bs, speed, granularity, buf_size, sync,
on_source_error, on_target_error,
block_job_cb, bs, &local_err);
if (local_err != NULL) {
bdrv_delete(target_bs);
error_propagate(errp, local_err);
return;
}
/* Grab a reference so hotplug does not delete the BlockDriverState from
* underneath us.
*/
drive_get_ref(drive_get_by_blockdev(bs));
}
static BlockJob *find_block_job(const char *device)
{
BlockDriverState *bs;
@@ -1353,28 +1142,19 @@ void qmp_block_job_set_speed(const char *device, int64_t speed, Error **errp)
BlockJob *job = find_block_job(device);
if (!job) {
error_set(errp, QERR_BLOCK_JOB_NOT_ACTIVE, device);
error_set(errp, QERR_DEVICE_NOT_ACTIVE, device);
return;
}
block_job_set_speed(job, speed, errp);
}
void qmp_block_job_cancel(const char *device,
bool has_force, bool force, Error **errp)
void qmp_block_job_cancel(const char *device, Error **errp)
{
BlockJob *job = find_block_job(device);
if (!has_force) {
force = false;
}
if (!job) {
error_set(errp, QERR_BLOCK_JOB_NOT_ACTIVE, device);
return;
}
if (job->paused && !force) {
error_set(errp, QERR_BLOCK_JOB_PAUSED, device);
error_set(errp, QERR_DEVICE_NOT_ACTIVE, device);
return;
}
@@ -1382,53 +1162,25 @@ void qmp_block_job_cancel(const char *device,
block_job_cancel(job);
}
void qmp_block_job_pause(const char *device, Error **errp)
{
BlockJob *job = find_block_job(device);
if (!job) {
error_set(errp, QERR_BLOCK_JOB_NOT_ACTIVE, device);
return;
}
trace_qmp_block_job_pause(job);
block_job_pause(job);
}
void qmp_block_job_resume(const char *device, Error **errp)
{
BlockJob *job = find_block_job(device);
if (!job) {
error_set(errp, QERR_BLOCK_JOB_NOT_ACTIVE, device);
return;
}
trace_qmp_block_job_resume(job);
block_job_resume(job);
}
void qmp_block_job_complete(const char *device, Error **errp)
{
BlockJob *job = find_block_job(device);
if (!job) {
error_set(errp, QERR_BLOCK_JOB_NOT_ACTIVE, device);
return;
}
trace_qmp_block_job_complete(job);
block_job_complete(job, errp);
}
static void do_qmp_query_block_jobs_one(void *opaque, BlockDriverState *bs)
{
BlockJobInfoList **prev = opaque;
BlockJob *job = bs->job;
if (job) {
BlockJobInfoList *elem = g_new0(BlockJobInfoList, 1);
elem->value = block_job_query(bs->job);
BlockJobInfoList *elem;
BlockJobInfo *info = g_new(BlockJobInfo, 1);
*info = (BlockJobInfo){
.type = g_strdup(job->job_type->job_type),
.device = g_strdup(bdrv_get_device_name(bs)),
.len = job->len,
.offset = job->offset,
.speed = job->speed,
};
elem = g_new0(BlockJobInfoList, 1);
elem->value = info;
(*prev)->next = elem;
*prev = elem;
}
@@ -1442,121 +1194,3 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp)
bdrv_iterate(do_qmp_query_block_jobs_one, &prev);
return dummy.next;
}
QemuOptsList qemu_drive_opts = {
.name = "drive",
.head = QTAILQ_HEAD_INITIALIZER(qemu_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 = "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 */ }
},
};

View File

@@ -10,22 +10,17 @@
#ifndef BLOCKDEV_H
#define BLOCKDEV_H
#include "block/block.h"
#include "qapi/error.h"
#include "qemu/queue.h"
#include "block.h"
#include "error.h"
#include "qemu-queue.h"
void blockdev_mark_auto_del(BlockDriverState *bs);
void blockdev_auto_del(BlockDriverState *bs);
typedef enum {
IF_DEFAULT = -1, /* for use with drive_add() only */
/*
* IF_IDE must be zero, because we want QEMUMachine member
* block_default_type to default-initialize to IF_IDE
*/
IF_IDE = 0,
IF_NONE,
IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN,
IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN,
IF_COUNT
} BlockInterfaceType;
@@ -56,7 +51,7 @@ DriveInfo *drive_get_by_blockdev(BlockDriverState *bs);
QemuOpts *drive_def(const char *optstr);
QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file,
const char *optstr);
DriveInfo *drive_init(QemuOpts *arg, BlockInterfaceType block_default_type);
DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi);
/* device-hotplug */

View File

@@ -1,283 +0,0 @@
/*
* QEMU System Emulator block driver
*
* Copyright (c) 2011 IBM Corp.
* Copyright (c) 2012 Red Hat, Inc.
*
* 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 "config-host.h"
#include "qemu-common.h"
#include "trace.h"
#include "monitor/monitor.h"
#include "block/block.h"
#include "block/blockjob.h"
#include "block/block_int.h"
#include "qapi/qmp/qjson.h"
#include "block/coroutine.h"
#include "qmp-commands.h"
#include "qemu/timer.h"
void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs,
int64_t speed, BlockDriverCompletionFunc *cb,
void *opaque, Error **errp)
{
BlockJob *job;
if (bs->job || bdrv_in_use(bs)) {
error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
return NULL;
}
bdrv_set_in_use(bs, 1);
job = g_malloc0(job_type->instance_size);
job->job_type = job_type;
job->bs = bs;
job->cb = cb;
job->opaque = opaque;
job->busy = true;
bs->job = job;
/* Only set speed when necessary to avoid NotSupported error */
if (speed != 0) {
Error *local_err = NULL;
block_job_set_speed(job, speed, &local_err);
if (error_is_set(&local_err)) {
bs->job = NULL;
g_free(job);
bdrv_set_in_use(bs, 0);
error_propagate(errp, local_err);
return NULL;
}
}
return job;
}
void block_job_completed(BlockJob *job, int ret)
{
BlockDriverState *bs = job->bs;
assert(bs->job == job);
job->cb(job->opaque, ret);
bs->job = NULL;
g_free(job);
bdrv_set_in_use(bs, 0);
}
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
{
Error *local_err = NULL;
if (!job->job_type->set_speed) {
error_set(errp, QERR_NOT_SUPPORTED);
return;
}
job->job_type->set_speed(job, speed, &local_err);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
return;
}
job->speed = speed;
}
void block_job_complete(BlockJob *job, Error **errp)
{
if (job->paused || job->cancelled || !job->job_type->complete) {
error_set(errp, QERR_BLOCK_JOB_NOT_READY, job->bs->device_name);
return;
}
job->job_type->complete(job, errp);
}
void block_job_pause(BlockJob *job)
{
job->paused = true;
}
bool block_job_is_paused(BlockJob *job)
{
return job->paused;
}
void block_job_resume(BlockJob *job)
{
job->paused = false;
block_job_iostatus_reset(job);
if (job->co && !job->busy) {
qemu_coroutine_enter(job->co, NULL);
}
}
void block_job_cancel(BlockJob *job)
{
job->cancelled = true;
block_job_resume(job);
}
bool block_job_is_cancelled(BlockJob *job)
{
return job->cancelled;
}
void block_job_iostatus_reset(BlockJob *job)
{
job->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
if (job->job_type->iostatus_reset) {
job->job_type->iostatus_reset(job);
}
}
struct BlockCancelData {
BlockJob *job;
BlockDriverCompletionFunc *cb;
void *opaque;
bool cancelled;
int ret;
};
static void block_job_cancel_cb(void *opaque, int ret)
{
struct BlockCancelData *data = opaque;
data->cancelled = block_job_is_cancelled(data->job);
data->ret = ret;
data->cb(data->opaque, ret);
}
int block_job_cancel_sync(BlockJob *job)
{
struct BlockCancelData data;
BlockDriverState *bs = job->bs;
assert(bs->job == job);
/* Set up our own callback to store the result and chain to
* the original callback.
*/
data.job = job;
data.cb = job->cb;
data.opaque = job->opaque;
data.ret = -EINPROGRESS;
job->cb = block_job_cancel_cb;
job->opaque = &data;
block_job_cancel(job);
while (data.ret == -EINPROGRESS) {
qemu_aio_wait();
}
return (data.cancelled && data.ret == 0) ? -ECANCELED : data.ret;
}
void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns)
{
assert(job->busy);
/* Check cancellation *before* setting busy = false, too! */
if (block_job_is_cancelled(job)) {
return;
}
job->busy = false;
if (block_job_is_paused(job)) {
qemu_coroutine_yield();
} else {
co_sleep_ns(clock, ns);
}
job->busy = true;
}
BlockJobInfo *block_job_query(BlockJob *job)
{
BlockJobInfo *info = g_new0(BlockJobInfo, 1);
info->type = g_strdup(job->job_type->job_type);
info->device = g_strdup(bdrv_get_device_name(job->bs));
info->len = job->len;
info->busy = job->busy;
info->paused = job->paused;
info->offset = job->offset;
info->speed = job->speed;
info->io_status = job->iostatus;
return info;
}
static void block_job_iostatus_set_err(BlockJob *job, int error)
{
if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
job->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE :
BLOCK_DEVICE_IO_STATUS_FAILED;
}
}
QObject *qobject_from_block_job(BlockJob *job)
{
return qobject_from_jsonf("{ 'type': %s,"
"'device': %s,"
"'len': %" PRId64 ","
"'offset': %" PRId64 ","
"'speed': %" PRId64 " }",
job->job_type->job_type,
bdrv_get_device_name(job->bs),
job->len,
job->offset,
job->speed);
}
void block_job_ready(BlockJob *job)
{
QObject *data = qobject_from_block_job(job);
monitor_protocol_event(QEVENT_BLOCK_JOB_READY, data);
qobject_decref(data);
}
BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
BlockdevOnError on_err,
int is_read, int error)
{
BlockErrorAction action;
switch (on_err) {
case BLOCKDEV_ON_ERROR_ENOSPC:
action = (error == ENOSPC) ? BDRV_ACTION_STOP : BDRV_ACTION_REPORT;
break;
case BLOCKDEV_ON_ERROR_STOP:
action = BDRV_ACTION_STOP;
break;
case BLOCKDEV_ON_ERROR_REPORT:
action = BDRV_ACTION_REPORT;
break;
case BLOCKDEV_ON_ERROR_IGNORE:
action = BDRV_ACTION_IGNORE;
break;
default:
abort();
}
bdrv_emit_qmp_error_event(job->bs, QEVENT_BLOCK_JOB_ERROR, action, is_read);
if (action == BDRV_ACTION_STOP) {
block_job_pause(job);
block_job_iostatus_set_err(job, error);
if (bs != job->bs) {
bdrv_iostatus_set_err(bs, error);
}
}
return action;
}

View File

@@ -10,7 +10,7 @@
#include <string.h>
#include "qemu.h"
#include "disas/disas.h"
#include "disas.h"
#ifdef _ARCH_PPC64
#undef ARCH_DLINFO

View File

@@ -31,8 +31,8 @@
/* For tb_lock */
#include "cpu.h"
#include "tcg.h"
#include "qemu/timer.h"
#include "qemu/envlist.h"
#include "qemu-timer.h"
#include "envlist.h"
#define DEBUG_LOGFILE "/tmp/qemu.log"
@@ -917,7 +917,7 @@ int main(int argc, char **argv)
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
#if defined(TARGET_SPARC) || defined(TARGET_PPC)
#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
cpu_reset(ENV_GET_CPU(env));
#endif
thread_env = env;

View File

@@ -74,7 +74,7 @@ void mmap_unlock(void)
}
#endif
static void *bsd_vmalloc(size_t size)
void *qemu_vmalloc(size_t size)
{
void *p;
mmap_lock();
@@ -98,7 +98,7 @@ void *g_malloc(size_t size)
{
char * p;
size += 16;
p = bsd_vmalloc(size);
p = qemu_vmalloc(size);
*(size_t *)p = size;
return p + 16;
}

24
bsd-user/qemu-types.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef QEMU_TYPES_H
#define QEMU_TYPES_H
#include "cpu.h"
#ifdef TARGET_ABI32
typedef uint32_t abi_ulong;
typedef int32_t abi_long;
#define TARGET_ABI_FMT_lx "%08x"
#define TARGET_ABI_FMT_ld "%d"
#define TARGET_ABI_FMT_lu "%u"
#define TARGET_ABI_BITS 32
#else
typedef target_ulong abi_ulong;
typedef target_long abi_long;
#define TARGET_ABI_FMT_lx TARGET_FMT_lx
#define TARGET_ABI_FMT_ld TARGET_FMT_ld
#define TARGET_ABI_FMT_lu TARGET_FMT_lu
#define TARGET_ABI_BITS TARGET_LONG_BITS
/* for consistency, define ABI32 too */
#if TARGET_ABI_BITS == 32
#define TARGET_ABI32 1
#endif
#endif
#endif

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