import stable-4 build files

master
Wolfgang Bumiller 2017-04-05 10:49:19 +02:00
commit 9525982417
117 changed files with 13967 additions and 0 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "qemu"]
path = qemu
url = ../mirror_qemu

54
Makefile Normal file
View File

@ -0,0 +1,54 @@
# also update debian/changelog
KVMVER=2.7.1
KVMPKGREL=4
KVMPACKAGE = pve-qemu-kvm
KVMSRC = qemu
BUILDSRC = $(KVMSRC).tmp
SRCDIR := qemu
ARCH := $(shell dpkg-architecture -qDEB_BUILD_ARCH)
GITVERSION := $(shell git rev-parse master)
DEB = ${KVMPACKAGE}_${KVMVER}-${KVMPKGREL}_${ARCH}.deb
DEB_DBG = ${KVMPACKAGE}-dbg_${KVMVER}-${KVMPKGREL}_${ARCH}.deb
DEBS = $(DEB) $(DEB_DBG)
all: $(DEBS)
.PHONY: submodule
submodule:
test -f "${SRCDIR}/debian/changelog" || git submodule update --init
.PHONY: deb kvm
deb kvm: $(DEBS)
$(DEB_DBG): $(DEB)
$(DEB): | submodule
rm -f *.deb
rm -rf $(BUILDSRC)
mkdir $(BUILDSRC)
cp -a $(KVMSRC)/* $(BUILDSRC)/
tar -C $(BUILDSRC) -xJf efi-roms-1182.tar.xz
cp -a debian $(BUILDSRC)/debian
echo "git clone git://git.proxmox.com/git/pve-qemu-kvm.git\\ngit checkout $(GITVERSION)" > $(BUILDSRC)/debian/SOURCE
# set package version
sed -i 's/^pkgversion="".*/pkgversion="${KVMPACKAGE}_${KVMVER}-${KVMPKGREL}"/' $(BUILDSRC)/configure
cd $(BUILDSRC); dpkg-buildpackage -b -rfakeroot -us -uc
lintian $(DEBS) || true
.PHONY: upload
upload: $(DEBS)
tar cf - $(DEBS) | ssh repoman@repo.proxmox.com upload --produce pve --dist jessie
.PHONY: distclean
distclean: clean
.PHONY: clean
clean:
rm -rf $(BUILDSRC) $(KVMPACKAGE)_* $(DEBS) *.buildinfo
.PHONY: dinstall
dinstall: $(DEBS)
dpkg -i $(DEBS)

116
backup.txt Normal file
View File

@ -0,0 +1,116 @@
Efficient VM backup for qemu
=Requirements=
* Backup to a single archive file
* Backup needs to contain all data to restore VM (full backup)
* Do not depend on storage type or image format
* Avoid use of temporary storage
* store sparse images efficiently
=Introduction=
Most VM backup solutions use some kind of snapshot to get a consistent
VM view at a specific point in time. For example, we previously used
LVM to create a snapshot of all used VM images, which are then copied
into a tar file.
That basically means that any data written during backup involve
considerable overhead. For LVM we get the following steps:
1.) read original data (VM write)
2.) write original data into snapshot (VM write)
3.) write new data (VM write)
4.) read data from snapshot (backup)
5.) write data from snapshot into tar file (backup)
Another approach to backup VM images is to create a new qcow2 image
which use the old image as base. During backup, writes are redirected
to the new image, so the old image represents a 'snapshot'. After
backup, data need to be copied back from new image into the old
one (commit). So a simple write during backup triggers the following
steps:
1.) write new data to new image (VM write)
2.) read data from old image (backup)
3.) write data from old image into tar file (backup)
4.) read data from new image (commit)
5.) write data to old image (commit)
This is in fact the same overhead as before. Other tools like qemu
livebackup produces similar overhead (2 reads, 3 writes).
Some storage types/formats supports internal snapshots using some kind
of reference counting (rados, sheepdog, dm-thin, qcow2). It would be possible
to use that for backups, but for now we want to be storage-independent.
=Make it more efficient=
The be more efficient, we simply need to avoid unnecessary steps. The
following steps are always required:
1.) read old data before it gets overwritten
2.) write that data into the backup archive
3.) write new data (VM write)
As you can see, this involves only one read, and two writes.
To make that work, our backup archive need to be able to store image
data 'out of order'. It is important to notice that this will not work
with traditional archive formats like tar.
During backup we simply intercept writes, then read existing data and
store that directly into the archive. After that we can continue the
write.
==Advantages==
* very good performance (1 read, 2 writes)
* works on any storage type and image format.
* avoid usage of temporary storage
* we can define a new and simple archive format, which is able to
store sparse files efficiently.
Note: Storing sparse files is a mess with existing archive
formats. For example, tar requires information about holes at the
beginning of the archive.
==Disadvantages==
* we need to define a new archive format
Note: Most existing archive formats are optimized to store small files
including file attributes. We simply do not need that for VM archives.
* archive contains data 'out of order'
If you want to access image data in sequential order, you need to
re-order archive data. It would be possible to to that on the fly,
using temporary files.
Fortunately, a normal restore/extract works perfectly with 'out of
order' data, because the target files are seekable.
* slow backup storage can slow down VM during backup
It is important to note that we only do sequential writes to the
backup storage. Furthermore one can compress the backup stream. IMHO,
it is better to slow down the VM a bit. All other solutions creates
large amounts of temporary data during backup.
=Archive format requirements=
The basic requirement for such new format is that we can store image
date 'out of order'. It is also very likely that we have less than 256
drives/images per VM, and we want to be able to store VM configuration
files.
We have defined a very simply format with those properties, see:
https://git.proxmox.com/?p=pve-qemu-kvm.git;a=blob;f=vma_spec.txt;
Please let us know if you know an existing format which provides the
same functionality.

BIN
debian/Logo.bmp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
debian/OVMF_CODE-pure-efi.fd vendored Normal file

Binary file not shown.

11
debian/OVMF_README.txt vendored Normal file
View File

@ -0,0 +1,11 @@
The OVMF images were built through the edk2 github repository.
git clone https://github.com/tianocore/edk2
set up the build environment
copy the Logo.bmp to ./edk2/MdeModulePkg/Logo/
call ./edk2/OvmfPkg/build.sh -a X64 -b RELEASE
The license is under ./edk2/OvmfPkg/License.txt

BIN
debian/OVMF_VARS-pure-efi.fd vendored Normal file

Binary file not shown.

1328
debian/changelog vendored Normal file

File diff suppressed because it is too large Load Diff

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
5

25
debian/control vendored Normal file
View File

@ -0,0 +1,25 @@
Source: pve-qemu-kvm
Section: admin
Priority: extra
Maintainer: Proxmox Support Team <support@proxmox.com>
Build-Depends: debhelper (>= 5), autotools-dev, libpci-dev, quilt, texinfo, texi2html, libgnutls28-dev, libsdl1.2-dev, check, libaio-dev, uuid-dev, librbd-dev (>= 0.48), libiscsi-dev (>= 1.12.0), libspice-protocol-dev (>= 0.12.5), pve-libspice-server-dev (>= 0.12.5-1), libusbredirparser-dev (>= 0.6-2), glusterfs-common (>= 3.5.2-1), libusb-1.0-0-dev (>= 1.0.17-1), xfslibs-dev, libnuma-dev, libjemalloc-dev, libjpeg-dev, libacl1-dev
Standards-Version: 3.7.2
Package: pve-qemu-kvm
Architecture: any
Depends: iproute2, bridge-utils, python, libsdl1.2debian, libaio1, libuuid1, ceph-common (>= 0.48), libiscsi4 (>= 1.12.0) | libiscsi7, pve-libspice-server1 (>= 0.12.5-1), ${shlibs:Depends}, ${misc:Depends}, libusbredirparser1 (>= 0.6-2), glusterfs-common (>= 3.5.2-1), libusb-1.0-0 (>= 1.0.17-1), numactl, libjemalloc1, libjpeg62-turbo
Conflicts: qemu, qemu-kvm, qemu-utils, kvm, pve-kvm, pve-qemu-kvm-2.6.18
Provides: qemu-utils
Replaces: pve-kvm, pve-qemu-kvm-2.6.18, qemu-utils
Description: Full virtualization on x86 hardware
Using KVM, one can run multiple virtual PCs, each running unmodified Linux or
Windows images. Each virtual machine has private virtualized hardware: a
network card, disk, graphics adapter, etc.
Package: pve-qemu-kvm-dbg
Architecture: any
Section: debug
Depends: pve-qemu-kvm (= ${binary:Version})
Description: pve qemu debugging symbols
This package contains the debugging symbols for pve-qemu-kvm.

92
debian/copyright vendored Normal file
View File

@ -0,0 +1,92 @@
This package was debianized by the proxmox support team <support@proxmox.com>
It was downloaded from
git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git
Upstream Author: Fabrice Bellard <fabrice.bellard@free.fr>
Upstream Maintainers: Avi Kivity <avi@redhat.com>
Anthony Liguori <aliguori@us.ibm.com>
Copyright: Copyright (C) 2006 Qumranet, Inc.
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Fabrice Bellard
License:
QEMU as a whole is released under the GNU General Public License version 2.
On Debian systems, the complete text of the GNU General Public License
version 2 can be found in the file /usr/share/common-licenses/GPL-2.
Parts of QEMU have specific licenses which are compatible with the
GNU General Public License. Hence each source file contains its own
licensing information.
In particular, the QEMU virtual CPU core library (libqemu.a) is
released under the GNU Lesser General Public License version 2 or later.
On Debian systems, the complete text of the GNU Lesser General Public
License can be found in the file /usr/share/common-licenses/LGPL.
Some hardware device emulation sources and other QEMU functionality are
released under the BSD license, including:
* aes, bsd-user, sd, slirp, sys-queue
Some hardware device emulation sources and other QEMU functionality are
released under the MIT/X11 (BSD-like) license, including:
* sdl, host-utils, vnc, keymaps, ioport, usb, hw/*, net, acl, block,
kqemu, monitor, curses, readline, vl, savevm, osdep, audio, tcg,
qemu-malloc, qemu-img
The following points clarify the QEMU license:
1) QEMU as a whole is released under the GNU General Public License
2) Parts of QEMU have specific licenses which are compatible with the
GNU General Public License. Hence each source file contains its own
licensing information.
In particular, the QEMU virtual CPU core library (libqemu.a) is
released under the GNU Lesser General Public License. Many hardware
device emulation sources are released under the BSD license.
3) The Tiny Code Generator (TCG) is released under the BSD license
(see license headers in files).
4) QEMU is a trademark of Fabrice Bellard.
-- Fabrice Bellard.
BIOS sources in QEMU:
bios.bin: Copyright (C) 2002 MandrakeSoft S.A. and others. This file
is licensed under the GNU LGPL, version 2, or (at your option) any later
version.
Homepage: http://sourceforge.net/projects/bochs
vgabios.bin and vgabios-cirrus.bin: (C) 2003 the LGPL VGABios
developers Team. These files are licensed under the GNU LGPL, version 2,
or (at your option) any later version.
Homepage: http://savannah.nongnu.org/projects/vgabios
BSD license:
Copyright (c) The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

1
debian/docs vendored Normal file
View File

@ -0,0 +1 @@
debian/SOURCE

3
debian/kvm-ifdown vendored Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
exit 0

5
debian/kvm-ifup vendored Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
switch=$(/sbin/ip route list | awk '/^default / { print $NF }')
/sbin/ifconfig $1 0.0.0.0 promisc up
/sbin/brctl addif ${switch} $1

View File

@ -0,0 +1,33 @@
From 603c472d61c354c30bc898b0e9ff1914302cbca9 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Mon, 4 Jul 2016 15:02:26 +0200
Subject: [PATCH 1/3] Revert "target-i386: disable LINT0 after reset"
This reverts commit b8eb5512fd8a115f164edbbe897cdf8884920ccb.
---
hw/intc/apic_common.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
index 14ac43c..1ed0511 100644
--- a/hw/intc/apic_common.c
+++ b/hw/intc/apic_common.c
@@ -246,6 +246,15 @@ static void apic_reset_common(DeviceState *dev)
info->vapic_base_update(s);
apic_init_reset(dev);
+
+ if (bsp) {
+ /*
+ * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
+ * time typically by BIOS, so PIC interrupt can be delivered to the
+ * processor when local APIC is enabled.
+ */
+ s->lvt[APIC_LVT_LINT0] = 0x700;
+ }
}
/* This function is only used for old state version 1 and 2 */
--
2.1.4

View File

@ -0,0 +1,100 @@
From 391a9e6fd8c6cf615f2ffe44bb85245df52cc2b6 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 9 Feb 2017 14:02:20 +0100
Subject: [PATCH 1/2] cirrus: fix patterncopy checks
The blit_region_is_unsafe checks don't work correctly for the
patterncopy source. It's a fixed-sized region, which doesn't
depend on cirrus_blt_{width,height}. So go do the check in
cirrus_bitblt_common_patterncopy instead, then tell blit_is_unsafe that
it doesn't need to verify the source. Also handle the case where we
blit from cirrus_bitbuf correctly.
This patch replaces 5858dd1801883309bdd208d72ddb81c4e9fee30c.
Security impact: I think for the most part error on the safe side this
time, refusing blits which should have been allowed.
Only exception is placing the blit source at the end of the video ram,
so cirrus_blt_srcaddr + 256 goes beyond the end of video memory. But
even in that case I'm not fully sure this actually allows read access to
host memory. To trick the commit 5858dd18 security checks one has to
pick very small cirrus_blt_{width,height} values, which in turn implies
only a fraction of the blit source will actually be used.
Cc: Wolfgang Bumiller <w.bumiller@proxmox.com>
Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/cirrus_vga.c | 36 ++++++++++++++++++++++++++++++------
1 file changed, 30 insertions(+), 6 deletions(-)
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 16f27e8..6bd13fc 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -683,14 +683,39 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
}
}
-static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
- const uint8_t * src)
+static int cirrus_bitblt_common_patterncopy(CirrusVGAState *s, bool videosrc)
{
+ uint32_t patternsize;
uint8_t *dst;
+ uint8_t *src;
dst = s->vga.vram_ptr + s->cirrus_blt_dstaddr;
- if (blit_is_unsafe(s, false, true)) {
+ if (videosrc) {
+ switch (s->vga.get_bpp(&s->vga)) {
+ case 8:
+ patternsize = 64;
+ break;
+ case 15:
+ case 16:
+ patternsize = 128;
+ break;
+ case 24:
+ case 32:
+ default:
+ patternsize = 256;
+ break;
+ }
+ s->cirrus_blt_srcaddr &= ~(patternsize - 1);
+ if (s->cirrus_blt_srcaddr + patternsize > s->vga.vram_size) {
+ return 0;
+ }
+ src = s->vga.vram_ptr + s->cirrus_blt_srcaddr;
+ } else {
+ src = s->cirrus_bltbuf;
+ }
+
+ if (blit_is_unsafe(s, true, true)) {
return 0;
}
@@ -731,8 +756,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
{
- return cirrus_bitblt_common_patterncopy(s, s->vga.vram_ptr +
- (s->cirrus_blt_srcaddr & ~7));
+ return cirrus_bitblt_common_patterncopy(s, true);
}
static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
@@ -831,7 +855,7 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
if (s->cirrus_srccounter > 0) {
if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
- cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
+ cirrus_bitblt_common_patterncopy(s, false);
the_end:
s->cirrus_srccounter = 0;
cirrus_bitblt_reset(s);
--
2.1.4

View File

@ -0,0 +1,51 @@
From b3ce5aeaacdd0cec5bab1d83ee24bae73b0dd506 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 25 Jan 2017 14:48:57 +0100
Subject: [PATCH 1/4] cirrus: handle negative pitch in
cirrus_invalidate_region()
cirrus_invalidate_region() calls memory_region_set_dirty()
on a per-line basis, always ranging from off_begin to
off_begin+bytesperline. With a negative pitch off_begin
marks the top most used address and thus we need to do an
initial shift backwards by a line for negative pitches of
backward blits, otherwise the first iteration covers the
line going from the start offset forwards instead of
backwards.
Additionally since the start address is inclusive, if we
shift by a full `bytesperline` we move to the first address
*not* included in the blit, so we only shift by one less
than bytesperline.
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Message-id: 1485352137-29367-1-git-send-email-w.bumiller@proxmox.com
[ kraxel: codestyle fixes ]
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/cirrus_vga.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 379910d..0f05e45 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -661,9 +661,14 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
int off_cur;
int off_cur_end;
+ if (off_pitch < 0) {
+ off_begin -= bytesperline - 1;
+ }
+
for (y = 0; y < lines; y++) {
off_cur = off_begin;
off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
+ assert(off_cur_end >= off_cur);
memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
off_begin += off_pitch;
}
--
2.1.4

View File

@ -0,0 +1,72 @@
From f5dc8e6b503fda1ed87c0f4f53c6d2c76a584872 Mon Sep 17 00:00:00 2001
From: Bruce Rogers <brogers@suse.com>
Date: Mon, 9 Jan 2017 13:35:20 -0700
Subject: [PATCH 1/5] display: cirrus: ignore source pitch value as needed in
blit_is_unsafe
Commit 4299b90 added a check which is too broad, given that the source
pitch value is not required to be initialized for solid fill operations.
This patch refines the blit_is_unsafe() check to ignore source pitch in
that case. After applying the above commit as a security patch, we
noticed the SLES 11 SP4 guest gui failed to initialize properly.
Signed-off-by: Bruce Rogers <brogers@suse.com>
Message-id: 20170109203520.5619-1-brogers@suse.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/cirrus_vga.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index bdb092e..379910d 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -294,7 +294,7 @@ static bool blit_region_is_unsafe(struct CirrusVGAState *s,
return false;
}
-static bool blit_is_unsafe(struct CirrusVGAState *s)
+static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only)
{
/* should be the case, see cirrus_bitblt_start */
assert(s->cirrus_blt_width > 0);
@@ -308,6 +308,9 @@ static bool blit_is_unsafe(struct CirrusVGAState *s)
s->cirrus_blt_dstaddr & s->cirrus_addr_mask)) {
return true;
}
+ if (dst_only) {
+ return false;
+ }
if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
s->cirrus_blt_srcaddr & s->cirrus_addr_mask)) {
return true;
@@ -673,7 +676,7 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
- if (blit_is_unsafe(s))
+ if (blit_is_unsafe(s, false))
return 0;
(*s->cirrus_rop) (s, dst, src,
@@ -691,7 +694,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
{
cirrus_fill_t rop_func;
- if (blit_is_unsafe(s)) {
+ if (blit_is_unsafe(s, true)) {
return 0;
}
rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
@@ -795,7 +798,7 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
{
- if (blit_is_unsafe(s))
+ if (blit_is_unsafe(s, false))
return 0;
return cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
--
2.1.4

View File

@ -0,0 +1,101 @@
From cba280fe94eaed53952e2997cac1ee2bed6cfdee Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Fri, 10 Feb 2017 08:34:03 +0100
Subject: [PATCH 2/2] Revert "cirrus: allow zero source pitch in pattern fill
rops"
This reverts commit cf9c099a7694eb47ded529e1ed40ee8789f32d31.
Conflicts:
hw/display/cirrus_vga.c
---
hw/display/cirrus_vga.c | 29 +++++++++--------------------
1 file changed, 9 insertions(+), 20 deletions(-)
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 6bd13fc..92e7951 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -272,6 +272,9 @@ static void cirrus_update_memory_access(CirrusVGAState *s);
static bool blit_region_is_unsafe(struct CirrusVGAState *s,
int32_t pitch, int32_t addr)
{
+ if (!pitch) {
+ return true;
+ }
if (pitch < 0) {
int64_t min = addr
+ ((int64_t)s->cirrus_blt_height - 1) * pitch
@@ -290,11 +293,8 @@ static bool blit_region_is_unsafe(struct CirrusVGAState *s,
return false;
}
-static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only,
- bool zero_src_pitch_ok)
+static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only)
{
- int32_t check_pitch;
-
/* should be the case, see cirrus_bitblt_start */
assert(s->cirrus_blt_width > 0);
assert(s->cirrus_blt_height > 0);
@@ -303,10 +303,6 @@ static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only,
return true;
}
- if (!s->cirrus_blt_dstpitch) {
- return true;
- }
-
if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
s->cirrus_blt_dstaddr)) {
return true;
@@ -314,14 +310,8 @@ static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only,
if (dst_only) {
return false;
}
-
- check_pitch = s->cirrus_blt_srcpitch;
- if (!zero_src_pitch_ok && !check_pitch) {
- check_pitch = s->cirrus_blt_width;
- }
-
- if (blit_region_is_unsafe(s, check_pitch,
- s->cirrus_blt_srcaddr)) {
+ if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
+ s->cirrus_blt_srcaddr & s->cirrus_addr_mask)) {
return true;
}
@@ -715,9 +705,8 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState *s, bool videosrc)
src = s->cirrus_bltbuf;
}
- if (blit_is_unsafe(s, true, true)) {
+ if (blit_is_unsafe(s, true))
return 0;
- }
(*s->cirrus_rop) (s, dst, src,
s->cirrus_blt_dstpitch, 0,
@@ -734,7 +723,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
{
cirrus_fill_t rop_func;
- if (blit_is_unsafe(s, true, true)) {
+ if (blit_is_unsafe(s, true)) {
return 0;
}
rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
@@ -834,7 +823,7 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
{
- if (blit_is_unsafe(s, false, false))
+ if (blit_is_unsafe(s, false))
return 0;
return cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
--
2.1.4

View File

@ -0,0 +1,102 @@
From cf9c099a7694eb47ded529e1ed40ee8789f32d31 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Tue, 24 Jan 2017 16:35:38 +0100
Subject: [PATCH 2/4] cirrus: allow zero source pitch in pattern fill rops
The rops used by cirrus_bitblt_common_patterncopy only use
the destination pitch, so the source pitch shoul allowed to
be zero and the blit with used for the range check around the
source address.
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Message-id: 1485272138-23249-1-git-send-email-w.bumiller@proxmox.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/cirrus_vga.c | 27 +++++++++++++++++++--------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 0f05e45..98f089e 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -272,9 +272,6 @@ static void cirrus_update_memory_access(CirrusVGAState *s);
static bool blit_region_is_unsafe(struct CirrusVGAState *s,
int32_t pitch, int32_t addr)
{
- if (!pitch) {
- return true;
- }
if (pitch < 0) {
int64_t min = addr
+ ((int64_t)s->cirrus_blt_height-1) * pitch;
@@ -294,8 +291,11 @@ static bool blit_region_is_unsafe(struct CirrusVGAState *s,
return false;
}
-static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only)
+static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only,
+ bool zero_src_pitch_ok)
{
+ int32_t check_pitch;
+
/* should be the case, see cirrus_bitblt_start */
assert(s->cirrus_blt_width > 0);
assert(s->cirrus_blt_height > 0);
@@ -304,6 +304,10 @@ static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only)
return true;
}
+ if (!s->cirrus_blt_dstpitch) {
+ return true;
+ }
+
if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
s->cirrus_blt_dstaddr & s->cirrus_addr_mask)) {
return true;
@@ -311,7 +315,13 @@ static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only)
if (dst_only) {
return false;
}
- if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
+
+ check_pitch = s->cirrus_blt_srcpitch;
+ if (!zero_src_pitch_ok && !check_pitch) {
+ check_pitch = s->cirrus_blt_width;
+ }
+
+ if (blit_region_is_unsafe(s, check_pitch,
s->cirrus_blt_srcaddr & s->cirrus_addr_mask)) {
return true;
}
@@ -681,8 +691,9 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
- if (blit_is_unsafe(s, false))
+ if (blit_is_unsafe(s, false, true)) {
return 0;
+ }
(*s->cirrus_rop) (s, dst, src,
s->cirrus_blt_dstpitch, 0,
@@ -699,7 +710,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
{
cirrus_fill_t rop_func;
- if (blit_is_unsafe(s, true)) {
+ if (blit_is_unsafe(s, true, true)) {
return 0;
}
rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
@@ -803,7 +814,7 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
{
- if (blit_is_unsafe(s, false))
+ if (blit_is_unsafe(s, false, false))
return 0;
return cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
--
2.1.4

View File

@ -0,0 +1,31 @@
From 1313d27fc347633d0cf6fc2ff8cbe17a740dd658 Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Thu, 11 Aug 2016 00:42:20 +0530
Subject: [PATCH 2/3] net: vmxnet: initialise local tx descriptor
In Vmxnet3 device emulator while processing transmit(tx) queue,
when it reaches end of packet, it calls vmxnet3_complete_packet.
In that local 'txcq_descr' object is not initialised, which could
leak host memory bytes a guest.
Reported-by: Li Qiang <liqiang6-s@360.cn>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
---
hw/net/vmxnet3.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
index 90f6943..92f6af9 100644
--- a/hw/net/vmxnet3.c
+++ b/hw/net/vmxnet3.c
@@ -531,6 +531,7 @@ static void vmxnet3_complete_packet(VMXNET3State *s, int qidx, uint32_t tx_ridx)
VMXNET3_RING_DUMP(VMW_RIPRN, "TXC", qidx, &s->txq_descr[qidx].comp_ring);
+ memset(&txcq_descr, 0, sizeof(txcq_descr));
txcq_descr.txdIdx = tx_ridx;
txcq_descr.gen = vmxnet3_ring_curr_gen(&s->txq_descr[qidx].comp_ring);
--
2.1.4

View File

@ -0,0 +1,104 @@
From a173829e6ebd8b2d7f29028f106173ba067c8b8c Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 25 Jan 2017 11:09:56 +0100
Subject: [PATCH 3/4] cirrus: fix blit address mask handling
Apply the cirrus_addr_mask to cirrus_blt_dstaddr and cirrus_blt_srcaddr
right after assigning them, in cirrus_bitblt_start(), instead of having
this all over the place in the cirrus code, and missing a few places.
Reported-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 1485338996-17095-1-git-send-email-kraxel@redhat.com
---
hw/display/cirrus_vga.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 98f089e..7db6409 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -309,7 +309,7 @@ static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only,
}
if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
- s->cirrus_blt_dstaddr & s->cirrus_addr_mask)) {
+ s->cirrus_blt_dstaddr)) {
return true;
}
if (dst_only) {
@@ -322,7 +322,7 @@ static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only,
}
if (blit_region_is_unsafe(s, check_pitch,
- s->cirrus_blt_srcaddr & s->cirrus_addr_mask)) {
+ s->cirrus_blt_srcaddr)) {
return true;
}
@@ -689,7 +689,7 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
{
uint8_t *dst;
- dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
+ dst = s->vga.vram_ptr + s->cirrus_blt_dstaddr;
if (blit_is_unsafe(s, false, true)) {
return 0;
@@ -714,7 +714,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
return 0;
}
rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- rop_func(s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
+ rop_func(s, s->vga.vram_ptr + s->cirrus_blt_dstaddr,
s->cirrus_blt_dstpitch,
s->cirrus_blt_width, s->cirrus_blt_height);
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
@@ -732,9 +732,8 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
{
- return cirrus_bitblt_common_patterncopy(s,
- s->vga.vram_ptr + ((s->cirrus_blt_srcaddr & ~7) &
- s->cirrus_addr_mask));
+ return cirrus_bitblt_common_patterncopy(s, s->vga.vram_ptr +
+ (s->cirrus_blt_srcaddr & ~7));
}
static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
@@ -788,10 +787,8 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
if (notify)
graphic_hw_update(s->vga.con);
- (*s->cirrus_rop) (s, s->vga.vram_ptr +
- (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
- s->vga.vram_ptr +
- (s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
+ (*s->cirrus_rop) (s, s->vga.vram_ptr + s->cirrus_blt_dstaddr,
+ s->vga.vram_ptr + s->cirrus_blt_srcaddr,
s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
s->cirrus_blt_width, s->cirrus_blt_height);
@@ -842,8 +839,7 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
} else {
/* at least one scan line */
do {
- (*s->cirrus_rop)(s, s->vga.vram_ptr +
- (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
+ (*s->cirrus_rop)(s, s->vga.vram_ptr + s->cirrus_blt_dstaddr,
s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
s->cirrus_blt_width, 1);
@@ -962,6 +958,9 @@ static void cirrus_bitblt_start(CirrusVGAState * s)
s->cirrus_blt_modeext = s->vga.gr[0x33];
blt_rop = s->vga.gr[0x32];
+ s->cirrus_blt_dstaddr &= s->cirrus_addr_mask;
+ s->cirrus_blt_srcaddr &= s->cirrus_addr_mask;
+
#ifdef DEBUG_BITBLT
printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
blt_rop,
--
2.1.4

View File

@ -0,0 +1,37 @@
From 2705772316ff905f3ed08871c602fca1c636f332 Mon Sep 17 00:00:00 2001
From: Peter Lieven <pl@kamp.de>
Date: Thu, 30 Jun 2016 11:49:40 +0200
Subject: [PATCH 3/3] net: limit allocation in nc_sendv_compat
we only need to allocate enough memory to hold the packet. This might be
less than NET_BUFSIZE. Additionally fail early if the packet is larger
than NET_BUFSIZE.
Signed-off-by: Peter Lieven <pl@kamp.de>
---
net/net.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/net/net.c b/net/net.c
index c94d93d..2ac46a6 100644
--- a/net/net.c
+++ b/net/net.c
@@ -690,9 +690,13 @@ static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov,
buffer = iov[0].iov_base;
offset = iov[0].iov_len;
} else {
- buf = g_new(uint8_t, NET_BUFSIZE);
+ offset = iov_size(iov, iovcnt);
+ if (offset > NET_BUFSIZE) {
+ return -1;
+ }
+ buf = g_malloc(offset);
buffer = buf;
- offset = iov_to_buf(iov, iovcnt, 0, buf, NET_BUFSIZE);
+ offset = iov_to_buf(iov, iovcnt, 0, buf, offset);
}
if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) {
--
2.1.4

View File

@ -0,0 +1,61 @@
From da4c6050712be98934918e348aa34a74be0e4e57 Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Tue, 31 Jan 2017 17:54:15 +0530
Subject: [PATCH 3/8] sd: sdhci: check transfer mode register in multi block
transfer
In SDHCI device emulation the transfer mode register value
is used during multi block transfer to check if block count
register is enabled and should be updated. Transfer mode
register could be set such that, block count register would
not be updated, thus leading to an infinite loop. Add check
to avoid it.
Reported-by: Wjjzhang <wjjzhang@tencent.com>
Reported-by: Jiang Xin <jiangxin1@huawei.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
---
hw/sd/sdhci.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 01fbf22..35f953a 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -486,6 +486,12 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
uint32_t boundary_chk = 1 << (((s->blksize & 0xf000) >> 12) + 12);
uint32_t boundary_count = boundary_chk - (s->sdmasysad % boundary_chk);
+ if (!(s->trnmod & SDHC_TRNS_MULTI)
+ || !(s->trnmod & SDHC_TRNS_BLK_CNT_EN)
+ || !s->blkcnt) {
+ return;
+ }
+
/* XXX: Some sd/mmc drivers (for example, u-boot-slp) do not account for
* possible stop at page boundary if initial address is not page aligned,
* allow them to work properly */
@@ -797,11 +803,6 @@ static void sdhci_data_transfer(void *opaque)
if (s->trnmod & SDHC_TRNS_DMA) {
switch (SDHC_DMA_TYPE(s->hostctl)) {
case SDHC_CTRL_SDMA:
- if ((s->trnmod & SDHC_TRNS_MULTI) &&
- (!(s->trnmod & SDHC_TRNS_BLK_CNT_EN) || s->blkcnt == 0)) {
- break;
- }
-
if ((s->blkcnt == 1) || !(s->trnmod & SDHC_TRNS_MULTI)) {
sdhci_sdma_transfer_single_block(s);
} else {
@@ -1050,7 +1051,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
if (!(s->capareg & SDHC_CAN_DO_DMA)) {
value &= ~SDHC_TRNS_DMA;
}
- MASKED_WRITE(s->trnmod, mask, value);
+ MASKED_WRITE(s->trnmod, mask, value & 0x0037);
MASKED_WRITE(s->cmdreg, mask >> 16, value >> 16);
/* Writing to the upper byte of CMDREG triggers SD command generation */
--
2.1.4

View File

@ -0,0 +1,50 @@
From e3ff618899e53791fdff5dbd3f8fa889a2ed7b1d Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Wed, 1 Feb 2017 09:35:01 +0100
Subject: [PATCH 4/4] cirrus: fix oob access issue (CVE-2017-2615)
When doing bitblt copy in backward mode, we should minus the
blt width first just like the adding in the forward mode. This
can avoid the oob access of the front of vga's vram.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 1485938101-26602-1-git-send-email-kraxel@redhat.com
Message-id: 5887254f.863a240a.2c122.5500@mx.google.com
{ kraxel: with backward blits (negative pitch) addr is the topmost
address, so check it as-is against vram size ]
Cc: qemu-stable@nongnu.org
Cc: P J P <ppandit@redhat.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Wolfgang Bumiller <w.bumiller@proxmox.com>
Fixes: d3532a0db02296e687711b8cdc7791924efccea0 (CVE-2014-8106)
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/cirrus_vga.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 7db6409..16f27e8 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -274,10 +274,9 @@ static bool blit_region_is_unsafe(struct CirrusVGAState *s,
{
if (pitch < 0) {
int64_t min = addr
- + ((int64_t)s->cirrus_blt_height-1) * pitch;
- int32_t max = addr
- + s->cirrus_blt_width;
- if (min < 0 || max > s->vga.vram_size) {
+ + ((int64_t)s->cirrus_blt_height - 1) * pitch
+ - s->cirrus_blt_width;
+ if (min < -1 || addr >= s->vga.vram_size) {
return true;
}
} else {
--
2.1.4

View File

@ -0,0 +1,42 @@
From b9bc05a3a687f9993c5c2a8890b53ab9e8dbc96c Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Tue, 31 Jan 2017 17:54:16 +0530
Subject: [PATCH 4/8] sd: sdhci: block count enable not relevant in single
block transfer
In SDHCI device emulation the 'Block count enable' bit
of the Transfer Mode register is only relevant in multi block
transfers. We need not check it in single block transfers.
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
---
hw/sd/sdhci.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 35f953a..85cac42 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -570,7 +570,6 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
}
/* single block SDMA transfer */
-
static void sdhci_sdma_transfer_single_block(SDHCIState *s)
{
int n;
@@ -589,10 +588,7 @@ static void sdhci_sdma_transfer_single_block(SDHCIState *s)
sdbus_write_data(&s->sdbus, s->fifo_buffer[n]);
}
}
-
- if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
- s->blkcnt--;
- }
+ s->blkcnt--;
sdhci_end_transfer(s);
}
--
2.1.4

View File

@ -0,0 +1,44 @@
From b891912de9c0ef615955fccc043915eb36ce3c02 Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Wed, 14 Dec 2016 12:31:56 +0530
Subject: [PATCH 2/8] display: virtio-gpu-3d: check virgl capabilities max_size
Virtio GPU device while processing 'VIRTIO_GPU_CMD_GET_CAPSET'
command, retrieves the maximum capabilities size to fill in the
response object. It continues to fill in capabilities even if
retrieved 'max_size' is zero(0), thus resulting in OOB access.
Add check to avoid it.
Reported-by: Zhenhao Hong <zhenhaohong@gmail.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Message-id: 20161214070156.23368-1-ppandit@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
Notes:
CVE-2016-10028
hw/display/virtio-gpu-3d.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c
index d98b140..cdd03a4 100644
--- a/hw/display/virtio-gpu-3d.c
+++ b/hw/display/virtio-gpu-3d.c
@@ -371,8 +371,12 @@ static void virgl_cmd_get_capset(VirtIOGPU *g,
virgl_renderer_get_cap_set(gc.capset_id, &max_ver,
&max_size);
- resp = g_malloc0(sizeof(*resp) + max_size);
+ if (!max_size) {
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+ return;
+ }
+ resp = g_malloc0(sizeof(*resp) + max_size);
resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET;
virgl_renderer_fill_caps(gc.capset_id,
gc.capset_version,
--
2.1.4

View File

@ -0,0 +1,50 @@
From a8341ea109259c17ad18b02597e5e03e99db60ae Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Mon, 28 Nov 2016 17:49:04 -0800
Subject: [PATCH 1/8] watchdog: 6300esb: add exit function
When the Intel 6300ESB watchdog is hot unplug. The timer allocated
in realize isn't freed thus leaking memory leak. This patch avoid
this through adding the exit function.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Message-Id: <583cde9c.3223ed0a.7f0c2.886e@mx.google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
Notes:
CVE-2016-10155
hw/watchdog/wdt_i6300esb.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c
index a83d951..49b3cd1 100644
--- a/hw/watchdog/wdt_i6300esb.c
+++ b/hw/watchdog/wdt_i6300esb.c
@@ -428,6 +428,14 @@ static void i6300esb_realize(PCIDevice *dev, Error **errp)
/* qemu_register_coalesced_mmio (addr, 0x10); ? */
}
+static void i6300esb_exit(PCIDevice *dev)
+{
+ I6300State *d = WATCHDOG_I6300ESB_DEVICE(dev);
+
+ timer_del(d->timer);
+ timer_free(d->timer);
+}
+
static WatchdogTimerModel model = {
.wdt_name = "i6300esb",
.wdt_description = "Intel 6300ESB",
@@ -441,6 +449,7 @@ static void i6300esb_class_init(ObjectClass *klass, void *data)
k->config_read = i6300esb_config_read;
k->config_write = i6300esb_config_write;
k->realize = i6300esb_realize;
+ k->exit = i6300esb_exit;
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = PCI_DEVICE_ID_INTEL_ESB_9;
k->class_id = PCI_CLASS_SYSTEM_OTHER;
--
2.1.4

View File

@ -0,0 +1,63 @@
From a8ceb006190b9072b0b9866ec5a07bd6de4eca6d Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Tue, 6 Sep 2016 23:23:17 +0530
Subject: [PATCH 5/6] scsi: pvscsi: avoid infinite loop while building SG list
In PVSCSI paravirtual SCSI bus, pvscsi_convert_sglist can take a very
long time or go into an infinite loop due to two different bugs:
1) the request descriptor data length is defined to be 64 bit. While
building SG list from a request descriptor, it gets truncated to 32bit
in routine 'pvscsi_convert_sglist'. This could lead to an infinite loop
situation for large 'dataLen' values, when data_length is cast to uint32_t
and chunk_size becomes always zero. Fix this by removing the incorrect
cast.
2) pvscsi_get_next_sg_elem can be called arbitrarily many times if the
element has a zero length. Get out of the loop early when this happens,
by introducing an upper limit on the number of SG list elements.
Reported-by: Li Qiang <liqiang6-s@360.cn>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
---
hw/scsi/vmw_pvscsi.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
index 22f872c..e43e0a4 100644
--- a/hw/scsi/vmw_pvscsi.c
+++ b/hw/scsi/vmw_pvscsi.c
@@ -40,6 +40,8 @@
#define PVSCSI_MAX_DEVS (64)
#define PVSCSI_MSIX_NUM_VECTORS (1)
+#define PVSCSI_MAX_SG_ELEM 2048
+
#define PVSCSI_MAX_CMD_DATA_WORDS \
(sizeof(PVSCSICmdDescSetupRings)/sizeof(uint32_t))
@@ -629,17 +631,16 @@ pvscsi_queue_pending_descriptor(PVSCSIState *s, SCSIDevice **d,
static void
pvscsi_convert_sglist(PVSCSIRequest *r)
{
- int chunk_size;
+ uint32_t chunk_size, elmcnt = 0;
uint64_t data_length = r->req.dataLen;
PVSCSISGState sg = r->sg;
- while (data_length) {
- while (!sg.resid) {
+ while (data_length && elmcnt < PVSCSI_MAX_SG_ELEM) {
+ while (!sg.resid && elmcnt++ < PVSCSI_MAX_SG_ELEM) {
pvscsi_get_next_sg_elem(&sg);
trace_pvscsi_convert_sglist(r->req.context, r->sg.dataAddr,
r->sg.resid);
}
- assert(data_length > 0);
- chunk_size = MIN((unsigned) data_length, sg.resid);
+ chunk_size = MIN(data_length, sg.resid);
if (chunk_size) {
qemu_sglist_add(&r->sgl, sg.dataAddr, chunk_size);
}
--
2.1.4

View File

@ -0,0 +1,35 @@
From b5cfb53ba6a976d0d478eb438a5ada3b719e8d59 Mon Sep 17 00:00:00 2001
From: chaojianhu <chaojianhu@hotmail.com>
Date: Tue, 9 Aug 2016 11:52:54 +0800
Subject: [PATCH 2/5] hw/net: Fix a heap overflow in xlnx.xps-ethernetlite
The .receive callback of xlnx.xps-ethernetlite doesn't check the length
of data before calling memcpy. As a result, the NetClientState object in
heap will be overflowed. All versions of qemu with xlnx.xps-ethernetlite
will be affected.
Reported-by: chaojianhu <chaojianhu@hotmail.com>
Signed-off-by: chaojianhu <chaojianhu@hotmail.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
hw/net/xilinx_ethlite.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c
index bc846e7..12b7419 100644
--- a/hw/net/xilinx_ethlite.c
+++ b/hw/net/xilinx_ethlite.c
@@ -197,6 +197,10 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
}
D(qemu_log("%s %zd rxbase=%x\n", __func__, size, rxbase));
+ if (size > (R_MAX - R_RX_BUF0 - rxbase) * 4) {
+ D(qemu_log("ethlite packet is too big, size=%x\n", size));
+ return -1;
+ }
memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size);
s->regs[rxbase + R_RX_CTRL0] |= CTRL_S;
--
2.1.4

View File

@ -0,0 +1,45 @@
From 167d97a3def77ee2dbf6e908b0ecbfe2103977db Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Thu, 8 Sep 2016 18:15:54 +0530
Subject: [PATCH] vmsvga: correct bitmap and pixmap size checks
When processing svga command DEFINE_CURSOR in vmsvga_fifo_run,
the computed BITMAP and PIXMAP size are checked against the
'cursor.mask[]' and 'cursor.image[]' array sizes in bytes.
Correct these checks to avoid OOB memory access.
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Reported-by: Li Qiang <liqiang6-s@360.cn>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Message-id: 1473338754-15430-1-git-send-email-ppandit@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vmware_vga.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index e51a05e..6599cf0 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -676,11 +676,13 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
cursor.bpp = vmsvga_fifo_read(s);
args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp);
- if (cursor.width > 256 ||
- cursor.height > 256 ||
- cursor.bpp > 32 ||
- SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask ||
- SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image) {
+ if (cursor.width > 256
+ || cursor.height > 256
+ || cursor.bpp > 32
+ || SVGA_BITMAP_SIZE(x, y)
+ > sizeof(cursor.mask) / sizeof(cursor.mask[0])
+ || SVGA_PIXMAP_SIZE(x, y, cursor.bpp)
+ > sizeof(cursor.image) / sizeof(cursor.image[0])) {
goto badcmd;
}
--
2.1.4

View File

@ -0,0 +1,38 @@
From 1723b5e7962eb077353bab0772ca8114774b6c60 Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Mon, 19 Sep 2016 23:55:45 +0530
Subject: [PATCH 4/7] virtio: add check for descriptor's mapped address
virtio back end uses set of buffers to facilitate I/O operations.
If its size is too large, 'cpu_physical_memory_map' could return
a null address. This would result in a null dereference while
un-mapping descriptors. Add check to avoid it.
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
hw/virtio/virtio.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 74c085c..eabe573 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -473,6 +473,11 @@ static void virtqueue_map_desc(unsigned int *p_num_sg, hwaddr *addr, struct iove
}
iov[num_sg].iov_base = cpu_physical_memory_map(pa, &len, is_write);
+ if (!iov[num_sg].iov_base) {
+ error_report("virtio: bogus descriptor or out of resources");
+ exit(1);
+ }
+
iov[num_sg].iov_len = len;
addr[num_sg] = pa;
--
2.1.4

View File

@ -0,0 +1,32 @@
From b53dd4495ced2432a0b652ea895e651d07336f7e Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Tue, 13 Sep 2016 03:20:03 -0700
Subject: [PATCH] usb:xhci:fix memory leak in usb_xhci_exit
If the xhci uses msix, it doesn't free the corresponding
memory, thus leading a memory leak. This patch avoid this.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Message-id: 57d7d2e0.d4301c0a.d13e9.9a55@mx.google.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/hcd-xhci.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 37c1493..726435c 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -3715,8 +3715,7 @@ static void usb_xhci_exit(PCIDevice *dev)
/* destroy msix memory region */
if (dev->msix_table && dev->msix_pba
&& dev->msix_entry_used) {
- memory_region_del_subregion(&xhci->mem, &dev->msix_table_mmio);
- memory_region_del_subregion(&xhci->mem, &dev->msix_pba_mmio);
+ msix_uninit(dev, &xhci->mem, &xhci->mem);
}
usb_bus_release(&xhci->bus);
--
2.1.4

View File

@ -0,0 +1,48 @@
From 3798522afcf58abbce6de67446fcae7a34ae919d Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Thu, 22 Sep 2016 16:01:38 +0530
Subject: [PATCH 5/7] net: imx: limit buffer descriptor count
i.MX Fast Ethernet Controller uses buffer descriptors to manage
data flow to/fro receive & transmit queues. While transmitting
packets, it could continue to read buffer descriptors if a buffer
descriptor has length of zero and has crafted values in bd.flags.
Set an upper limit to number of buffer descriptors.
Reported-by: Li Qiang <liqiang6-s@360.cn>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
---
hw/net/imx_fec.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
index 1c415ab..1d74827 100644
--- a/hw/net/imx_fec.c
+++ b/hw/net/imx_fec.c
@@ -220,6 +220,8 @@ static const VMStateDescription vmstate_imx_eth = {
#define PHY_INT_PARFAULT (1 << 2)
#define PHY_INT_AUTONEG_PAGE (1 << 1)
+#define IMX_MAX_DESC 1024
+
static void imx_eth_update(IMXFECState *s);
/*
@@ -402,12 +404,12 @@ static void imx_eth_update(IMXFECState *s)
static void imx_fec_do_tx(IMXFECState *s)
{
- int frame_size = 0;
+ int frame_size = 0, descnt = 0;
uint8_t frame[ENET_MAX_FRAME_SIZE];
uint8_t *ptr = frame;
uint32_t addr = s->tx_descriptor;
- while (1) {
+ while (descnt++ < IMX_MAX_DESC) {
IMXFECBufDesc bd;
int len;
--
2.1.4

View File

@ -0,0 +1,52 @@
From 94087c0cbe014b4a60d96930d7cb43d54a05c701 Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Thu, 22 Sep 2016 16:02:37 +0530
Subject: [PATCH 6/7] net: mcf: limit buffer descriptor count
ColdFire Fast Ethernet Controller uses buffer descriptors to manage
data flow to/fro receive & transmit queues. While transmitting
packets, it could continue to read buffer descriptors if a buffer
descriptor has length of zero and has crafted values in bd.flags.
Set upper limit to number of buffer descriptors.
Reported-by: Li Qiang <liqiang6-s@360.cn>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
hw/net/mcf_fec.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c
index 0ee8ad9..d31fea1 100644
--- a/hw/net/mcf_fec.c
+++ b/hw/net/mcf_fec.c
@@ -23,6 +23,7 @@ do { printf("mcf_fec: " fmt , ## __VA_ARGS__); } while (0)
#define DPRINTF(fmt, ...) do {} while(0)
#endif
+#define FEC_MAX_DESC 1024
#define FEC_MAX_FRAME_SIZE 2032
typedef struct {
@@ -149,7 +150,7 @@ static void mcf_fec_do_tx(mcf_fec_state *s)
uint32_t addr;
mcf_fec_bd bd;
int frame_size;
- int len;
+ int len, descnt = 0;
uint8_t frame[FEC_MAX_FRAME_SIZE];
uint8_t *ptr;
@@ -157,7 +158,7 @@ static void mcf_fec_do_tx(mcf_fec_state *s)
ptr = frame;
frame_size = 0;
addr = s->tx_descriptor;
- while (1) {
+ while (descnt++ < FEC_MAX_DESC) {
mcf_fec_read_bd(&bd, addr);
DPRINTF("tx_bd %x flags %04x len %d data %08x\n",
addr, bd.flags, bd.length, bd.data);
--
2.1.4

View File

@ -0,0 +1,36 @@
From ed825b783750cbe88aa67bbe83cf662082828efa Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Fri, 30 Sep 2016 00:27:33 +0530
Subject: [PATCH 7/7] net: pcnet: check rx/tx descriptor ring length
The AMD PC-Net II emulator has set of control and status(CSR)
registers. Of these, CSR76 and CSR78 hold receive and transmit
descriptor ring length respectively. This ring length could range
from 1 to 65535. Setting ring length to zero leads to an infinite
loop in pcnet_rdra_addr. Add check to avoid it.
Reported-by: Li Qiang <liqiang6-s@360.cn>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
---
hw/net/pcnet.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c
index 198a01f..3078de8 100644
--- a/hw/net/pcnet.c
+++ b/hw/net/pcnet.c
@@ -1429,8 +1429,11 @@ static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value)
case 47: /* POLLINT */
case 72:
case 74:
+ break;
case 76: /* RCVRL */
case 78: /* XMTRL */
+ val = (val > 0) ? val : 512;
+ break;
case 112:
if (CSR_STOP(s) || CSR_SPND(s))
break;
--
2.1.4

View File

@ -0,0 +1,30 @@
From 594fa98211f92ab07ee6d6b6a9eda93a416a1f57 Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Sun, 18 Sep 2016 19:07:11 -0700
Subject: [PATCH 1/2] virtio-gpu: fix memory leak in
virtio_gpu_resource_create_2d
In virtio gpu resource create dispatch, if the pixman format is zero
it doesn't free the resource object allocated previously. Thus leading
a host memory leak issue. This patch avoid this.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
---
hw/display/virtio-gpu.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 7fe6ed8..5b6d17b 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -333,6 +333,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
qemu_log_mask(LOG_GUEST_ERROR,
"%s: host couldn't handle guest format %d\n",
__func__, c2d.format);
+ g_free(res);
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
return;
}
--
2.1.4

View File

@ -0,0 +1,32 @@
From 91a16e6e51a4e046d59379fc83b9dfc1e860e9c7 Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Sat, 8 Oct 2016 11:58:03 +0300
Subject: [PATCH 2/2] usb: ehci: fix memory leak in ehci_process_itd
While processing isochronous transfer descriptors(iTD), if the page
select(PG) field value is out of bands it will return. In this
situation the ehci's sg list is not freed thus leading to a memory
leak issue. This patch avoid this.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
---
hw/usb/hcd-ehci.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index b093db7..f4ece9a 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1426,6 +1426,7 @@ static int ehci_process_itd(EHCIState *ehci,
if (off + len > 4096) {
/* transfer crosses page border */
if (pg == 6) {
+ qemu_sglist_destroy(&ehci->isgl);
return -1; /* avoid page pg + 1 */
}
ptr2 = (itd->bufptr[pg + 1] & ITD_BUFPTR_MASK);
--
2.1.4

View File

@ -0,0 +1,69 @@
From b5ef1754de94247de307044b19e6bc3fa0ad5ba8 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Mon, 10 Oct 2016 12:46:22 +0200
Subject: [PATCH 2/4] xhci: limit the number of link trbs we are willing to
process
Needed to avoid we run in circles forever in case the guest builds
an endless loop with link trbs.
Reported-by: Li Qiang <liqiang6-s@360.cn>
Tested-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 1476096382-7981-1-git-send-email-kraxel@redhat.com
---
hw/usb/hcd-xhci.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 281a2a5..8a9a31a 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -54,6 +54,8 @@
* to the specs when it gets them */
#define ER_FULL_HACK
+#define TRB_LINK_LIMIT 4
+
#define LEN_CAP 0x40
#define LEN_OPER (0x400 + 0x10 * MAXPORTS)
#define LEN_RUNTIME ((MAXINTRS + 1) * 0x20)
@@ -1000,6 +1002,7 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
dma_addr_t *addr)
{
PCIDevice *pci_dev = PCI_DEVICE(xhci);
+ uint32_t link_cnt = 0;
while (1) {
TRBType type;
@@ -1026,6 +1029,9 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
ring->dequeue += TRB_SIZE;
return type;
} else {
+ if (++link_cnt > TRB_LINK_LIMIT) {
+ return 0;
+ }
ring->dequeue = xhci_mask64(trb->parameter);
if (trb->control & TRB_LK_TC) {
ring->ccs = !ring->ccs;
@@ -1043,6 +1049,7 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
bool ccs = ring->ccs;
/* hack to bundle together the two/three TDs that make a setup transfer */
bool control_td_set = 0;
+ uint32_t link_cnt = 0;
while (1) {
TRBType type;
@@ -1058,6 +1065,9 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
type = TRB_TYPE(trb);
if (type == TR_LINK) {
+ if (++link_cnt > TRB_LINK_LIMIT) {
+ return -length;
+ }
dequeue = xhci_mask64(trb.parameter);
if (trb.control & TRB_LK_TC) {
ccs = !ccs;
--
2.1.4

View File

@ -0,0 +1,39 @@
From 8794fc68736fda80d7191f100c03c960a5ef1224 Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Tue, 11 Oct 2016 09:27:45 +0200
Subject: [PATCH 3/4] 9pfs: fix potential host memory leak in v9fs_read
In 9pfs read dispatch function, it doesn't free two QEMUIOVector
object thus causing potential memory leak. This patch avoid this.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Signed-off-by: Greg Kurz <groug@kaod.org>
---
hw/9pfs/9p.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index dfe293d..54e18a2 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -1812,14 +1812,15 @@ static void v9fs_read(void *opaque)
if (len < 0) {
/* IO error return the error */
err = len;
- goto out;
+ goto out_free_iovec;
}
} while (count < max_count && len > 0);
err = pdu_marshal(pdu, offset, "d", count);
if (err < 0) {
- goto out;
+ goto out_free_iovec;
}
err += offset + count;
+out_free_iovec:
qemu_iovec_destroy(&qiov);
qemu_iovec_destroy(&qiov_full);
} else if (fidp->fid_type == P9_FID_XATTR) {
--
2.1.4

View File

@ -0,0 +1,58 @@
From 630abd0c70f272b36361348e9ee7d6a71577b72f Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Tue, 11 Oct 2016 09:27:45 +0200
Subject: [PATCH 4/4] 9pfs: allocate space for guest originated empty strings
If a guest sends an empty string paramater to any 9P operation, the current
code unmarshals it into a V9fsString equal to { .size = 0, .data = NULL }.
This is unfortunate because it can cause NULL pointer dereference to happen
at various locations in the 9pfs code. And we don't want to check str->data
everywhere we pass it to strcmp() or any other function which expects a
dereferenceable pointer.
This patch enforces the allocation of genuine C empty strings instead, so
callers don't have to bother.
Out of all v9fs_iov_vunmarshal() users, only v9fs_xattrwalk() checks if
the returned string is empty. It now uses v9fs_string_size() since
name.data cannot be NULL anymore.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
[groug, rewritten title and changelog,
fix empty string check in v9fs_xattrwalk()]
Signed-off-by: Greg Kurz <groug@kaod.org>
---
fsdev/9p-iov-marshal.c | 2 +-
hw/9pfs/9p.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/fsdev/9p-iov-marshal.c b/fsdev/9p-iov-marshal.c
index 663cad5..1d16f8d 100644
--- a/fsdev/9p-iov-marshal.c
+++ b/fsdev/9p-iov-marshal.c
@@ -125,7 +125,7 @@ ssize_t v9fs_iov_vunmarshal(struct iovec *out_sg, int out_num, size_t offset,
str->data = g_malloc(str->size + 1);
copied = v9fs_unpack(str->data, out_sg, out_num, offset,
str->size);
- if (copied > 0) {
+ if (copied >= 0) {
str->data[str->size] = 0;
} else {
v9fs_string_free(str);
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 54e18a2..75ba5f1 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -3161,7 +3161,7 @@ static void v9fs_xattrwalk(void *opaque)
goto out;
}
v9fs_path_copy(&xattr_fidp->path, &file_fidp->path);
- if (name.data == NULL) {
+ if (!v9fs_string_size(&name)) {
/*
* listxattr request. Get the size first
*/
--
2.1.4

View File

@ -0,0 +1,34 @@
From 0d3ac427e34f12b1a33646d47ef3dc390a9b569d Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Wed, 12 Oct 2016 14:40:55 +0530
Subject: [PATCH 1/2] net: rocker: set limit to DMA buffer size
Rocker network switch emulator has test registers to help debug
DMA operations. While testing host DMA access, a buffer address
is written to register 'TEST_DMA_ADDR' and its size is written to
register 'TEST_DMA_SIZE'. When performing TEST_DMA_CTRL_INVERT
test, if DMA buffer size was greater than 'INT_MAX', it leads to
an invalid buffer access. Limit the DMA buffer size to avoid it.
Reported-by: Huawei PSIRT <psirt@huawei.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
---
hw/net/rocker/rocker.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c
index 30f2ce4..e9d215a 100644
--- a/hw/net/rocker/rocker.c
+++ b/hw/net/rocker/rocker.c
@@ -860,7 +860,7 @@ static void rocker_io_writel(void *opaque, hwaddr addr, uint32_t val)
rocker_msix_irq(r, val);
break;
case ROCKER_TEST_DMA_SIZE:
- r->test_dma_size = val;
+ r->test_dma_size = val & 0xFFFF;
break;
case ROCKER_TEST_DMA_ADDR + 4:
r->test_dma_addr = ((uint64_t)val) << 32 | r->lower32;
--
2.1.4

View File

@ -0,0 +1,35 @@
From 7e0ebfd13e55a706396197437f375692bbf75d15 Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Wed, 12 Oct 2016 11:28:08 +0530
Subject: [PATCH 2/2] char: serial: check divider value against baud base
16550A UART device uses an oscillator to generate frequencies
(baud base), which decide communication speed. This speed could
be changed by dividing it by a divider. If the divider is
greater than the baud base, speed is set to zero, leading to a
divide by zero error. Add check to avoid it.
Reported-by: Huawei PSIRT <psirt@huawei.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
---
hw/char/serial.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/hw/char/serial.c b/hw/char/serial.c
index 3442f47..eec72b7 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -153,8 +153,9 @@ static void serial_update_parameters(SerialState *s)
int speed, parity, data_bits, stop_bits, frame_size;
QEMUSerialSetParams ssp;
- if (s->divider == 0)
+ if (s->divider == 0 || s->divider > s->baudbase) {
return;
+ }
/* Start bit. */
frame_size = 1;
--
2.1.4

View File

@ -0,0 +1,39 @@
From ad0e6e88e0432aa1e6c75f52a6b3b4bf463e2563 Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Thu, 20 Oct 2016 13:10:24 +0530
Subject: [PATCH 1/8] audio: intel-hda: check stream entry count during
transfer
Intel HDA emulator uses stream of buffers during DMA data
transfers. Each entry has buffer length and buffer pointer
position, which are used to derive bytes to 'copy'. If this
length and buffer pointer were to be same, 'copy' could be
set to zero(0), leading to an infinite loop. Add check to
avoid it.
Reported-by: Huawei PSIRT <psirt@huawei.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: 1476949224-6865-1-git-send-email-ppandit@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/audio/intel-hda.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
index cd95340..537face 100644
--- a/hw/audio/intel-hda.c
+++ b/hw/audio/intel-hda.c
@@ -416,7 +416,8 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
}
left = len;
- while (left > 0) {
+ s = st->bentries;
+ while (left > 0 && s-- > 0) {
copy = left;
if (copy > st->bsize - st->lpib)
copy = st->bsize - st->lpib;
--
2.1.4

View File

@ -0,0 +1,30 @@
From 1fab838b55ee7cc199b105d80de4a80f336231b3 Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Sat, 8 Oct 2016 05:07:25 -0700
Subject: [PATCH 3/8] net: eepro100: fix memory leak in device uninit
The exit dispatch of eepro100 network card device doesn't free
the 's->vmstate' field which was allocated in device realize thus
leading a host memory leak. This patch avoid this.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
hw/net/eepro100.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c
index bab4dbf..4bf71f2 100644
--- a/hw/net/eepro100.c
+++ b/hw/net/eepro100.c
@@ -1843,6 +1843,7 @@ static void pci_nic_uninit(PCIDevice *pci_dev)
EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
vmstate_unregister(&pci_dev->qdev, s->vmstate, s);
+ g_free(s->vmstate);
eeprom93xx_free(&pci_dev->qdev, s->eeprom);
qemu_del_nic(s->nic);
}
--
2.1.4

View File

@ -0,0 +1,34 @@
From f132108afabf074403afadf822ad2d2275d115cd Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Mon, 17 Oct 2016 14:13:58 +0200
Subject: [PATCH 5/8] 9pfs: fix memory leak in v9fs_xattrcreate
The 'fs.xattr.value' field in V9fsFidState object doesn't consider the
situation that this field has been allocated previously. Every time, it
will be allocated directly. This leads to a host memory leak issue if
the client sends another Txattrcreate message with the same fid number
before the fid from the previous time got clunked.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Reviewed-by: Greg Kurz <groug@kaod.org>
[groug, updated the changelog to indicate how the leak can occur]
Signed-off-by: Greg Kurz <groug@kaod.org>
---
hw/9pfs/9p.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 3becdd0..f5af4e3 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -3269,6 +3269,7 @@ static void v9fs_xattrcreate(void *opaque)
xattr_fidp->fs.xattr.flags = flags;
v9fs_string_init(&xattr_fidp->fs.xattr.name);
v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
+ g_free(xattr_fidp->fs.xattr.value);
xattr_fidp->fs.xattr.value = g_malloc0(size);
err = offset;
put_fid(pdu, file_fidp);
--
2.1.4

View File

@ -0,0 +1,32 @@
From 644566ea6fe2896b6b171797cfe6e7219939d968 Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Mon, 17 Oct 2016 14:13:58 +0200
Subject: [PATCH 4/8] 9pfs: fix information leak in xattr read
9pfs uses g_malloc() to allocate the xattr memory space, if the guest
reads this memory before writing to it, this will leak host heap memory
to the guest. This patch avoid this.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Reviewed-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Greg Kurz <groug@kaod.org>
---
hw/9pfs/9p.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 75ba5f1..3becdd0 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -3269,7 +3269,7 @@ static void v9fs_xattrcreate(void *opaque)
xattr_fidp->fs.xattr.flags = flags;
v9fs_string_init(&xattr_fidp->fs.xattr.name);
v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
- xattr_fidp->fs.xattr.value = g_malloc(size);
+ xattr_fidp->fs.xattr.value = g_malloc0(size);
err = offset;
put_fid(pdu, file_fidp);
out_nofid:
--
2.1.4

View File

@ -0,0 +1,92 @@
From 86a37b0a0ed8f32db819782ca4a367712ece1453 Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Tue, 1 Nov 2016 12:00:40 +0100
Subject: [PATCH 8/8] 9pfs: fix integer overflow issue in xattr read/write
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The v9fs_xattr_read() and v9fs_xattr_write() are passed a guest
originated offset: they must ensure this offset does not go beyond
the size of the extended attribute that was set in v9fs_xattrcreate().
Unfortunately, the current code implement these checks with unsafe
calculations on 32 and 64 bit values, which may allow a malicious
guest to cause OOB access anyway.
Fix this by comparing the offset and the xattr size, which are
both uint64_t, before trying to compute the effective number of bytes
to read or write.
Suggested-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Reviewed-by: Greg Kurz <groug@kaod.org>
Reviewed-By: Guido Günther <agx@sigxcpu.org>
Signed-off-by: Greg Kurz <groug@kaod.org>
---
hw/9pfs/9p.c | 32 ++++++++++++--------------------
1 file changed, 12 insertions(+), 20 deletions(-)
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index af07846..fc4f2cd 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -1628,20 +1628,17 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
{
ssize_t err;
size_t offset = 7;
- int read_count;
- int64_t xattr_len;
+ uint64_t read_count;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
VirtQueueElement *elem = v->elems[pdu->idx];
- xattr_len = fidp->fs.xattr.len;
- read_count = xattr_len - off;
+ if (fidp->fs.xattr.len < off) {
+ read_count = 0;
+ } else {
+ read_count = fidp->fs.xattr.len - off;
+ }
if (read_count > max_count) {
read_count = max_count;
- } else if (read_count < 0) {
- /*
- * read beyond XATTR value
- */
- read_count = 0;
}
err = pdu_marshal(pdu, offset, "d", read_count);
if (err < 0) {
@@ -1969,23 +1966,18 @@ static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
{
int i, to_copy;
ssize_t err = 0;
- int write_count;
- int64_t xattr_len;
+ uint64_t write_count;
size_t offset = 7;
- xattr_len = fidp->fs.xattr.len;
- write_count = xattr_len - off;
- if (write_count > count) {
- write_count = count;
- } else if (write_count < 0) {
- /*
- * write beyond XATTR value len specified in
- * xattrcreate
- */
+ if (fidp->fs.xattr.len < off) {
err = -ENOSPC;
goto out;
}
+ write_count = fidp->fs.xattr.len - off;
+ if (write_count > count) {
+ write_count = count;
+ }
err = pdu_marshal(pdu, offset, "d", write_count);
if (err < 0) {
return err;
--
2.1.4

View File

@ -0,0 +1,32 @@
From 94979ec1a852871eaee150cb56f0e8cac4316e35 Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Mon, 17 Oct 2016 14:13:58 +0200
Subject: [PATCH 6/8] 9pfs: fix memory leak in v9fs_link
The v9fs_link() function keeps a reference on the source fid object. This
causes a memory leak since the reference never goes down to 0. This patch
fixes the issue.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Reviewed-by: Greg Kurz <groug@kaod.org>
[groug, rephrased the changelog]
Signed-off-by: Greg Kurz <groug@kaod.org>
---
hw/9pfs/9p.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index f5af4e3..aa2b8c0 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -2403,6 +2403,7 @@ static void v9fs_link(void *opaque)
if (!err) {
err = offset;
}
+ put_fid(pdu, oldfidp);
out:
put_fid(pdu, dfidp);
out_nofid:
--
2.1.4

View File

@ -0,0 +1,33 @@
From 2c5bcb2d5f32ffcf5064d3557e44836fa70700be Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Mon, 17 Oct 2016 14:13:58 +0200
Subject: [PATCH 7/8] 9pfs: fix memory leak in v9fs_write
If an error occurs when marshalling the transfer length to the guest, the
v9fs_write() function doesn't free an IO vector, thus leading to a memory
leak. This patch fixes the issue.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Reviewed-by: Greg Kurz <groug@kaod.org>
[groug, rephrased the changelog]
Signed-off-by: Greg Kurz <groug@kaod.org>
---
hw/9pfs/9p.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index aa2b8c0..af07846 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -2080,7 +2080,7 @@ static void v9fs_write(void *opaque)
offset = 7;
err = pdu_marshal(pdu, offset, "d", total);
if (err < 0) {
- goto out;
+ goto out_qiov;
}
err += offset;
trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
--
2.1.4

View File

@ -0,0 +1,34 @@
From 2a4848046ad64db5cb1c1090565a28a5cb2c518e Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Tue, 29 Nov 2016 00:38:39 +0530
Subject: [PATCH 01/12] net: mcf: check receive buffer size register value
ColdFire Fast Ethernet Controller uses a receive buffer size
register(EMRBR) to hold maximum size of all receive buffers.
It is set by a user before any operation. If it was set to be
zero, ColdFire emulator would go into an infinite loop while
receiving data in mcf_fec_receive. Add check to avoid it.
Reported-by: Wjjzhang <wjjzhang@tencent.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
hw/net/mcf_fec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c
index d31fea1..3d4b3b3 100644
--- a/hw/net/mcf_fec.c
+++ b/hw/net/mcf_fec.c
@@ -393,7 +393,7 @@ static void mcf_fec_write(void *opaque, hwaddr addr,
s->tx_descriptor = s->etdsr;
break;
case 0x188:
- s->emrbr = value & 0x7f0;
+ s->emrbr = value > 0 ? value & 0x7F0 : 0x7F0;
break;
default:
hw_error("mcf_fec_write Bad address 0x%x\n", (int)addr);
--
2.1.4

View File

@ -0,0 +1,37 @@
From 71ee39ea06cbcbd1971213aa1f3a9036c50b6a57 Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Tue, 1 Nov 2016 02:53:11 -0700
Subject: [PATCH 02/12] virtio-gpu: fix information leak in getting capset info
dispatch
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In virgl_cmd_get_capset_info dispatch function, the 'resp' hasn't
been full initialized before writing to the guest. This will leak
the 'resp.padding' and 'resp.hdr.padding' fieds to the guest. This
patch fix this issue.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Message-id: 5818661e.0860240a.77264.7a56@mx.google.com
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/virtio-gpu-3d.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c
index 758d33a..23f39de 100644
--- a/hw/display/virtio-gpu-3d.c
+++ b/hw/display/virtio-gpu-3d.c
@@ -347,6 +347,7 @@ static void virgl_cmd_get_capset_info(VirtIOGPU *g,
VIRTIO_GPU_FILL_CMD(info);
+ memset(&resp, 0, sizeof(resp));
if (info.capset_index == 0) {
resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL;
virgl_renderer_get_cap_set(resp.capset_id,
--
2.1.4

View File

@ -0,0 +1,36 @@
From 74a46afa58632277063ca4990cf0c954f342dd7d Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Tue, 1 Nov 2016 04:06:58 -0700
Subject: [PATCH 03/12] virtio-gpu: fix memory leak in update_cursor_data_virgl
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In update_cursor_data_virgl function, if the 'width'/ 'height'
is not equal to current cursor's width/height it will return
without free the 'data' allocated previously. This will lead
a memory leak issue. This patch fix this issue.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Message-id: 58187760.41d71c0a.cca75.4cb9@mx.google.com
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/virtio-gpu.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 5b6d17b..41f8096 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -84,6 +84,7 @@ static void update_cursor_data_virgl(VirtIOGPU *g,
if (width != s->current_cursor->width ||
height != s->current_cursor->height) {
+ free(data);
return;
}
--
2.1.4

View File

@ -0,0 +1,54 @@
From 5bbb994dd062eb3950d67db3c6189dab0df7ec9b Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Mon, 7 Nov 2016 21:57:46 -0800
Subject: [PATCH 04/12] usbredir: free vm_change_state_handler in usbredir
destroy dispatch
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In usbredir destroy dispatch function, it doesn't free the vm change
state handler once registered in usbredir_realize function. This will
lead a memory leak issue. This patch avoid this.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-id: 58216976.d0236b0a.77b99.bcd6@mx.google.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/redirect.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 444672a..42aeaa4 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -132,6 +132,7 @@ struct USBRedirDevice {
struct usbredirfilter_rule *filter_rules;
int filter_rules_count;
int compatible_speedmask;
+ VMChangeStateEntry *vmstate;
};
#define TYPE_USB_REDIR "usb-redir"
@@ -1409,7 +1410,8 @@ static void usbredir_realize(USBDevice *udev, Error **errp)
qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read,
usbredir_chardev_read, usbredir_chardev_event, dev);
- qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);
+ dev->vmstate =
+ qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);
}
static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
@@ -1446,6 +1448,7 @@ static void usbredir_handle_destroy(USBDevice *udev)
}
free(dev->filter_rules);
+ qemu_del_vm_change_state_handler(dev->vmstate);
}
static int usbredir_check_filter(USBRedirDevice *dev)
--
2.1.4

View File

@ -0,0 +1,31 @@
From bde803ceb42d6bddc06a1881c00acdf203214772 Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Tue, 1 Nov 2016 05:37:57 -0700
Subject: [PATCH 10/12] virtio-gpu: fix information leak in capset get dispatch
In virgl_cmd_get_capset function, it uses g_malloc to allocate
a response struct to the guest. As the 'resp'struct hasn't been full
initialized it will lead the 'resp->padding' field to the guest.
Use g_malloc0 to avoid this.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
---
hw/display/virtio-gpu-3d.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c
index 23f39de..d98b140 100644
--- a/hw/display/virtio-gpu-3d.c
+++ b/hw/display/virtio-gpu-3d.c
@@ -371,7 +371,7 @@ static void virgl_cmd_get_capset(VirtIOGPU *g,
virgl_renderer_get_cap_set(gc.capset_id, &max_ver,
&max_size);
- resp = g_malloc(sizeof(*resp) + max_size);
+ resp = g_malloc0(sizeof(*resp) + max_size);
resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET;
virgl_renderer_fill_caps(gc.capset_id,
--
2.1.4

View File

@ -0,0 +1,31 @@
From 824f78bb0135cff4cb29e26c3de1cb4c2da35b46 Mon Sep 17 00:00:00 2001
From: Li Qiang <liqiang6-s@360.cn>
Date: Tue, 8 Nov 2016 04:11:10 -0800
Subject: [PATCH 05/12] usb: ehci: fix memory leak in ehci_init_transfer
In ehci_init_transfer function, if the 'cpage' is bigger than 4,
it doesn't free the 'p->sgl' once allocated previously thus leading
a memory leak issue. This patch avoid this.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
Message-id: 5821c0f4.091c6b0a.e0c92.e811@mx.google.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/hcd-ehci.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index f4ece9a..7622a3a 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1190,6 +1190,7 @@ static int ehci_init_transfer(EHCIPacket *p)
while (bytes > 0) {
if (cpage > 4) {
fprintf(stderr, "cpage out of range (%d)\n", cpage);
+ qemu_sglist_destroy(&p->sgl);
return -1;
}
--
2.1.4

View File

@ -0,0 +1,39 @@
From efc44f269fe72bab2c496f21809f6bef20d9c398 Mon Sep 17 00:00:00 2001
From: Li Qiang <liq3ea@gmail.com>
Date: Mon, 28 Nov 2016 21:29:25 -0500
Subject: [PATCH 11/12] virtio-gpu: call cleanup mapping function in resource
destroy
If the guest destroy the resource before detach banking, the 'iov'
and 'addrs' field in resource is not freed thus leading memory
leak issue. This patch avoid this.
Signed-off-by: Li Qiang <liq3ea@gmail.com>
---
hw/display/virtio-gpu.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 41f8096..8903dee 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -28,6 +28,8 @@
static struct virtio_gpu_simple_resource*
virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
+static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res);
+
#ifdef CONFIG_VIRGL
#include <virglrenderer.h>
#define VIRGL(_g, _virgl, _simple, ...) \
@@ -359,6 +361,7 @@ static void virtio_gpu_resource_destroy(VirtIOGPU *g,
struct virtio_gpu_simple_resource *res)
{
pixman_image_unref(res->image);
+ virtio_gpu_cleanup_mapping(res);
QTAILQ_REMOVE(&g->reslist, res, next);
g_free(res);
}
--
2.1.4

View File

@ -0,0 +1,43 @@
From 9be364d4b3bc173103bec0dc76259f40d232eb88 Mon Sep 17 00:00:00 2001
From: Li Qiang <liq3ea@gmail.com>
Date: Wed, 23 Nov 2016 13:53:34 +0100
Subject: [PATCH 06/12] 9pfs: adjust the order of resource cleanup in device
unrealize
Unrealize should undo things that were set during realize in
reverse order. So should do in the error path in realize.
Signed-off-by: Li Qiang <liq3ea@gmail.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Greg Kurz <groug@kaod.org>
---
hw/9pfs/9p.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index fc4f2cd..ced7b4c 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -3490,8 +3490,8 @@ int v9fs_device_realize_common(V9fsState *s, Error **errp)
rc = 0;
out:
if (rc) {
- g_free(s->ctx.fs_root);
g_free(s->tag);
+ g_free(s->ctx.fs_root);
v9fs_path_free(&path);
}
return rc;
@@ -3499,8 +3499,8 @@ out:
void v9fs_device_unrealize_common(V9fsState *s, Error **errp)
{
- g_free(s->ctx.fs_root);
g_free(s->tag);
+ g_free(s->ctx.fs_root);
}
static void __attribute__((__constructor__)) v9fs_set_fd_limit(void)
--
2.1.4

View File

@ -0,0 +1,56 @@
From f2ef9ae2a512fca1df0d56c226adc24ddf002b8b Mon Sep 17 00:00:00 2001
From: Li Qiang <liq3ea@gmail.com>
Date: Wed, 23 Nov 2016 13:53:34 +0100
Subject: [PATCH 07/12] 9pfs: add cleanup operation in FileOperations
Currently, the backend of VirtFS doesn't have a cleanup
function. This will lead resource leak issues if the backed
driver allocates resources. This patch addresses this issue.
Signed-off-by: Li Qiang <liq3ea@gmail.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Greg Kurz <groug@kaod.org>
---
fsdev/file-op-9p.h | 1 +
hw/9pfs/9p.c | 6 ++++++
2 files changed, 7 insertions(+)
diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 6db9fea..a56dc84 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -100,6 +100,7 @@ struct FileOperations
{
int (*parse_opts)(QemuOpts *, struct FsDriverEntry *);
int (*init)(struct FsContext *);
+ void (*cleanup)(struct FsContext *);
int (*lstat)(FsContext *, V9fsPath *, struct stat *);
ssize_t (*readlink)(FsContext *, V9fsPath *, char *, size_t);
int (*chmod)(FsContext *, V9fsPath *, FsCred *);
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index ced7b4c..f2a90d4 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -3490,6 +3490,9 @@ int v9fs_device_realize_common(V9fsState *s, Error **errp)
rc = 0;
out:
if (rc) {
+ if (s->ops->cleanup && s->ctx.private) {
+ s->ops->cleanup(&s->ctx);
+ }
g_free(s->tag);
g_free(s->ctx.fs_root);
v9fs_path_free(&path);
@@ -3499,6 +3502,9 @@ out:
void v9fs_device_unrealize_common(V9fsState *s, Error **errp)
{
+ if (s->ops->cleanup) {
+ s->ops->cleanup(&s->ctx);
+ }
g_free(s->tag);
g_free(s->ctx.fs_root);
}
--
2.1.4

View File

@ -0,0 +1,47 @@
From 4196726e44c437793294af15d95e53164cf9a02d Mon Sep 17 00:00:00 2001
From: Li Qiang <liq3ea@gmail.com>
Date: Wed, 23 Nov 2016 13:53:34 +0100
Subject: [PATCH 08/12] 9pfs: add cleanup operation for handle backend driver
In the init operation of handle backend dirver, it allocates a
handle_data struct and opens a mount file. We should free these
resources when the 9pfs device is unrealized. This is what this
patch does.
Signed-off-by: Li Qiang <liq3ea@gmail.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Greg Kurz <groug@kaod.org>
---
hw/9pfs/9p-handle.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c
index 3d77594..1687661 100644
--- a/hw/9pfs/9p-handle.c
+++ b/hw/9pfs/9p-handle.c
@@ -649,6 +649,14 @@ out:
return ret;
}
+static void handle_cleanup(FsContext *ctx)
+{
+ struct handle_data *data = ctx->private;
+
+ close(data->mountfd);
+ g_free(data);
+}
+
static int handle_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
{
const char *sec_model = qemu_opt_get(opts, "security_model");
@@ -671,6 +679,7 @@ static int handle_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
FileOperations handle_ops = {
.parse_opts = handle_parse_opts,
.init = handle_init,
+ .cleanup = handle_cleanup,
.lstat = handle_lstat,
.readlink = handle_readlink,
.close = handle_close,
--
2.1.4

View File

@ -0,0 +1,47 @@
From ae9b5c9dae96dd8d3bdf9bb6b9a0f7a2d6f532f7 Mon Sep 17 00:00:00 2001
From: Li Qiang <liq3ea@gmail.com>
Date: Wed, 23 Nov 2016 13:53:34 +0100
Subject: [PATCH 09/12] 9pfs: add cleanup operation for proxy backend driver
In the init operation of proxy backend dirver, it allocates a
V9fsProxy struct and some other resources. We should free these
resources when the 9pfs device is unrealized. This is what this
patch does.
Signed-off-by: Li Qiang <liq3ea@gmail.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Greg Kurz <groug@kaod.org>
---
hw/9pfs/9p-proxy.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c
index f265501..336e9fe 100644
--- a/hw/9pfs/9p-proxy.c
+++ b/hw/9pfs/9p-proxy.c
@@ -1179,9 +1179,22 @@ static int proxy_init(FsContext *ctx)
return 0;
}
+static void proxy_cleanup(FsContext *ctx)
+{
+ V9fsProxy *proxy = ctx->private;
+
+ g_free(proxy->out_iovec.iov_base);
+ g_free(proxy->in_iovec.iov_base);
+ if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
+ close(proxy->sockfd);
+ }
+ g_free(proxy);
+}
+
FileOperations proxy_ops = {
.parse_opts = proxy_parse_opts,
.init = proxy_init,
+ .cleanup = proxy_cleanup,
.lstat = proxy_lstat,
.readlink = proxy_readlink,
.close = proxy_close,
--
2.1.4

View File

@ -0,0 +1,81 @@
From 9ec3cbedab41f93d2fbf742f2ca6705c2d68c3e1 Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Tue, 18 Oct 2016 13:15:17 +0530
Subject: [PATCH 12/12] display: cirrus: check vga bits per pixel(bpp) value
In Cirrus CLGD 54xx VGA Emulator, if cirrus graphics mode is VGA,
'cirrus_get_bpp' returns zero(0), which could lead to a divide
by zero error in while copying pixel data. The same could occur
via blit pitch values. Add check to avoid it.
Reported-by: Huawei PSIRT <psirt@huawei.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Message-id: 1476776717-24807-1-git-send-email-ppandit@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
Notes:
CVE-2016-9921
CVE-2016-9922
hw/display/cirrus_vga.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 3d712d5..bdb092e 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -272,6 +272,9 @@ static void cirrus_update_memory_access(CirrusVGAState *s);
static bool blit_region_is_unsafe(struct CirrusVGAState *s,
int32_t pitch, int32_t addr)
{
+ if (!pitch) {
+ return true;
+ }
if (pitch < 0) {
int64_t min = addr
+ ((int64_t)s->cirrus_blt_height-1) * pitch;
@@ -715,7 +718,7 @@ static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
s->cirrus_addr_mask));
}
-static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
+static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
{
int sx = 0, sy = 0;
int dx = 0, dy = 0;
@@ -729,6 +732,9 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
int width, height;
depth = s->vga.get_bpp(&s->vga) / 8;
+ if (!depth) {
+ return 0;
+ }
s->vga.get_resolution(&s->vga, &width, &height);
/* extra x, y */
@@ -783,6 +789,8 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
s->cirrus_blt_dstpitch, s->cirrus_blt_width,
s->cirrus_blt_height);
+
+ return 1;
}
static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
@@ -790,11 +798,9 @@ static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
if (blit_is_unsafe(s))
return 0;
- cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
+ return cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
s->cirrus_blt_srcaddr - s->vga.start_addr,
s->cirrus_blt_width, s->cirrus_blt_height);
-
- return 1;
}
/***************************************
--
2.1.4

View File

@ -0,0 +1,52 @@
From d775c497a84a5c4be3f15cca85ca8440dd5880a0 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 22 Feb 2017 13:42:31 +0100
Subject: [PATCH qemu] cirrus: add blit_is_unsafe call to
cirrus_bitblt_cputovideo (CVE-2017-2620)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
CIRRUS_BLTMODE_MEMSYSSRC blits do NOT check blit destination
and blit width, at all. Oops. Fix it.
Security impact: high.
The missing blit destination check allows to write to host memory.
Basically same as CVE-2014-8106 for the other blit variants.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 1487679663-3264-1-git-send-email-kraxel@redhat.com
---
hw/display/cirrus_vga.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 1deb520..b9e7cb1 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -900,6 +900,10 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
{
int w;
+ if (blit_is_unsafe(s, true)) {
+ return 0;
+ }
+
s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC;
s->cirrus_srcptr = &s->cirrus_bltbuf[0];
s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
@@ -925,6 +929,10 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
}
s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
}
+
+ /* the blit_is_unsafe call above should catch this */
+ assert(s->cirrus_blt_srcpitch <= CIRRUS_BLTBUFSIZE);
+
s->cirrus_srcptr = s->cirrus_bltbuf;
s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
cirrus_update_memory_access(s);
--
2.1.4

View File

@ -0,0 +1,133 @@
From 385c66564aad5fbbe303e0d2ee5e8ffd9c10bc23 Mon Sep 17 00:00:00 2001
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
Date: Mon, 12 Sep 2016 18:18:35 +0100
Subject: [PATCH 04/36] x86/lapic: Load LAPIC state at post_load
Load the LAPIC state during post_load (rather than when the CPU
starts).
This allows an interrupt to be delivered from the ioapic to
the lapic prior to cpu loading, in particular the RTC that starts
ticking as soon as we load it's state.
Fixes a case where Windows hangs after migration due to RTC interrupts
disappearing.
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/i386/kvm/apic.c | 26 ++++++++++++++++++++++++--
include/sysemu/kvm.h | 1 -
target-i386/kvm.c | 17 -----------------
3 files changed, 24 insertions(+), 20 deletions(-)
diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c
index 2bd0de8..feb0002 100644
--- a/hw/i386/kvm/apic.c
+++ b/hw/i386/kvm/apic.c
@@ -28,9 +28,8 @@ static inline uint32_t kvm_apic_get_reg(struct kvm_lapic_state *kapic,
return *((uint32_t *)(kapic->regs + (reg_id << 4)));
}
-void kvm_put_apic_state(DeviceState *dev, struct kvm_lapic_state *kapic)
+static void kvm_put_apic_state(APICCommonState *s, struct kvm_lapic_state *kapic)
{
- APICCommonState *s = APIC_COMMON(dev);
int i;
memset(kapic, 0, sizeof(*kapic));
@@ -125,6 +124,26 @@ static void kvm_apic_vapic_base_update(APICCommonState *s)
}
}
+static void kvm_apic_put(void *data)
+{
+ APICCommonState *s = data;
+ struct kvm_lapic_state kapic;
+ int ret;
+
+ kvm_put_apic_state(s, &kapic);
+
+ ret = kvm_vcpu_ioctl(CPU(s->cpu), KVM_SET_LAPIC, &kapic);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_SET_LAPIC failed: %s\n", strerror(ret));
+ abort();
+ }
+}
+
+static void kvm_apic_post_load(APICCommonState *s)
+{
+ run_on_cpu(CPU(s->cpu), kvm_apic_put, s);
+}
+
static void do_inject_external_nmi(void *data)
{
APICCommonState *s = data;
@@ -178,6 +197,8 @@ static void kvm_apic_reset(APICCommonState *s)
{
/* Not used by KVM, which uses the CPU mp_state instead. */
s->wait_for_sipi = 0;
+
+ run_on_cpu(CPU(s->cpu), kvm_apic_put, s);
}
static void kvm_apic_realize(DeviceState *dev, Error **errp)
@@ -206,6 +227,7 @@ static void kvm_apic_class_init(ObjectClass *klass, void *data)
k->set_base = kvm_apic_set_base;
k->set_tpr = kvm_apic_set_tpr;
k->get_tpr = kvm_apic_get_tpr;
+ k->post_load = kvm_apic_post_load;
k->enable_tpr_reporting = kvm_apic_enable_tpr_reporting;
k->vapic_base_update = kvm_apic_vapic_base_update;
k->external_nmi = kvm_apic_external_nmi;
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index c9c2436..ae5d81b 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -372,7 +372,6 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg);
void kvm_irqchip_add_irq_route(KVMState *s, int gsi, int irqchip, int pin);
-void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic);
void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic);
struct kvm_guest_debug;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index d1a25c5..f1ad805 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -2416,19 +2416,6 @@ static int kvm_get_apic(X86CPU *cpu)
return 0;
}
-static int kvm_put_apic(X86CPU *cpu)
-{
- DeviceState *apic = cpu->apic_state;
- struct kvm_lapic_state kapic;
-
- if (apic && kvm_irqchip_in_kernel()) {
- kvm_put_apic_state(apic, &kapic);
-
- return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_LAPIC, &kapic);
- }
- return 0;
-}
-
static int kvm_put_vcpu_events(X86CPU *cpu, int level)
{
CPUState *cs = CPU(cpu);
@@ -2670,10 +2657,6 @@ int kvm_arch_put_registers(CPUState *cpu, int level)
if (ret < 0) {
return ret;
}
- ret = kvm_put_apic(x86_cpu);
- if (ret < 0) {
- return ret;
- }
}
ret = kvm_put_tscdeadline_msr(x86_cpu);
--
2.1.4

View File

@ -0,0 +1,48 @@
From 109c1a773ac37b2dc3d9781ce203a804d3e77651 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 14:15:49 +0100
Subject: [PATCH 01/47] fr-ca keymap corrections
---
pc-bios/keymaps/fr-ca | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/pc-bios/keymaps/fr-ca b/pc-bios/keymaps/fr-ca
index b645208..9291240 100644
--- a/pc-bios/keymaps/fr-ca
+++ b/pc-bios/keymaps/fr-ca
@@ -14,22 +14,31 @@ bar 0x29 shift
twosuperior 0x9 altgr
threesuperior 0xa altgr
onequarter 0xb altgr
+minus 0x0c
onehalf 0xc altgr
+equal 0xd
threequarters 0xd altgr
section 0x18 altgr
paragraph 0x19 altgr
bracketleft 0x1a altgr
bracketright 0x1b altgr
+semicolon 0x27
+colon 0x27 shift
asciitilde 0x27 altgr
braceleft 0x28 altgr
+numbersign 0x29
braceright 0x2b altgr
less 0x2b
greater 0x2b shift
guillemotleft 0x56
guillemotright 0x56 shift
degree 0x56 altgr
+comma 0x33
mu 0x32 altgr
+apostrophe 0x33 shift
+period 0x34 shift
eacute 0x35
+Eacute 0x35 shift
dead_acute 0x35 altgr
dead_grave 0x28
dead_circumflex 0x1a
--
2.1.4

View File

@ -0,0 +1,28 @@
From 1dfa1a8df7b065e15639d078c0f137f2dec7c3fa Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 14:16:49 +0100
Subject: [PATCH 02/47] Adjust network script path to /etc/kvm/
---
include/net/net.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/include/net/net.h b/include/net/net.h
index e8d9e9e..375e81d 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -216,8 +216,9 @@ void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp);
int net_hub_id_for_client(NetClientState *nc, int *id);
NetClientState *net_hub_port_find(int hub_id);
-#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
-#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
+#define DEFAULT_NETWORK_SCRIPT "/etc/kvm/kvm-ifup"
+#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/kvm/kvm-ifdown"
+
#define DEFAULT_BRIDGE_HELPER CONFIG_QEMU_HELPERDIR "/qemu-bridge-helper"
#define DEFAULT_BRIDGE_INTERFACE "br0"
--
2.1.4

View File

@ -0,0 +1,65 @@
From cf2ef62fc7d4ff7e64eed5a01e499c91b62121b9 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 14:17:38 +0100
Subject: [PATCH 03/47] vnc: altgr emulation
---
ui/vnc.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/ui/vnc.c b/ui/vnc.c
index 76a3273..b9f36b5 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1733,6 +1733,10 @@ static void kbd_leds(void *opaque, int ledstate)
static void do_key_event(VncState *vs, int down, int keycode, int sym)
{
+ int mods = keycode & 0xf00;
+
+ keycode &= SCANCODE_KEYMASK;
+
/* QEMU console switch */
switch(keycode) {
case 0x2a: /* Left Shift */
@@ -1813,8 +1817,27 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
}
if (qemu_console_is_graphic(NULL)) {
+
+ /* our java vnc client never sends ALTGR, so we create
+ an artificial up/down event */
+
+ int emul_altgr = (mods & SCANCODE_ALTGR) &&
+ !vs->modifiers_state[0xb8];
+
+ if (emul_altgr) {
+ reset_keys(vs);
+ qemu_input_event_send_key_number(vs->vd->dcl.con, 0xb8, true);
+ qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
+ }
+
qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down);
qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
+
+ if (emul_altgr) {
+ qemu_input_event_send_key_number(vs->vd->dcl.con, 0xb8, false);
+ qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
+ }
+
} else {
bool numlock = vs->modifiers_state[0x45];
bool control = (vs->modifiers_state[0x1d] ||
@@ -1954,7 +1977,8 @@ static void key_event(VncState *vs, int down, uint32_t sym)
lsym = lsym - 'A' + 'a';
}
- keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF) & SCANCODE_KEYMASK;
+ keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF);
+
trace_vnc_key_event_map(down, sym, keycode, code2name(keycode));
do_key_event(vs, down, keycode, sym);
}
--
2.1.4

View File

@ -0,0 +1,26 @@
From baf469b28e3f1bfd5b03e449ffcd8f41c80a5387 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 14:18:46 +0100
Subject: [PATCH 04/47] qemu-img: return success on info without snapshots
---
qemu-img.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/qemu-img.c b/qemu-img.c
index f204d041..99be68f 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -2389,7 +2389,8 @@ static int img_info(int argc, char **argv)
list = collect_image_info_list(image_opts, filename, fmt, chain);
if (!list) {
- return 1;
+ // return success if snapshot does not exists
+ return 0;
}
switch (output_format) {
--
2.1.4

View File

@ -0,0 +1,27 @@
From c5405c552945f19b36ecc748a2a0e0ec14dff31e Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 14:27:05 +0100
Subject: [PATCH 05/47] use kvm by default
---
accel.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/accel.c b/accel.c
index 403eb5e..dd2ebea 100644
--- a/accel.c
+++ b/accel.c
@@ -88,8 +88,8 @@ void configure_accelerator(MachineState *ms)
p = qemu_opt_get(qemu_get_machine_opts(), "accel");
if (p == NULL) {
- /* Use the default "accelerator", tcg */
- p = "tcg";
+ /* Use the default "accelerator", kvm */
+ p = "kvm";
}
while (!accel_initialised && *p != '\0') {
--
2.1.4

View File

@ -0,0 +1,169 @@
From 132444451193736847c68d91f74c09cb76a16e6a Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 14:27:49 +0100
Subject: [PATCH 06/47] virtio-balloon: fix query
Actually provide memory information via the query-balloon
command.
---
hmp.c | 30 +++++++++++++++++++++++++++++-
hw/virtio/virtio-balloon.c | 33 +++++++++++++++++++++++++++++++--
qapi-schema.json | 23 +++++++++++++++++++++--
qmp-commands.hx | 13 +++++++++++++
4 files changed, 94 insertions(+), 5 deletions(-)
diff --git a/hmp.c b/hmp.c
index bb45f7f..3b0dd81 100644
--- a/hmp.c
+++ b/hmp.c
@@ -704,7 +704,35 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict)
return;
}
- monitor_printf(mon, "balloon: actual=%" PRId64 "\n", info->actual >> 20);
+ monitor_printf(mon, "balloon: actual=%" PRId64, info->actual >> 20);
+ monitor_printf(mon, " max_mem=%" PRId64, info->max_mem >> 20);
+ if (info->has_total_mem) {
+ monitor_printf(mon, " total_mem=%" PRId64, info->total_mem >> 20);
+ }
+ if (info->has_free_mem) {
+ monitor_printf(mon, " free_mem=%" PRId64, info->free_mem >> 20);
+ }
+
+ if (info->has_mem_swapped_in) {
+ monitor_printf(mon, " mem_swapped_in=%" PRId64, info->mem_swapped_in);
+ }
+ if (info->has_mem_swapped_out) {
+ monitor_printf(mon, " mem_swapped_out=%" PRId64, info->mem_swapped_out);
+ }
+ if (info->has_major_page_faults) {
+ monitor_printf(mon, " major_page_faults=%" PRId64,
+ info->major_page_faults);
+ }
+ if (info->has_minor_page_faults) {
+ monitor_printf(mon, " minor_page_faults=%" PRId64,
+ info->minor_page_faults);
+ }
+ if (info->has_last_update) {
+ monitor_printf(mon, " last_update=%" PRId64,
+ info->last_update);
+ }
+
+ monitor_printf(mon, "\n");
qapi_free_BalloonInfo(info);
}
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index ad4189a..b3a17f4 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -376,8 +376,37 @@ static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f,
static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
{
VirtIOBalloon *dev = opaque;
- info->actual = get_current_ram_size() - ((uint64_t) dev->actual <<
- VIRTIO_BALLOON_PFN_SHIFT);
+ ram_addr_t ram_size = get_current_ram_size();
+ info->actual = ram_size - ((uint64_t) dev->actual <<
+ VIRTIO_BALLOON_PFN_SHIFT);
+
+ info->max_mem = ram_size;
+
+ if (!(balloon_stats_enabled(dev) && balloon_stats_supported(dev) &&
+ dev->stats_last_update)) {
+ return;
+ }
+
+ info->last_update = dev->stats_last_update;
+ info->has_last_update = true;
+
+ info->mem_swapped_in = dev->stats[VIRTIO_BALLOON_S_SWAP_IN];
+ info->has_mem_swapped_in = info->mem_swapped_in >= 0 ? true : false;
+
+ info->mem_swapped_out = dev->stats[VIRTIO_BALLOON_S_SWAP_OUT];
+ info->has_mem_swapped_out = info->mem_swapped_out >= 0 ? true : false;
+
+ info->major_page_faults = dev->stats[VIRTIO_BALLOON_S_MAJFLT];
+ info->has_major_page_faults = info->major_page_faults >= 0 ? true : false;
+
+ info->minor_page_faults = dev->stats[VIRTIO_BALLOON_S_MINFLT];
+ info->has_minor_page_faults = info->minor_page_faults >= 0 ? true : false;
+
+ info->free_mem = dev->stats[VIRTIO_BALLOON_S_MEMFREE];
+ info->has_free_mem = info->free_mem >= 0 ? true : false;
+
+ info->total_mem = dev->stats[VIRTIO_BALLOON_S_MEMTOT];
+ info->has_total_mem = info->total_mem >= 0 ? true : false;
}
static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
diff --git a/qapi-schema.json b/qapi-schema.json
index 5658723..4bf7222 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1278,10 +1278,29 @@
#
# @actual: the number of bytes the balloon currently contains
#
-# Since: 0.14.0
+# @last_update: #optional time when stats got updated from guest
+#
+# @mem_swapped_in: #optional number of pages swapped in within the guest
+#
+# @mem_swapped_out: #optional number of pages swapped out within the guest
+#
+# @major_page_faults: #optional number of major page faults within the guest
#
+# @minor_page_faults: #optional number of minor page faults within the guest
+#
+# @free_mem: #optional amount of memory (in bytes) free in the guest
+#
+# @total_mem: #optional amount of memory (in bytes) visible to the guest
+#
+# @max_mem: amount of memory (in bytes) assigned to the guest
+#
+# Since: 0.14.0
##
-{ 'struct': 'BalloonInfo', 'data': {'actual': 'int' } }
+{ 'struct': 'BalloonInfo',
+ 'data': {'actual': 'int', '*last_update': 'int', '*mem_swapped_in': 'int',
+ '*mem_swapped_out': 'int', '*major_page_faults': 'int',
+ '*minor_page_faults': 'int', '*free_mem': 'int',
+ '*total_mem': 'int', 'max_mem': 'int' } }
##
# @query-balloon:
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 6866264..6de28d4 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3854,6 +3854,13 @@ Make an asynchronous request for balloon info. When the request completes a
json-object will be returned containing the following data:
- "actual": current balloon value in bytes (json-int)
+- "mem_swapped_in": Amount of memory swapped in bytes (json-int, optional)
+- "mem_swapped_out": Amount of memory swapped out in bytes (json-int, optional)
+- "major_page_faults": Number of major faults (json-int, optional)
+- "minor_page_faults": Number of minor faults (json-int, optional)
+- "free_mem": Total amount of free and unused memory in
+ bytes (json-int, optional)
+- "total_mem": Total amount of available memory in bytes (json-int, optional)
Example:
@@ -3861,6 +3868,12 @@ Example:
<- {
"return":{
"actual":1073741824,
+ "mem_swapped_in":0,
+ "mem_swapped_out":0,
+ "major_page_faults":142,
+ "minor_page_faults":239245,
+ "free_mem":1014185984,
+ "total_mem":1044668416
}
}
--
2.1.4

View File

@ -0,0 +1,28 @@
From 118ca6343a48aaab7d1a8f252fb36008c823e551 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 14:30:21 +0100
Subject: [PATCH 07/47] set the CPU model to kvm64/32 instead of qemu64/32
---
hw/i386/pc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 022dd1b..ba8a5a1 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1160,9 +1160,9 @@ void pc_cpus_init(PCMachineState *pcms)
/* init CPUs */
if (machine->cpu_model == NULL) {
#ifdef TARGET_X86_64
- machine->cpu_model = "qemu64";
+ machine->cpu_model = "kvm64";
#else
- machine->cpu_model = "qemu32";
+ machine->cpu_model = "kvm32";
#endif
}
--
2.1.4

View File

@ -0,0 +1,52 @@
From dc5b92fbb2d405fd86228409b1f25c0bb2d6d973 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 14:31:18 +0100
Subject: [PATCH 08/47] qapi: modify query machines
provide '*is-current' in MachineInfo struct
---
qapi-schema.json | 4 +++-
vl.c | 5 +++++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/qapi-schema.json b/qapi-schema.json
index 4bf7222..63507f5 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3027,6 +3027,8 @@
#
# @default: #optional whether the machine is default
#
+# @current: #optional whether this machine is currently used
+#
# @cpu-max: maximum number of CPUs supported by the machine type
# (since 1.5.0)
#
@@ -3036,7 +3038,7 @@
##
{ 'struct': 'MachineInfo',
'data': { 'name': 'str', '*alias': 'str',
- '*is-default': 'bool', 'cpu-max': 'int',
+ '*is-default': 'bool', '*is-current': 'bool', 'cpu-max': 'int',
'hotpluggable-cpus': 'bool'} }
##
diff --git a/vl.c b/vl.c
index 6a218ce..b226e0b 100644
--- a/vl.c
+++ b/vl.c
@@ -1509,6 +1509,11 @@ MachineInfoList *qmp_query_machines(Error **errp)
info->cpu_max = !mc->max_cpus ? 1 : mc->max_cpus;
info->hotpluggable_cpus = !!mc->query_hotpluggable_cpus;
+ if (strcmp(mc->name, MACHINE_GET_CLASS(current_machine)->name) == 0) {
+ info->has_is_current = true;
+ info->is_current = true;
+ }
+
entry = g_malloc0(sizeof(*entry));
entry->value = info;
entry->next = mach_list;
--
2.1.4

View File

@ -0,0 +1,49 @@
From c09467afaf37989942076b45f6ffa7bb8ebde2ca Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 14:32:11 +0100
Subject: [PATCH 09/47] qapi: modify spice query
Provide the last ticket in the SpiceInfo struct optionally.
---
qapi-schema.json | 3 +++
ui/spice-core.c | 5 +++++
2 files changed, 8 insertions(+)
diff --git a/qapi-schema.json b/qapi-schema.json
index 63507f5..518c2ea 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1253,11 +1253,14 @@
#
# @channels: a list of @SpiceChannel for each active spice channel
#
+# @ticket: #optional The last ticket set with set_password
+#
# Since: 0.14.0
##
{ 'struct': 'SpiceInfo',
'data': {'enabled': 'bool', 'migrated': 'bool', '*host': 'str', '*port': 'int',
'*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str',
+ '*ticket': 'str',
'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']} }
##
diff --git a/ui/spice-core.c b/ui/spice-core.c
index da05054..acf5a73 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -543,6 +543,11 @@ SpiceInfo *qmp_query_spice(Error **errp)
micro = SPICE_SERVER_VERSION & 0xff;
info->compiled_version = g_strdup_printf("%d.%d.%d", major, minor, micro);
+ if (auth_passwd) {
+ info->has_ticket = true;
+ info->ticket = g_strdup(auth_passwd);
+ }
+
if (port) {
info->has_port = true;
info->port = port;
--
2.1.4

View File

@ -0,0 +1,59 @@
From 78cc6a38bfa2c986ff75a322d750a548bf2291b9 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 14:33:34 +0100
Subject: [PATCH 10/47] ui/spice: default to pve certs unless otherwise
specified
---
ui/spice-core.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/ui/spice-core.c b/ui/spice-core.c
index acf5a73..4f1cf45 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -676,32 +676,35 @@ void qemu_spice_init(void)
if (tls_port) {
x509_dir = qemu_opt_get(opts, "x509-dir");
- if (!x509_dir) {
- x509_dir = ".";
- }
str = qemu_opt_get(opts, "x509-key-file");
if (str) {
x509_key_file = g_strdup(str);
- } else {
+ } else if (x509_dir) {
x509_key_file = g_strdup_printf("%s/%s", x509_dir,
X509_SERVER_KEY_FILE);
+ } else {
+ x509_key_file = g_strdup("/etc/pve/local/pve-ssl.key");
}
str = qemu_opt_get(opts, "x509-cert-file");
if (str) {
x509_cert_file = g_strdup(str);
- } else {
+ } else if (x509_dir) {
x509_cert_file = g_strdup_printf("%s/%s", x509_dir,
X509_SERVER_CERT_FILE);
+ } else {
+ x509_cert_file = g_strdup("/etc/pve/local/pve-ssl.pem");
}
str = qemu_opt_get(opts, "x509-cacert-file");
if (str) {
x509_cacert_file = g_strdup(str);
- } else {
+ } else if (x509_dir) {
x509_cacert_file = g_strdup_printf("%s/%s", x509_dir,
X509_CA_CERT_FILE);
+ } else {
+ x509_cacert_file = g_strdup("/etc/pve/pve-root-ca.pem");
}
x509_key_password = qemu_opt_get(opts, "x509-key-password");
--
2.1.4

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,321 @@
From 144e613eeca6a3383b981f9ca8b82c4a354b36c2 Mon Sep 17 00:00:00 2001
From: Dietmar Maurer <dietmar@proxmox.com>
Date: Mon, 11 Mar 2013 07:07:46 +0100
Subject: [PATCH 12/47] vma: add verify command
Users wants to verify the archive after backup.
Examples:
# vma verify -v test.vma
# lzop -d -c test.vma.lzo |vma verify -
Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
---
vma-reader.c | 121 ++++++++++++++++++++++++++++++++++++++++++++---------------
vma.c | 55 +++++++++++++++++++++++++++
vma.h | 1 +
3 files changed, 147 insertions(+), 30 deletions(-)
diff --git a/vma-reader.c b/vma-reader.c
index 51dd8fe..2aafb26 100644
--- a/vma-reader.c
+++ b/vma-reader.c
@@ -45,6 +45,8 @@ struct VmaReader {
time_t start_time;
int64_t cluster_count;
int64_t clusters_read;
+ int64_t zero_cluster_data;
+ int64_t partial_zero_cluster_data;
int clusters_read_per;
};
@@ -425,6 +427,27 @@ VmaDeviceInfo *vma_reader_get_device_info(VmaReader *vmar, guint8 dev_id)
return NULL;
}
+static void allocate_rstate(VmaReader *vmar, guint8 dev_id,
+ BlockDriverState *bs, bool write_zeroes)
+{
+ assert(vmar);
+ assert(dev_id);
+
+ vmar->rstate[dev_id].bs = bs;
+ vmar->rstate[dev_id].write_zeroes = write_zeroes;
+
+ int64_t size = vmar->devinfo[dev_id].size;
+
+ int64_t bitmap_size = (size/BDRV_SECTOR_SIZE) +
+ (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG - 1;
+ bitmap_size /= (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG;
+
+ vmar->rstate[dev_id].bitmap_size = bitmap_size;
+ vmar->rstate[dev_id].bitmap = g_new0(unsigned long, bitmap_size);
+
+ vmar->cluster_count += size/VMA_CLUSTER_SIZE;
+}
+
int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockDriverState *bs,
bool write_zeroes, Error **errp)
{
@@ -447,17 +470,7 @@ int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockDriverState *bs,
return -1;
}
- vmar->rstate[dev_id].bs = bs;
- vmar->rstate[dev_id].write_zeroes = write_zeroes;
-
- int64_t bitmap_size = (size/BDRV_SECTOR_SIZE) +
- (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG - 1;
- bitmap_size /= (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG;
-
- vmar->rstate[dev_id].bitmap_size = bitmap_size;
- vmar->rstate[dev_id].bitmap = g_new0(unsigned long, bitmap_size);
-
- vmar->cluster_count += size/VMA_CLUSTER_SIZE;
+ allocate_rstate(vmar, dev_id, bs, write_zeroes);
return 0;
}
@@ -524,9 +537,10 @@ static int restore_write_data(VmaReader *vmar, guint8 dev_id,
}
return 0;
}
+
static int restore_extent(VmaReader *vmar, unsigned char *buf,
int extent_size, int vmstate_fd,
- bool verbose, Error **errp)
+ bool verbose, bool verify, Error **errp)
{
assert(vmar);
assert(buf);
@@ -551,7 +565,7 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
if (dev_id != vmar->vmstate_stream) {
bs = rstate->bs;
- if (!bs) {
+ if (!verify && !bs) {
error_setg(errp, "got wrong dev id %d", dev_id);
return -1;
}
@@ -607,10 +621,13 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
return -1;
}
- int nb_sectors = end_sector - sector_num;
- if (restore_write_data(vmar, dev_id, bs, vmstate_fd, buf + start,
- sector_num, nb_sectors, errp) < 0) {
- return -1;
+ if (!verify) {
+ int nb_sectors = end_sector - sector_num;
+ if (restore_write_data(vmar, dev_id, bs, vmstate_fd,
+ buf + start, sector_num, nb_sectors,
+ errp) < 0) {
+ return -1;
+ }
}
start += VMA_CLUSTER_SIZE;
@@ -640,26 +657,37 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
return -1;
}
- int nb_sectors = end_sector - sector_num;
- if (restore_write_data(vmar, dev_id, bs, vmstate_fd,
- buf + start, sector_num,
- nb_sectors, errp) < 0) {
- return -1;
+ if (!verify) {
+ int nb_sectors = end_sector - sector_num;
+ if (restore_write_data(vmar, dev_id, bs, vmstate_fd,
+ buf + start, sector_num,
+ nb_sectors, errp) < 0) {
+ return -1;
+ }
}
start += VMA_BLOCK_SIZE;
} else {
- if (rstate->write_zeroes && (end_sector > sector_num)) {
+
+ if (end_sector > sector_num) {
/* Todo: use bdrv_co_write_zeroes (but that need to
* be run inside coroutine?)
*/
int nb_sectors = end_sector - sector_num;
- if (restore_write_data(vmar, dev_id, bs, vmstate_fd,
- zero_vma_block, sector_num,
- nb_sectors, errp) < 0) {
- return -1;
+ int zero_size = BDRV_SECTOR_SIZE*nb_sectors;
+ vmar->zero_cluster_data += zero_size;
+ if (mask != 0) {
+ vmar->partial_zero_cluster_data += zero_size;
+ }
+
+ if (rstate->write_zeroes && !verify) {
+ if (restore_write_data(vmar, dev_id, bs, vmstate_fd,
+ zero_vma_block, sector_num,
+ nb_sectors, errp) < 0) {
+ return -1;
+ }
}
}
}
@@ -677,8 +705,9 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
return 0;
}
-int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
- Error **errp)
+static int vma_reader_restore_full(VmaReader *vmar, int vmstate_fd,
+ bool verbose, bool verify,
+ Error **errp)
{
assert(vmar);
assert(vmar->head_data);
@@ -745,7 +774,7 @@ int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
}
if (restore_extent(vmar, buf, extent_size, vmstate_fd, verbose,
- errp) < 0) {
+ verify, errp) < 0) {
return -1;
}
@@ -792,6 +821,38 @@ int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
}
}
+ if (verbose) {
+ printf("total bytes read %zd, sparse bytes %zd (%.3g%%)\n",
+ vmar->clusters_read*VMA_CLUSTER_SIZE,
+ vmar->zero_cluster_data,
+ (double)(100.0*vmar->zero_cluster_data)/
+ (vmar->clusters_read*VMA_CLUSTER_SIZE));
+
+ int64_t datasize = vmar->clusters_read*VMA_CLUSTER_SIZE-vmar->zero_cluster_data;
+ if (datasize) { // this does not make sense for empty files
+ printf("space reduction due to 4K zero blocks %.3g%%\n",
+ (double)(100.0*vmar->partial_zero_cluster_data) / datasize);
+ }
+ }
return ret;
}
+int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
+ Error **errp)
+{
+ return vma_reader_restore_full(vmar, vmstate_fd, verbose, false, errp);
+}
+
+int vma_reader_verify(VmaReader *vmar, bool verbose, Error **errp)
+{
+ guint8 dev_id;
+
+ for (dev_id = 1; dev_id < 255; dev_id++) {
+ if (vma_reader_get_device_info(vmar, dev_id)) {
+ allocate_rstate(vmar, dev_id, NULL, false);
+ }
+ }
+
+ return vma_reader_restore_full(vmar, -1, verbose, true, errp);
+}
+
diff --git a/vma.c b/vma.c
index 8014090..d55874a 100644
--- a/vma.c
+++ b/vma.c
@@ -28,6 +28,7 @@ static void help(void)
"vma list <filename>\n"
"vma create <filename> [-c config] <archive> pathname ...\n"
"vma extract <filename> [-r <fifo>] <targetdir>\n"
+ "vma verify <filename> [-v]\n"
;
printf("%s", help_msg);
@@ -332,6 +333,58 @@ static int extract_content(int argc, char **argv)
return ret;
}
+static int verify_content(int argc, char **argv)
+{
+ int c, ret = 0;
+ int verbose = 0;
+ const char *filename;
+
+ for (;;) {
+ c = getopt(argc, argv, "hv");
+ if (c == -1) {
+ break;
+ }
+ switch (c) {
+ case '?':
+ case 'h':
+ help();
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ help();
+ }
+ }
+
+ /* Get the filename */
+ if ((optind + 1) != argc) {
+ help();
+ }
+ filename = argv[optind++];
+
+ Error *errp = NULL;
+ VmaReader *vmar = vma_reader_create(filename, &errp);
+
+ if (!vmar) {
+ g_error("%s", error_get_pretty(errp));
+ }
+
+ if (verbose) {
+ print_content(vmar);
+ }
+
+ if (vma_reader_verify(vmar, verbose, &errp) < 0) {
+ g_error("verify failed - %s", error_get_pretty(errp));
+ }
+
+ vma_reader_destroy(vmar);
+
+ bdrv_close_all();
+
+ return ret;
+}
+
typedef struct BackupJob {
BlockDriverState *bs;
int64_t len;
@@ -578,6 +631,8 @@ int main(int argc, char **argv)
return create_archive(argc, argv);
} else if (!strcmp(cmdname, "extract")) {
return extract_content(argc, argv);
+ } else if (!strcmp(cmdname, "verify")) {
+ return verify_content(argc, argv);
}
help();
diff --git a/vma.h b/vma.h
index 6625eb9..9bb6ea4 100644
--- a/vma.h
+++ b/vma.h
@@ -142,5 +142,6 @@ int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id,
Error **errp);
int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
Error **errp);
+int vma_reader_verify(VmaReader *vmar, bool verbose, Error **errp);
#endif /* BACKUP_VMA_H */
--
2.1.4

View File

@ -0,0 +1,101 @@
From 48896281bebc5c69760f4e47625e4db81e3a9004 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 14:46:49 +0100
Subject: [PATCH 13/47] vma: add 'config' command to dump the config
---
vma.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+)
diff --git a/vma.c b/vma.c
index d55874a..79bdd00 100644
--- a/vma.c
+++ b/vma.c
@@ -26,6 +26,7 @@ static void help(void)
"usage: vma command [command options]\n"
"\n"
"vma list <filename>\n"
+ "vma config <filename> [-c config]\n"
"vma create <filename> [-c config] <archive> pathname ...\n"
"vma extract <filename> [-r <fifo>] <targetdir>\n"
"vma verify <filename> [-v]\n"
@@ -604,6 +605,67 @@ static int create_archive(int argc, char **argv)
return 0;
}
+static int dump_config(int argc, char **argv)
+{
+ int c, ret = 0;
+ const char *filename;
+ const char *config_name = "qemu-server.conf";
+
+ for (;;) {
+ c = getopt(argc, argv, "hc:");
+ if (c == -1) {
+ break;
+ }
+ switch (c) {
+ case '?':
+ case 'h':
+ help();
+ break;
+ case 'c':
+ config_name = optarg;
+ break;
+ default:
+ help();
+ }
+ }
+
+ /* Get the filename */
+ if ((optind + 1) != argc) {
+ help();
+ }
+ filename = argv[optind++];
+
+ Error *errp = NULL;
+ VmaReader *vmar = vma_reader_create(filename, &errp);
+
+ if (!vmar) {
+ g_error("%s", error_get_pretty(errp));
+ }
+
+ int found = 0;
+ GList *l = vma_reader_get_config_data(vmar);
+ while (l && l->data) {
+ VmaConfigData *cdata = (VmaConfigData *)l->data;
+ l = g_list_next(l);
+ if (strcmp(cdata->name, config_name) == 0) {
+ found = 1;
+ fwrite(cdata->data, cdata->len, 1, stdout);
+ break;
+ }
+ }
+
+ vma_reader_destroy(vmar);
+
+ bdrv_close_all();
+
+ if (!found) {
+ fprintf(stderr, "unable to find configuration data '%s'\n", config_name);
+ return -1;
+ }
+
+ return ret;
+}
+
int main(int argc, char **argv)
{
const char *cmdname;
@@ -633,6 +695,8 @@ int main(int argc, char **argv)
return extract_content(argc, argv);
} else if (!strcmp(cmdname, "verify")) {
return verify_content(argc, argv);
+ } else if (!strcmp(cmdname, "config")) {
+ return dump_config(argc, argv);
}
help();
--
2.1.4

View File

@ -0,0 +1,236 @@
From 1078c0f6acc1bfba04b7d5cdfdeb02b161b5f7c4 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 15:04:57 +0100
Subject: [PATCH 14/47] backup: modify job api
Introduces a BackupDump function callback and a pause_count
for backup_start. For a dump-backup the target parameter
can now be NULL so access to target needs to be guarded now.
---
block/backup.c | 82 +++++++++++++++++++++++++++++++----------------
blockdev.c | 6 ++--
include/block/block_int.h | 5 +++
3 files changed, 63 insertions(+), 30 deletions(-)
diff --git a/block/backup.c b/block/backup.c
index 2c05323..f3c0ba3 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -41,6 +41,7 @@ typedef struct BackupBlockJob {
BdrvDirtyBitmap *sync_bitmap;
MirrorSyncMode sync_mode;
RateLimit limit;
+ BackupDumpFunc *dump_cb;
BlockdevOnError on_source_error;
BlockdevOnError on_target_error;
CoRwlock flush_rwlock;
@@ -149,12 +150,23 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
goto out;
}
+ int64_t start_sec = start * sectors_per_cluster;
if (buffer_is_zero(iov.iov_base, iov.iov_len)) {
- ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size,
- bounce_qiov.size, BDRV_REQ_MAY_UNMAP);
+ if (job->dump_cb) {
+ ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, NULL);
+ }
+ if (job->target) {
+ ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size,
+ bounce_qiov.size, BDRV_REQ_MAY_UNMAP);
+ }
} else {
- ret = blk_co_pwritev(job->target, start * job->cluster_size,
- bounce_qiov.size, &bounce_qiov, 0);
+ if (job->dump_cb) {
+ ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, bounce_buffer);
+ }
+ if (job->target) {
+ ret = blk_co_pwritev(job->target, start * job->cluster_size,
+ bounce_qiov.size, &bounce_qiov, 0);
+ }
}
if (ret < 0) {
trace_backup_do_cow_write_fail(job, start, ret);
@@ -268,9 +280,11 @@ static BlockErrorAction backup_error_action(BackupBlockJob *job,
if (read) {
return block_job_error_action(&job->common, job->on_source_error,
true, error);
- } else {
+ } else if (job->target) {
return block_job_error_action(&job->common, job->on_target_error,
false, error);
+ } else {
+ return BLOCK_ERROR_ACTION_REPORT;
}
}
@@ -393,6 +407,7 @@ static void coroutine_fn backup_run(void *opaque)
job->done_bitmap = bitmap_new(end);
+
job->before_write.notify = backup_before_write_notify;
bdrv_add_before_write_notifier(bs, &job->before_write);
@@ -467,7 +482,9 @@ static void coroutine_fn backup_run(void *opaque)
qemu_co_rwlock_unlock(&job->flush_rwlock);
g_free(job->done_bitmap);
- bdrv_op_unblock_all(blk_bs(target), job->common.blocker);
+ if (target) {
+ bdrv_op_unblock_all(blk_bs(target), job->common.blocker);
+ }
data = g_malloc(sizeof(*data));
data->ret = ret;
@@ -479,7 +496,9 @@ void backup_start(const char *job_id, BlockDriverState *bs,
MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap,
BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
+ BackupDumpFunc *dump_cb,
BlockCompletionFunc *cb, void *opaque,
+ int pause_count,
BlockJobTxn *txn, Error **errp)
{
int64_t len;
@@ -488,7 +507,7 @@ void backup_start(const char *job_id, BlockDriverState *bs,
int ret;
assert(bs);
- assert(target);
+ assert(target || dump_cb);
if (bs == target) {
error_setg(errp, "Source and target cannot be the same");
@@ -501,7 +520,7 @@ void backup_start(const char *job_id, BlockDriverState *bs,
return;
}
- if (!bdrv_is_inserted(target)) {
+ if (target && !bdrv_is_inserted(target)) {
error_setg(errp, "Device is not inserted: %s",
bdrv_get_device_name(target));
return;
@@ -511,7 +530,7 @@ void backup_start(const char *job_id, BlockDriverState *bs,
return;
}
- if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) {
+ if (target && bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) {
return;
}
@@ -547,34 +566,43 @@ void backup_start(const char *job_id, BlockDriverState *bs,
goto error;
}
- job->target = blk_new();
- blk_insert_bs(job->target, target);
+ if (target) {
+ job->target = blk_new();
+ blk_insert_bs(job->target, target);
+ }
+ job->dump_cb = dump_cb;
job->on_source_error = on_source_error;
job->on_target_error = on_target_error;
job->sync_mode = sync_mode;
job->sync_bitmap = sync_mode == MIRROR_SYNC_MODE_INCREMENTAL ?
sync_bitmap : NULL;
- /* If there is no backing file on the target, we cannot rely on COW if our
- * backup cluster size is smaller than the target cluster size. Even for
- * targets with a backing file, try to avoid COW if possible. */
- ret = bdrv_get_info(target, &bdi);
- if (ret < 0 && !target->backing) {
- error_setg_errno(errp, -ret,
- "Couldn't determine the cluster size of the target image, "
- "which has no backing file");
- error_append_hint(errp,
- "Aborting, since this may create an unusable destination image\n");
- goto error;
- } else if (ret < 0 && target->backing) {
- /* Not fatal; just trudge on ahead. */
- job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
+ if (target) {
+ /* If there is no backing file on the target, we cannot rely on COW if our
+ * backup cluster size is smaller than the target cluster size. Even for
+ * targets with a backing file, try to avoid COW if possible. */
+ ret = bdrv_get_info(target, &bdi);
+ if (ret < 0 && !target->backing) {
+ error_setg_errno(errp, -ret,
+ "Couldn't determine the cluster size of the target image, "
+ "which has no backing file");
+ error_append_hint(errp,
+ "Aborting, since this may create an unusable destination image\n");
+ goto error;
+ } else if (ret < 0 && target->backing) {
+ /* Not fatal; just trudge on ahead. */
+ job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
+ } else {
+ job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
+ }
+
+ bdrv_op_block_all(target, job->common.blocker);
} else {
- job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
+ job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
}
- bdrv_op_block_all(target, job->common.blocker);
+ job->common.pause_count = pause_count;
job->common.len = len;
job->common.co = qemu_coroutine_create(backup_run, job);
block_job_txn_add_job(txn, &job->common);
diff --git a/blockdev.c b/blockdev.c
index 2161400..5e3707d 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3277,8 +3277,8 @@ static void do_drive_backup(const char *job_id, const char *device,
}
backup_start(job_id, bs, target_bs, speed, sync, bmap,
- on_source_error, on_target_error,
- block_job_cb, bs, txn, &local_err);
+ on_source_error, on_target_error, NULL,
+ block_job_cb, bs, 0, txn, &local_err);
bdrv_unref(target_bs);
if (local_err != NULL) {
error_propagate(errp, local_err);
@@ -3371,7 +3371,7 @@ void do_blockdev_backup(const char *job_id, const char *device,
}
}
backup_start(job_id, bs, target_bs, speed, sync, NULL, on_source_error,
- on_target_error, block_job_cb, bs, txn, &local_err);
+ on_target_error, NULL, block_job_cb, bs, 0, txn, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
}
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 1e939de..db4650e 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -59,6 +59,9 @@
#define BLOCK_PROBE_BUF_SIZE 512
+typedef int BackupDumpFunc(void *opaque, BlockDriverState *bs,
+ int64_t sector_num, int n_sectors, unsigned char *buf);
+
enum BdrvTrackedRequestType {
BDRV_TRACKED_READ,
BDRV_TRACKED_WRITE,
@@ -767,7 +770,9 @@ void backup_start(const char *job_id, BlockDriverState *bs,
MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap,
BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
+ BackupDumpFunc *dump_cb,
BlockCompletionFunc *cb, void *opaque,
+ int pause_count,
BlockJobTxn *txn, Error **errp);
void hmp_drive_add_node(Monitor *mon, const char *optstr);
--
2.1.4

View File

@ -0,0 +1,797 @@
From 798846b48b31d8231a3af5858285845d932d1d6b Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 15:20:56 +0100
Subject: [PATCH 15/47] backup: add pve monitor commands
---
blockdev.c | 439 ++++++++++++++++++++++++++++++++++++++++++++++
blockjob.c | 3 +-
hmp-commands-info.hx | 13 ++
hmp-commands.hx | 29 +++
hmp.c | 61 +++++++
hmp.h | 3 +
include/block/block_int.h | 2 +-
qapi-schema.json | 89 ++++++++++
qmp-commands.hx | 18 ++
9 files changed, 655 insertions(+), 2 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 5e3707d..5417bb0 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -52,6 +52,7 @@
#include "sysemu/arch_init.h"
#include "qemu/cutils.h"
#include "qemu/help_option.h"
+#include "vma.h"
static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states);
@@ -2976,6 +2977,444 @@ static void block_job_cb(void *opaque, int ret)
}
}
+/* PVE backup related function */
+
+static struct PVEBackupState {
+ Error *error;
+ bool cancel;
+ uuid_t uuid;
+ char uuid_str[37];
+ int64_t speed;
+ time_t start_time;
+ time_t end_time;
+ char *backup_file;
+ VmaWriter *vmaw;
+ GList *di_list;
+ size_t total;
+ size_t transferred;
+ size_t zero_bytes;
+} backup_state;
+
+typedef struct PVEBackupDevInfo {
+ BlockDriverState *bs;
+ size_t size;
+ uint8_t dev_id;
+ //bool started;
+ bool completed;
+} PVEBackupDevInfo;
+
+static void pvebackup_run_next_job(void);
+
+static int pvebackup_dump_cb(void *opaque, BlockBackend *target,
+ int64_t sector_num, int n_sectors,
+ unsigned char *buf)
+{
+ PVEBackupDevInfo *di = opaque;
+
+ if (sector_num & 0x7f) {
+ if (!backup_state.error) {
+ error_setg(&backup_state.error,
+ "got unaligned write inside backup dump "
+ "callback (sector %ld)", sector_num);
+ }
+ return -1; // not aligned to cluster size
+ }
+
+ int64_t cluster_num = sector_num >> 7;
+ int size = n_sectors * BDRV_SECTOR_SIZE;
+
+ int ret = -1;
+
+ if (backup_state.vmaw) {
+ size_t zero_bytes = 0;
+ ret = vma_writer_write(backup_state.vmaw, di->dev_id, cluster_num,
+ buf, &zero_bytes);
+ backup_state.zero_bytes += zero_bytes;
+ } else {
+ ret = size;
+ if (!buf) {
+ backup_state.zero_bytes += size;
+ }
+ }
+
+ backup_state.transferred += size;
+
+ return ret;
+}
+
+static void pvebackup_cleanup(void)
+{
+ backup_state.end_time = time(NULL);
+
+ if (backup_state.vmaw) {
+ Error *local_err = NULL;
+ vma_writer_close(backup_state.vmaw, &local_err);
+ error_propagate(&backup_state.error, local_err);
+ backup_state.vmaw = NULL;
+ }
+
+ if (backup_state.di_list) {
+ GList *l = backup_state.di_list;
+ while (l) {
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
+ l = g_list_next(l);
+ g_free(di);
+ }
+ g_list_free(backup_state.di_list);
+ backup_state.di_list = NULL;
+ }
+}
+
+static void pvebackup_complete_cb(void *opaque, int ret)
+{
+ PVEBackupDevInfo *di = opaque;
+
+ assert(backup_state.vmaw);
+
+ di->completed = true;
+
+ if (ret < 0 && !backup_state.error) {
+ error_setg(&backup_state.error, "job failed with err %d - %s",
+ ret, strerror(-ret));
+ }
+
+ BlockDriverState *bs = di->bs;
+
+ di->bs = NULL;
+
+ vma_writer_close_stream(backup_state.vmaw, di->dev_id);
+
+ block_job_cb(bs, ret);
+
+ if (!backup_state.cancel) {
+ pvebackup_run_next_job();
+ }
+}
+
+static void pvebackup_cancel(void *opaque)
+{
+ backup_state.cancel = true;
+
+ if (!backup_state.error) {
+ error_setg(&backup_state.error, "backup cancelled");
+ }
+
+ /* drain all i/o (awake jobs waiting for aio) */
+ bdrv_drain_all();
+
+ GList *l = backup_state.di_list;
+ while (l) {
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
+ l = g_list_next(l);
+ if (!di->completed && di->bs) {
+ BlockJob *job = di->bs->job;
+ if (job) {
+ if (!di->completed) {
+ block_job_cancel_sync(job);
+ }
+ }
+ }
+ }
+
+ pvebackup_cleanup();
+}
+
+void qmp_backup_cancel(Error **errp)
+{
+ Coroutine *co = qemu_coroutine_create(pvebackup_cancel, NULL);
+ qemu_coroutine_enter(co);
+
+ while (backup_state.vmaw) {
+ /* vma writer use main aio context */
+ aio_poll(qemu_get_aio_context(), true);
+ }
+}
+
+bool block_job_should_pause(BlockJob *job);
+static void pvebackup_run_next_job(void)
+{
+ GList *l = backup_state.di_list;
+ while (l) {
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
+ l = g_list_next(l);
+ if (!di->completed && di->bs && di->bs->job) {
+ BlockJob *job = di->bs->job;
+ if (block_job_should_pause(job)) {
+ bool cancel = backup_state.error || backup_state.cancel;
+ if (cancel) {
+ block_job_cancel(job);
+ } else {
+ block_job_resume(job);
+ }
+ }
+ return;
+ }
+ }
+
+ pvebackup_cleanup();
+}
+
+UuidInfo *qmp_backup(const char *backup_file, bool has_format,
+ BackupFormat format,
+ bool has_config_file, const char *config_file,
+ bool has_devlist, const char *devlist,
+ bool has_speed, int64_t speed, Error **errp)
+{
+ BlockBackend *blk;
+ BlockDriverState *bs = NULL;
+ Error *local_err = NULL;
+ uuid_t uuid;
+ VmaWriter *vmaw = NULL;
+ gchar **devs = NULL;
+ GList *di_list = NULL;
+ GList *l;
+ UuidInfo *uuid_info;
+
+ if (backup_state.di_list) {
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+ "previous backup not finished");
+ return NULL;
+ }
+
+ /* Todo: try to auto-detect format based on file name */
+ format = has_format ? format : BACKUP_FORMAT_VMA;
+
+ if (format != BACKUP_FORMAT_VMA) {
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format");
+ return NULL;
+ }
+
+ if (has_devlist) {
+ devs = g_strsplit_set(devlist, ",;:", -1);
+
+ gchar **d = devs;
+ while (d && *d) {
+ blk = blk_by_name(*d);
+ if (blk) {
+ bs = blk_bs(blk);
+ if (bdrv_is_read_only(bs)) {
+ error_setg(errp, "Node '%s' is read only", *d);
+ goto err;
+ }
+ if (!bdrv_is_inserted(bs)) {
+ error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, *d);
+ goto err;
+ }
+ PVEBackupDevInfo *di = g_new0(PVEBackupDevInfo, 1);
+ di->bs = bs;
+ di_list = g_list_append(di_list, di);
+ } else {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", *d);
+ goto err;
+ }
+ d++;
+ }
+
+ } else {
+ BdrvNextIterator it;
+
+ bs = NULL;
+ for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
+ if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
+ continue;
+ }
+
+ PVEBackupDevInfo *di = g_new0(PVEBackupDevInfo, 1);
+ di->bs = bs;
+ di_list = g_list_append(di_list, di);
+ }
+ }
+
+ if (!di_list) {
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "empty device list");
+ goto err;
+ }
+
+ size_t total = 0;
+
+ l = di_list;
+ while (l) {
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
+ l = g_list_next(l);
+ if (bdrv_op_is_blocked(di->bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
+ goto err;
+ }
+
+ ssize_t size = bdrv_getlength(di->bs);
+ if (size < 0) {
+ error_setg_errno(errp, -di->size, "bdrv_getlength failed");
+ goto err;
+ }
+ di->size = size;
+ total += size;
+ }
+
+ uuid_generate(uuid);
+
+ vmaw = vma_writer_create(backup_file, uuid, &local_err);
+ if (!vmaw) {
+ if (local_err) {
+ error_propagate(errp, local_err);
+ }
+ goto err;
+ }
+
+ /* register all devices for vma writer */
+ l = di_list;
+ while (l) {
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
+ l = g_list_next(l);
+
+ const char *devname = bdrv_get_device_name(di->bs);
+ di->dev_id = vma_writer_register_stream(vmaw, devname, di->size);
+ if (di->dev_id <= 0) {
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+ "register_stream failed");
+ goto err;
+ }
+ }
+
+ /* add configuration file to archive */
+ if (has_config_file) {
+ char *cdata = NULL;
+ gsize clen = 0;
+ GError *err = NULL;
+ if (!g_file_get_contents(config_file, &cdata, &clen, &err)) {
+ error_setg(errp, "unable to read file '%s'", config_file);
+ goto err;
+ }
+
+ const char *basename = g_path_get_basename(config_file);
+ if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) {
+ error_setg(errp, "unable to add config data to vma archive");
+ g_free(cdata);
+ goto err;
+ }
+ g_free(cdata);
+ }
+
+ /* initialize global backup_state now */
+
+ backup_state.cancel = false;
+
+ if (backup_state.error) {
+ error_free(backup_state.error);
+ backup_state.error = NULL;
+ }
+
+ backup_state.speed = (has_speed && speed > 0) ? speed : 0;
+
+ backup_state.start_time = time(NULL);
+ backup_state.end_time = 0;
+
+ if (backup_state.backup_file) {
+ g_free(backup_state.backup_file);
+ }
+ backup_state.backup_file = g_strdup(backup_file);
+
+ backup_state.vmaw = vmaw;
+
+ uuid_copy(backup_state.uuid, uuid);
+ uuid_unparse_lower(uuid, backup_state.uuid_str);
+
+ backup_state.di_list = di_list;
+
+ backup_state.total = total;
+ backup_state.transferred = 0;
+ backup_state.zero_bytes = 0;
+
+ /* start all jobs (paused state) */
+ l = di_list;
+ while (l) {
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
+ l = g_list_next(l);
+
+ backup_start(NULL, di->bs, NULL, speed, MIRROR_SYNC_MODE_FULL, NULL,
+ BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
+ pvebackup_dump_cb, pvebackup_complete_cb, di,
+ 1, NULL, &local_err);
+ if (local_err != NULL) {
+ error_setg(&backup_state.error, "backup_job_create failed");
+ pvebackup_cancel(NULL);
+ }
+ }
+
+ if (!backup_state.error) {
+ pvebackup_run_next_job(); // run one job
+ }
+
+ uuid_info = g_malloc0(sizeof(*uuid_info));
+ uuid_info->UUID = g_strdup(backup_state.uuid_str);
+ return uuid_info;
+
+err:
+
+ l = di_list;
+ while (l) {
+ g_free(l->data);
+ l = g_list_next(l);
+ }
+ g_list_free(di_list);
+
+ if (devs) {
+ g_strfreev(devs);
+ }
+
+ if (vmaw) {
+ Error *err = NULL;
+ vma_writer_close(vmaw, &err);
+ unlink(backup_file);
+ }
+
+ return NULL;
+}
+
+BackupStatus *qmp_query_backup(Error **errp)
+{
+ BackupStatus *info = g_malloc0(sizeof(*info));
+
+ if (!backup_state.start_time) {
+ /* not started, return {} */
+ return info;
+ }
+
+ info->has_status = true;
+ info->has_start_time = true;
+ info->start_time = backup_state.start_time;
+
+ if (backup_state.backup_file) {
+ info->has_backup_file = true;
+ info->backup_file = g_strdup(backup_state.backup_file);
+ }
+
+ info->has_uuid = true;
+ info->uuid = g_strdup(backup_state.uuid_str);
+
+ if (backup_state.end_time) {
+ if (backup_state.error) {
+ info->status = g_strdup("error");
+ info->has_errmsg = true;
+ info->errmsg = g_strdup(error_get_pretty(backup_state.error));
+ } else {
+ info->status = g_strdup("done");
+ }
+ info->has_end_time = true;
+ info->end_time = backup_state.end_time;
+ } else {
+ info->status = g_strdup("active");
+ }
+
+ info->has_total = true;
+ info->total = backup_state.total;
+ info->has_zero_bytes = true;
+ info->zero_bytes = backup_state.zero_bytes;
+ info->has_transferred = true;
+ info->transferred = backup_state.transferred;
+
+ return info;
+}
+
void qmp_block_stream(bool has_job_id, const char *job_id, const char *device,
bool has_base, const char *base,
bool has_backing_file, const char *backing_file,
diff --git a/blockjob.c b/blockjob.c
index a5ba3be..a550458 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -331,7 +331,8 @@ void block_job_pause(BlockJob *job)
job->pause_count++;
}
-static bool block_job_should_pause(BlockJob *job)
+bool block_job_should_pause(BlockJob *job);
+bool block_job_should_pause(BlockJob *job)
{
return job->pause_count > 0;
}
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 74446c6..7616fe2 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -502,6 +502,19 @@ STEXI
Show CPU statistics.
ETEXI
+ {
+ .name = "backup",
+ .args_type = "",
+ .params = "",
+ .help = "show backup status",
+ .mhandler.cmd = hmp_info_backup,
+ },
+
+STEXI
+@item info backup
+show backup status
+ETEXI
+
#if defined(CONFIG_SLIRP)
{
.name = "usernet",
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 848efee..8f2f3e0 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -87,6 +87,35 @@ STEXI
Copy data from a backing file into a block device.
ETEXI
+ {
+ .name = "backup",
+ .args_type = "backupfile:s,speed:o?,devlist:s?",
+ .params = "backupfile [speed [devlist]]",
+ .help = "create a VM Backup.",
+ .mhandler.cmd = hmp_backup,
+ },
+
+STEXI
+@item backup
+@findex backup
+Create a VM backup.
+ETEXI
+
+ {
+ .name = "backup_cancel",
+ .args_type = "",
+ .params = "",
+ .help = "cancel the current VM backup",
+ .mhandler.cmd = hmp_backup_cancel,
+ },
+
+STEXI
+@item backup_cancel
+@findex backup_cancel
+Cancel the current VM backup.
+
+ETEXI
+
{
.name = "block_job_set_speed",
.args_type = "device:B,speed:o",
diff --git a/hmp.c b/hmp.c
index 3b0dd81..95da164 100644
--- a/hmp.c
+++ b/hmp.c
@@ -149,6 +149,44 @@ void hmp_info_mice(Monitor *mon, const QDict *qdict)
qapi_free_MouseInfoList(mice_list);
}
+void hmp_info_backup(Monitor *mon, const QDict *qdict)
+{
+ BackupStatus *info;
+
+ info = qmp_query_backup(NULL);
+ if (info->has_status) {
+ if (info->has_errmsg) {
+ monitor_printf(mon, "Backup status: %s - %s\n",
+ info->status, info->errmsg);
+ } else {
+ monitor_printf(mon, "Backup status: %s\n", info->status);
+ }
+ }
+
+ if (info->has_backup_file) {
+ monitor_printf(mon, "Start time: %s", ctime(&info->start_time));
+ if (info->end_time) {
+ monitor_printf(mon, "End time: %s", ctime(&info->end_time));
+ }
+
+ int per = (info->has_total && info->total &&
+ info->has_transferred && info->transferred) ?
+ (info->transferred * 100)/info->total : 0;
+ int zero_per = (info->has_total && info->total &&
+ info->has_zero_bytes && info->zero_bytes) ?
+ (info->zero_bytes * 100)/info->total : 0;
+ monitor_printf(mon, "Backup file: %s\n", info->backup_file);
+ monitor_printf(mon, "Backup uuid: %s\n", info->uuid);
+ monitor_printf(mon, "Total size: %zd\n", info->total);
+ monitor_printf(mon, "Transferred bytes: %zd (%d%%)\n",
+ info->transferred, per);
+ monitor_printf(mon, "Zero bytes: %zd (%d%%)\n",
+ info->zero_bytes, zero_per);
+ }
+
+ qapi_free_BackupStatus(info);
+}
+
void hmp_info_migrate(Monitor *mon, const QDict *qdict)
{
MigrationInfo *info;
@@ -1493,6 +1531,29 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, &error);
}
+void hmp_backup_cancel(Monitor *mon, const QDict *qdict)
+{
+ Error *error = NULL;
+
+ qmp_backup_cancel(&error);
+
+ hmp_handle_error(mon, &error);
+}
+
+void hmp_backup(Monitor *mon, const QDict *qdict)
+{
+ Error *error = NULL;
+
+ const char *backup_file = qdict_get_str(qdict, "backupfile");
+ const char *devlist = qdict_get_try_str(qdict, "devlist");
+ int64_t speed = qdict_get_try_int(qdict, "speed", 0);
+
+ qmp_backup(backup_file, true, BACKUP_FORMAT_VMA, false, NULL, !!devlist,
+ devlist, qdict_haskey(qdict, "speed"), speed, &error);
+
+ hmp_handle_error(mon, &error);
+}
+
void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
{
Error *error = NULL;
diff --git a/hmp.h b/hmp.h
index 0876ec0..9a4c1f6 100644
--- a/hmp.h
+++ b/hmp.h
@@ -30,6 +30,7 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict);
void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict);
void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict);
void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict);
+void hmp_info_backup(Monitor *mon, const QDict *qdict);
void hmp_info_cpus(Monitor *mon, const QDict *qdict);
void hmp_info_block(Monitor *mon, const QDict *qdict);
void hmp_info_blockstats(Monitor *mon, const QDict *qdict);
@@ -76,6 +77,8 @@ void hmp_eject(Monitor *mon, const QDict *qdict);
void hmp_change(Monitor *mon, const QDict *qdict);
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
void hmp_block_stream(Monitor *mon, const QDict *qdict);
+void hmp_backup(Monitor *mon, const QDict *qdict);
+void hmp_backup_cancel(Monitor *mon, const QDict *qdict);
void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
void hmp_block_job_pause(Monitor *mon, const QDict *qdict);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index db4650e..0f79b51 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -59,7 +59,7 @@
#define BLOCK_PROBE_BUF_SIZE 512
-typedef int BackupDumpFunc(void *opaque, BlockDriverState *bs,
+typedef int BackupDumpFunc(void *opaque, BlockBackend *be,
int64_t sector_num, int n_sectors, unsigned char *buf);
enum BdrvTrackedRequestType {
diff --git a/qapi-schema.json b/qapi-schema.json
index 518c2ea..89d9ea6 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -356,6 +356,95 @@
##
{ 'command': 'query-events', 'returns': ['EventInfo'] }
+# @BackupStatus:
+#
+# Detailed backup status.
+#
+# @status: #optional string describing the current backup status.
+# This can be 'active', 'done', 'error'. If this field is not
+# returned, no backup process has been initiated
+#
+# @errmsg: #optional error message (only returned if status is 'error')
+#
+# @total: #optional total amount of bytes involved in the backup process
+#
+# @transferred: #optional amount of bytes already backed up.
+#
+# @zero-bytes: #optional amount of 'zero' bytes detected.
+#
+# @start-time: #optional time (epoch) when backup job started.
+#
+# @end-time: #optional time (epoch) when backup job finished.
+#
+# @backupfile: #optional backup file name
+#
+# @uuid: #optional uuid for this backup job
+#
+##
+{ 'struct': 'BackupStatus',
+ 'data': {'*status': 'str', '*errmsg': 'str', '*total': 'int',
+ '*transferred': 'int', '*zero-bytes': 'int',
+ '*start-time': 'int', '*end-time': 'int',
+ '*backup-file': 'str', '*uuid': 'str' } }
+
+##
+# @BackupFormat
+#
+# An enumeration of supported backup formats.
+#
+# @vma: Proxmox vma backup format
+##
+{ 'enum': 'BackupFormat',
+ 'data': [ 'vma' ] }
+
+##
+# @backup:
+#
+# Starts a VM backup.
+#
+# @backup-file: the backup file name
+#
+# @format: format of the backup file
+#
+# @config-filename: #optional name of a configuration file to include into
+# the backup archive.
+#
+# @speed: #optional the maximum speed, in bytes per second
+#
+# @devlist: #optional list of block device names (separated by ',', ';'
+# or ':'). By default the backup includes all writable block devices.
+#
+# Returns: the uuid of the backup job
+#
+##
+{ 'command': 'backup', 'data': { 'backup-file': 'str',
+ '*format': 'BackupFormat',
+ '*config-file': 'str',
+ '*devlist': 'str', '*speed': 'int' },
+ 'returns': 'UuidInfo' }
+
+##
+# @query-backup
+#
+# Returns information about current/last backup task.
+#
+# Returns: @BackupStatus
+#
+##
+{ 'command': 'query-backup', 'returns': 'BackupStatus' }
+
+##
+# @backup-cancel
+#
+# Cancel the current executing backup process.
+#
+# Returns: nothing on success
+#
+# Notes: This command succeeds even if there is no backup process running.
+#
+##
+{ 'command': 'backup-cancel' }
+
##
# @MigrationStats
#
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 6de28d4..a8e8522 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1314,6 +1314,24 @@ Example:
EQMP
{
+ .name = "backup",
+ .args_type = "backup-file:s,format:s?,config-file:F?,speed:o?,devlist:s?",
+ .mhandler.cmd_new = qmp_marshal_backup,
+ },
+
+ {
+ .name = "backup-cancel",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_backup_cancel,
+ },
+
+ {
+ .name = "query-backup",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_query_backup,
+ },
+
+ {
.name = "block-job-set-speed",
.args_type = "device:B,speed:o",
.mhandler.cmd_new = qmp_marshal_block_job_set_speed,
--
2.1.4

View File

@ -0,0 +1,286 @@
From 210be0fc498989e7b029de90b9d2599fdcc343d3 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 15:21:54 +0100
Subject: [PATCH 16/47] backup: vma: add dir format
---
blockdev.c | 124 +++++++++++++++++++++++++++++++++++++++++--------------
hmp-commands.hx | 8 ++--
hmp.c | 4 +-
qapi-schema.json | 2 +-
vma.c | 2 +-
5 files changed, 103 insertions(+), 37 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 5417bb0..d8b1db8 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3001,6 +3001,8 @@ typedef struct PVEBackupDevInfo {
uint8_t dev_id;
//bool started;
bool completed;
+ char targetfile[PATH_MAX];
+ BlockDriverState *target;
} PVEBackupDevInfo;
static void pvebackup_run_next_job(void);
@@ -3069,8 +3071,6 @@ static void pvebackup_complete_cb(void *opaque, int ret)
{
PVEBackupDevInfo *di = opaque;
- assert(backup_state.vmaw);
-
di->completed = true;
if (ret < 0 && !backup_state.error) {
@@ -3081,8 +3081,11 @@ static void pvebackup_complete_cb(void *opaque, int ret)
BlockDriverState *bs = di->bs;
di->bs = NULL;
+ di->target = NULL;
- vma_writer_close_stream(backup_state.vmaw, di->dev_id);
+ if (backup_state.vmaw) {
+ vma_writer_close_stream(backup_state.vmaw, di->dev_id);
+ }
block_job_cb(bs, ret);
@@ -3162,6 +3165,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
{
BlockBackend *blk;
BlockDriverState *bs = NULL;
+ const char *backup_dir = NULL;
Error *local_err = NULL;
uuid_t uuid;
VmaWriter *vmaw = NULL;
@@ -3179,11 +3183,6 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
/* Todo: try to auto-detect format based on file name */
format = has_format ? format : BACKUP_FORMAT_VMA;
- if (format != BACKUP_FORMAT_VMA) {
- error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format");
- return NULL;
- }
-
if (has_devlist) {
devs = g_strsplit_set(devlist, ",;:", -1);
@@ -3252,27 +3251,62 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
uuid_generate(uuid);
- vmaw = vma_writer_create(backup_file, uuid, &local_err);
- if (!vmaw) {
- if (local_err) {
- error_propagate(errp, local_err);
+ if (format == BACKUP_FORMAT_VMA) {
+ vmaw = vma_writer_create(backup_file, uuid, &local_err);
+ if (!vmaw) {
+ if (local_err) {
+ error_propagate(errp, local_err);
+ }
+ goto err;
}
- goto err;
- }
- /* register all devices for vma writer */
- l = di_list;
- while (l) {
- PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
- l = g_list_next(l);
+ /* register all devices for vma writer */
+ l = di_list;
+ while (l) {
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
+ l = g_list_next(l);
- const char *devname = bdrv_get_device_name(di->bs);
- di->dev_id = vma_writer_register_stream(vmaw, devname, di->size);
- if (di->dev_id <= 0) {
- error_set(errp, ERROR_CLASS_GENERIC_ERROR,
- "register_stream failed");
+ const char *devname = bdrv_get_device_name(di->bs);
+ di->dev_id = vma_writer_register_stream(vmaw, devname, di->size);
+ if (di->dev_id <= 0) {
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+ "register_stream failed");
+ goto err;
+ }
+ }
+ } else if (format == BACKUP_FORMAT_DIR) {
+ if (mkdir(backup_file, 0640) != 0) {
+ error_setg_errno(errp, errno, "can't create directory '%s'\n",
+ backup_file);
goto err;
}
+ backup_dir = backup_file;
+
+ l = di_list;
+ while (l) {
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
+ l = g_list_next(l);
+
+ const char *devname = bdrv_get_device_name(di->bs);
+ snprintf(di->targetfile, PATH_MAX, "%s/%s.raw", backup_dir, devname);
+
+ int flags = BDRV_O_RDWR;
+ bdrv_img_create(di->targetfile, "raw", NULL, NULL, NULL,
+ di->size, flags, &local_err, false);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto err;
+ }
+
+ di->target = bdrv_open(di->targetfile, NULL, NULL, flags, &local_err);
+ if (!di->target) {
+ error_propagate(errp, local_err);
+ goto err;
+ }
+ }
+ } else {
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format");
+ goto err;
}
/* add configuration file to archive */
@@ -3285,12 +3319,27 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
goto err;
}
- const char *basename = g_path_get_basename(config_file);
- if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) {
- error_setg(errp, "unable to add config data to vma archive");
- g_free(cdata);
- goto err;
+ char *basename = g_path_get_basename(config_file);
+
+ if (format == BACKUP_FORMAT_VMA) {
+ if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) {
+ error_setg(errp, "unable to add config data to vma archive");
+ g_free(cdata);
+ g_free(basename);
+ goto err;
+ }
+ } else if (format == BACKUP_FORMAT_DIR) {
+ char config_path[PATH_MAX];
+ snprintf(config_path, PATH_MAX, "%s/%s", backup_dir, basename);
+ if (!g_file_set_contents(config_path, cdata, clen, &err)) {
+ error_setg(errp, "unable to write config file '%s'", config_path);
+ g_free(cdata);
+ g_free(basename);
+ goto err;
+ }
}
+
+ g_free(basename);
g_free(cdata);
}
@@ -3330,7 +3379,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
l = g_list_next(l);
- backup_start(NULL, di->bs, NULL, speed, MIRROR_SYNC_MODE_FULL, NULL,
+ backup_start(NULL, di->bs, di->target, speed, MIRROR_SYNC_MODE_FULL, NULL,
BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
pvebackup_dump_cb, pvebackup_complete_cb, di,
1, NULL, &local_err);
@@ -3352,8 +3401,17 @@ err:
l = di_list;
while (l) {
- g_free(l->data);
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
l = g_list_next(l);
+
+ if (di->target) {
+ bdrv_unref(di->target);
+ }
+
+ if (di->targetfile[0]) {
+ unlink(di->targetfile);
+ }
+ g_free(di);
}
g_list_free(di_list);
@@ -3367,6 +3425,10 @@ err:
unlink(backup_file);
}
+ if (backup_dir) {
+ rmdir(backup_dir);
+ }
+
return NULL;
}
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 8f2f3e0..0e20ef9 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -89,9 +89,11 @@ ETEXI
{
.name = "backup",
- .args_type = "backupfile:s,speed:o?,devlist:s?",
- .params = "backupfile [speed [devlist]]",
- .help = "create a VM Backup.",
+ .args_type = "directory:-d,backupfile:s,speed:o?,devlist:s?",
+ .params = "[-d] backupfile [speed [devlist]]",
+ .help = "create a VM Backup."
+ "\n\t\t\t Use -d to dump data into a directory instead"
+ "\n\t\t\t of using VMA format.",
.mhandler.cmd = hmp_backup,
},
diff --git a/hmp.c b/hmp.c
index 95da164..c23cf2f 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1544,11 +1544,13 @@ void hmp_backup(Monitor *mon, const QDict *qdict)
{
Error *error = NULL;
+ int dir = qdict_get_try_bool(qdict, "directory", 0);
const char *backup_file = qdict_get_str(qdict, "backupfile");
const char *devlist = qdict_get_try_str(qdict, "devlist");
int64_t speed = qdict_get_try_int(qdict, "speed", 0);
- qmp_backup(backup_file, true, BACKUP_FORMAT_VMA, false, NULL, !!devlist,
+ qmp_backup(backup_file, true, dir ? BACKUP_FORMAT_DIR : BACKUP_FORMAT_VMA,
+ false, NULL, !!devlist,
devlist, qdict_haskey(qdict, "speed"), speed, &error);
hmp_handle_error(mon, &error);
diff --git a/qapi-schema.json b/qapi-schema.json
index 89d9ea6..147137d 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -395,7 +395,7 @@
# @vma: Proxmox vma backup format
##
{ 'enum': 'BackupFormat',
- 'data': [ 'vma' ] }
+ 'data': [ 'vma', 'dir' ] }
##
# @backup:
diff --git a/vma.c b/vma.c
index 79bdd00..c88a4358 100644
--- a/vma.c
+++ b/vma.c
@@ -263,7 +263,7 @@ static int extract_content(int argc, char **argv)
g_free(statefn);
} else if (di) {
char *devfn = NULL;
- int flags = BDRV_O_RDWR|BDRV_O_CACHE_WB;
+ int flags = BDRV_O_RDWR;
bool write_zero = true;
if (readmap) {
--
2.1.4

View File

@ -0,0 +1,77 @@
From 8a10cce2efa3d8906617939a5c644c9cb7104ef6 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 15:22:19 +0100
Subject: [PATCH 17/47] backup: do not return errors in dump callback
---
blockdev.c | 26 ++++++++++++++++++++------
1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index d8b1db8..fb71cdc 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3013,6 +3013,11 @@ static int pvebackup_dump_cb(void *opaque, BlockBackend *target,
{
PVEBackupDevInfo *di = opaque;
+ int size = n_sectors * BDRV_SECTOR_SIZE;
+ if (backup_state.cancel) {
+ return size; // return success
+ }
+
if (sector_num & 0x7f) {
if (!backup_state.error) {
error_setg(&backup_state.error,
@@ -3023,7 +3028,6 @@ static int pvebackup_dump_cb(void *opaque, BlockBackend *target,
}
int64_t cluster_num = sector_num >> 7;
- int size = n_sectors * BDRV_SECTOR_SIZE;
int ret = -1;
@@ -3031,17 +3035,27 @@ static int pvebackup_dump_cb(void *opaque, BlockBackend *target,
size_t zero_bytes = 0;
ret = vma_writer_write(backup_state.vmaw, di->dev_id, cluster_num,
buf, &zero_bytes);
- backup_state.zero_bytes += zero_bytes;
+ if (ret < 0) {
+ if (!backup_state.error) {
+ error_setg(&backup_state.error, "vma_writer_write error %d", ret);
+ }
+ if (di->bs && di->bs->job) {
+ block_job_cancel(di->bs->job);
+ }
+ } else {
+ backup_state.zero_bytes += zero_bytes;
+ backup_state.transferred += size;
+ }
} else {
- ret = size;
if (!buf) {
backup_state.zero_bytes += size;
}
+ backup_state.transferred += size;
}
- backup_state.transferred += size;
+ // Note: always return success, because we want that writes succeed anyways.
- return ret;
+ return size;
}
static void pvebackup_cleanup(void)
@@ -3113,7 +3127,7 @@ static void pvebackup_cancel(void *opaque)
BlockJob *job = di->bs->job;
if (job) {
if (!di->completed) {
- block_job_cancel_sync(job);
+ block_job_cancel_sync(job);
}
}
}
--
2.1.4

View File

@ -0,0 +1,57 @@
From c31ba8ff9485b7648ca45952b9e7ccd74c50ac40 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 15:39:36 +0100
Subject: [PATCH 18/47] backup: vma: correctly propagate error
---
blockdev.c | 2 +-
vma-writer.c | 7 +++++++
vma.h | 1 +
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/blockdev.c b/blockdev.c
index fb71cdc..2e51913 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3037,7 +3037,7 @@ static int pvebackup_dump_cb(void *opaque, BlockBackend *target,
buf, &zero_bytes);
if (ret < 0) {
if (!backup_state.error) {
- error_setg(&backup_state.error, "vma_writer_write error %d", ret);
+ vma_writer_error_propagate(backup_state.vmaw, &backup_state.error);
}
if (di->bs && di->bs->job) {
block_job_cancel(di->bs->job);
diff --git a/vma-writer.c b/vma-writer.c
index b0cf529..689e988 100644
--- a/vma-writer.c
+++ b/vma-writer.c
@@ -792,6 +792,13 @@ vma_writer_write(VmaWriter *vmaw, uint8_t dev_id, int64_t cluster_num,
return transferred;
}
+void vma_writer_error_propagate(VmaWriter *vmaw, Error **errp)
+{
+ if (vmaw->status < 0 && *errp == NULL) {
+ error_setg(errp, "%s", vmaw->errmsg);
+ }
+}
+
int vma_writer_close(VmaWriter *vmaw, Error **errp)
{
g_assert(vmaw != NULL);
diff --git a/vma.h b/vma.h
index 9bb6ea4..98377e4 100644
--- a/vma.h
+++ b/vma.h
@@ -116,6 +116,7 @@ typedef struct VmaDeviceInfo {
VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, Error **errp);
int vma_writer_close(VmaWriter *vmaw, Error **errp);
+void vma_writer_error_propagate(VmaWriter *vmaw, Error **errp);
void vma_writer_destroy(VmaWriter *vmaw);
int vma_writer_add_config(VmaWriter *vmaw, const char *name, gpointer data,
size_t len);
--
2.1.4

View File

@ -0,0 +1,317 @@
From fb3d52b336cd8404055bf0b3b8d825c6f5247fef Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 15:40:00 +0100
Subject: [PATCH 19/47] backup: vma: remove async queue
---
blockdev.c | 6 ++
vma-writer.c | 179 +++++++++++------------------------------------------------
2 files changed, 38 insertions(+), 147 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 2e51913..1491c2d 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3116,6 +3116,11 @@ static void pvebackup_cancel(void *opaque)
error_setg(&backup_state.error, "backup cancelled");
}
+ if (backup_state.vmaw) {
+ /* make sure vma writer does not block anymore */
+ vma_writer_set_error(backup_state.vmaw, "backup cancelled");
+ }
+
/* drain all i/o (awake jobs waiting for aio) */
bdrv_drain_all();
@@ -3128,6 +3133,7 @@ static void pvebackup_cancel(void *opaque)
if (job) {
if (!di->completed) {
block_job_cancel_sync(job);
+ bdrv_drain_all(); /* drain all i/o (awake jobs waiting for aio) */
}
}
}
diff --git a/vma-writer.c b/vma-writer.c
index 689e988..6d3119d 100644
--- a/vma-writer.c
+++ b/vma-writer.c
@@ -28,14 +28,8 @@
do { if (DEBUG_VMA) { printf("vma: " fmt, ## __VA_ARGS__); } } while (0)
#define WRITE_BUFFERS 5
-
-typedef struct VmaAIOCB VmaAIOCB;
-struct VmaAIOCB {
- unsigned char buffer[VMA_MAX_EXTENT_SIZE];
- VmaWriter *vmaw;
- size_t bytes;
- Coroutine *co;
-};
+#define HEADER_CLUSTERS 8
+#define HEADERBUF_SIZE (VMA_CLUSTER_SIZE*HEADER_CLUSTERS)
struct VmaWriter {
int fd;
@@ -47,16 +41,14 @@ struct VmaWriter {
bool closed;
/* we always write extents */
- unsigned char outbuf[VMA_MAX_EXTENT_SIZE];
+ unsigned char *outbuf;
int outbuf_pos; /* in bytes */
int outbuf_count; /* in VMA_BLOCKS */
uint64_t outbuf_block_info[VMA_BLOCKS_PER_EXTENT];
- VmaAIOCB *aiocbs[WRITE_BUFFERS];
- CoQueue wqueue;
+ unsigned char *headerbuf;
GChecksum *md5csum;
- CoMutex writer_lock;
CoMutex flush_lock;
Coroutine *co_writer;
@@ -217,38 +209,39 @@ static void vma_co_continue_write(void *opaque)
}
static ssize_t coroutine_fn
-vma_co_write(VmaWriter *vmaw, const void *buf, size_t bytes)
+vma_queue_write(VmaWriter *vmaw, const void *buf, size_t bytes)
{
- size_t done = 0;
- ssize_t ret;
+ DPRINTF("vma_queue_write enter %zd\n", bytes);
- /* atomic writes (we cannot interleave writes) */
- qemu_co_mutex_lock(&vmaw->writer_lock);
+ assert(vmaw);
+ assert(buf);
+ assert(bytes <= VMA_MAX_EXTENT_SIZE);
- DPRINTF("vma_co_write enter %zd\n", bytes);
+ size_t done = 0;
+ ssize_t ret;
assert(vmaw->co_writer == NULL);
vmaw->co_writer = qemu_coroutine_self();
- aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, vma_co_continue_write, vmaw);
-
- DPRINTF("vma_co_write wait until writable\n");
- qemu_coroutine_yield();
- DPRINTF("vma_co_write starting %zd\n", bytes);
-
while (done < bytes) {
+ aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, vma_co_continue_write, vmaw);
+ qemu_coroutine_yield();
+ aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, NULL, NULL);
+ if (vmaw->status < 0) {
+ DPRINTF("vma_queue_write detected canceled backup\n");
+ done = -1;
+ break;
+ }
ret = write(vmaw->fd, buf + done, bytes - done);
if (ret > 0) {
done += ret;
- DPRINTF("vma_co_write written %zd %zd\n", done, ret);
+ DPRINTF("vma_queue_write written %zd %zd\n", done, ret);
} else if (ret < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
- DPRINTF("vma_co_write yield %zd\n", done);
- qemu_coroutine_yield();
- DPRINTF("vma_co_write restart %zd\n", done);
- } else {
- vma_writer_set_error(vmaw, "vma_co_write write error - %s",
+ /* try again */
+ } else {
+ vma_writer_set_error(vmaw, "vma_queue_write: write error - %s",
g_strerror(errno));
done = -1; /* always return failure for partial writes */
break;
@@ -258,102 +251,9 @@ vma_co_write(VmaWriter *vmaw, const void *buf, size_t bytes)
}
}
- aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, NULL, NULL);
-
vmaw->co_writer = NULL;
-
- qemu_co_mutex_unlock(&vmaw->writer_lock);
-
- DPRINTF("vma_co_write leave %zd\n", done);
- return done;
-}
-
-static void coroutine_fn vma_co_writer_task(void *opaque)
-{
- VmaAIOCB *cb = opaque;
-
- DPRINTF("vma_co_writer_task start\n");
-
- int64_t done = vma_co_write(cb->vmaw, cb->buffer, cb->bytes);
- DPRINTF("vma_co_writer_task write done %zd\n", done);
-
- if (done != cb->bytes) {
- DPRINTF("vma_co_writer_task failed write %zd %zd", cb->bytes, done);
- vma_writer_set_error(cb->vmaw, "vma_co_writer_task failed write %zd",
- done);
- }
-
- cb->bytes = 0;
-
- qemu_co_queue_next(&cb->vmaw->wqueue);
-
- DPRINTF("vma_co_writer_task end\n");
-}
-
-static void coroutine_fn vma_queue_flush(VmaWriter *vmaw)
-{
- DPRINTF("vma_queue_flush enter\n");
-
- assert(vmaw);
-
- while (1) {
- int i;
- VmaAIOCB *cb = NULL;
- for (i = 0; i < WRITE_BUFFERS; i++) {
- if (vmaw->aiocbs[i]->bytes) {
- cb = vmaw->aiocbs[i];
- DPRINTF("FOUND USED AIO BUFFER %d %zd\n", i,
- vmaw->aiocbs[i]->bytes);
- break;
- }
- }
- if (!cb) {
- break;
- }
- qemu_co_queue_wait(&vmaw->wqueue);
- }
-
- DPRINTF("vma_queue_flush leave\n");
-}
-
-/**
- * NOTE: pipe buffer size in only 4096 bytes on linux (see 'ulimit -a')
- * So we need to create a coroutione to allow 'parallel' execution.
- */
-static ssize_t coroutine_fn
-vma_queue_write(VmaWriter *vmaw, const void *buf, size_t bytes)
-{
- DPRINTF("vma_queue_write enter %zd\n", bytes);
-
- assert(vmaw);
- assert(buf);
- assert(bytes <= VMA_MAX_EXTENT_SIZE);
-
- VmaAIOCB *cb = NULL;
- while (!cb) {
- int i;
- for (i = 0; i < WRITE_BUFFERS; i++) {
- if (!vmaw->aiocbs[i]->bytes) {
- cb = vmaw->aiocbs[i];
- break;
- }
- }
- if (!cb) {
- qemu_co_queue_wait(&vmaw->wqueue);
- }
- }
-
- memcpy(cb->buffer, buf, bytes);
- cb->bytes = bytes;
- cb->vmaw = vmaw;
-
- DPRINTF("vma_queue_write start %zd\n", bytes);
- cb->co = qemu_coroutine_create(vma_co_writer_task);
- qemu_coroutine_enter(cb->co, cb);
-
- DPRINTF("vma_queue_write leave\n");
-
- return bytes;
+
+ return (done == bytes) ? bytes : -1;
}
VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, Error **errp)
@@ -420,20 +320,16 @@ VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, Error **errp)
}
/* we use O_DIRECT, so we need to align IO buffers */
- int i;
- for (i = 0; i < WRITE_BUFFERS; i++) {
- vmaw->aiocbs[i] = qemu_memalign(512, sizeof(VmaAIOCB));
- memset(vmaw->aiocbs[i], 0, sizeof(VmaAIOCB));
- }
+
+ vmaw->outbuf = qemu_memalign(512, VMA_MAX_EXTENT_SIZE);
+ vmaw->headerbuf = qemu_memalign(512, HEADERBUF_SIZE);
vmaw->outbuf_count = 0;
vmaw->outbuf_pos = VMA_EXTENT_HEADER_SIZE;
vmaw->header_blob_table_pos = 1; /* start at pos 1 */
- qemu_co_mutex_init(&vmaw->writer_lock);
qemu_co_mutex_init(&vmaw->flush_lock);
- qemu_co_queue_init(&vmaw->wqueue);
uuid_copy(vmaw->uuid, uuid);
@@ -460,8 +356,7 @@ err:
static int coroutine_fn vma_write_header(VmaWriter *vmaw)
{
assert(vmaw);
- int header_clusters = 8;
- char buf[65536*header_clusters];
+ unsigned char *buf = vmaw->headerbuf;
VmaHeader *head = (VmaHeader *)buf;
int i;
@@ -472,7 +367,7 @@ static int coroutine_fn vma_write_header(VmaWriter *vmaw)
return vmaw->status;
}
- memset(buf, 0, sizeof(buf));
+ memset(buf, 0, HEADERBUF_SIZE);
head->magic = VMA_MAGIC;
head->version = GUINT32_TO_BE(1); /* v1 */
@@ -507,7 +402,7 @@ static int coroutine_fn vma_write_header(VmaWriter *vmaw)
uint32_t header_size = sizeof(VmaHeader) + vmaw->header_blob_table_size;
head->header_size = GUINT32_TO_BE(header_size);
- if (header_size > sizeof(buf)) {
+ if (header_size > HEADERBUF_SIZE) {
return -1; /* just to be sure */
}
@@ -805,13 +700,7 @@ int vma_writer_close(VmaWriter *vmaw, Error **errp)
int i;
- vma_queue_flush(vmaw);
-
- /* this should not happen - just to be sure */
- while (!qemu_co_queue_empty(&vmaw->wqueue)) {
- DPRINTF("vma_writer_close wait\n");
- co_aio_sleep_ns(qemu_get_aio_context(), QEMU_CLOCK_REALTIME, 1000000);
- }
+ assert(vmaw->co_writer == NULL);
if (vmaw->cmd) {
if (pclose(vmaw->cmd) < 0) {
@@ -869,9 +758,5 @@ void vma_writer_destroy(VmaWriter *vmaw)
g_checksum_free(vmaw->md5csum);
}
- for (i = 0; i < WRITE_BUFFERS; i++) {
- free(vmaw->aiocbs[i]);
- }
-
g_free(vmaw);
}
--
2.1.4

View File

@ -0,0 +1,56 @@
From 3e0869f3ef3fc5537d90d22cde89f1384b164e70 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 15:40:42 +0100
Subject: [PATCH 20/47] backup: vma: run flush inside coroutine
---
blockdev.c | 10 +++++++++-
vma-writer.c | 4 ++++
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/blockdev.c b/blockdev.c
index 1491c2d..f3c0c58 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3081,6 +3081,13 @@ static void pvebackup_cleanup(void)
}
}
+static void coroutine_fn backup_close_vma_stream(void *opaque)
+{
+ PVEBackupDevInfo *di = opaque;
+
+ vma_writer_close_stream(backup_state.vmaw, di->dev_id);
+}
+
static void pvebackup_complete_cb(void *opaque, int ret)
{
PVEBackupDevInfo *di = opaque;
@@ -3098,7 +3105,8 @@ static void pvebackup_complete_cb(void *opaque, int ret)
di->target = NULL;
if (backup_state.vmaw) {
- vma_writer_close_stream(backup_state.vmaw, di->dev_id);
+ Coroutine *co = qemu_coroutine_create(backup_close_vma_stream, di);
+ qemu_coroutine_enter(co);
}
block_job_cb(bs, ret);
diff --git a/vma-writer.c b/vma-writer.c
index 6d3119d..79b7fd4 100644
--- a/vma-writer.c
+++ b/vma-writer.c
@@ -700,6 +700,10 @@ int vma_writer_close(VmaWriter *vmaw, Error **errp)
int i;
+ while (vmaw->co_writer) {
+ aio_poll(qemu_get_aio_context(), true);
+ }
+
assert(vmaw->co_writer == NULL);
if (vmaw->cmd) {
--
2.1.4

View File

@ -0,0 +1,36 @@
From e7cf613192638f5ac24629961c4010a3b3575ad6 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 15:41:13 +0100
Subject: [PATCH 21/47] backup: do not use bdrv_drain_all
---
blockdev.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index f3c0c58..2371cf3 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3129,9 +3129,6 @@ static void pvebackup_cancel(void *opaque)
vma_writer_set_error(backup_state.vmaw, "backup cancelled");
}
- /* drain all i/o (awake jobs waiting for aio) */
- bdrv_drain_all();
-
GList *l = backup_state.di_list;
while (l) {
PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
@@ -3140,8 +3137,7 @@ static void pvebackup_cancel(void *opaque)
BlockJob *job = di->bs->job;
if (job) {
if (!di->completed) {
- block_job_cancel_sync(job);
- bdrv_drain_all(); /* drain all i/o (awake jobs waiting for aio) */
+ block_job_cancel_sync(job);
}
}
}
--
2.1.4

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,256 @@
From e9b9fd9156a6631998ec4b4254fe2e91859b340a Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 16:31:51 +0100
Subject: [PATCH 23/47] backup: vma: allow empty backups
---
vma-reader.c | 29 ++++++++++++-------------
vma-writer.c | 30 ++++++++++++++++----------
vma.c | 70 ++++++++++++++++++++++++++++++++++++------------------------
vma.h | 1 +
4 files changed, 76 insertions(+), 54 deletions(-)
diff --git a/vma-reader.c b/vma-reader.c
index 2aafb26..78f1de9 100644
--- a/vma-reader.c
+++ b/vma-reader.c
@@ -326,11 +326,6 @@ static int vma_reader_read_head(VmaReader *vmar, Error **errp)
}
}
- if (!count) {
- error_setg(errp, "vma does not contain data");
- return -1;
- }
-
for (i = 0; i < VMA_MAX_CONFIGS; i++) {
uint32_t name_ptr = GUINT32_FROM_BE(h->config_names[i]);
uint32_t data_ptr = GUINT32_FROM_BE(h->config_data[i]);
@@ -822,16 +817,20 @@ static int vma_reader_restore_full(VmaReader *vmar, int vmstate_fd,
}
if (verbose) {
- printf("total bytes read %zd, sparse bytes %zd (%.3g%%)\n",
- vmar->clusters_read*VMA_CLUSTER_SIZE,
- vmar->zero_cluster_data,
- (double)(100.0*vmar->zero_cluster_data)/
- (vmar->clusters_read*VMA_CLUSTER_SIZE));
-
- int64_t datasize = vmar->clusters_read*VMA_CLUSTER_SIZE-vmar->zero_cluster_data;
- if (datasize) { // this does not make sense for empty files
- printf("space reduction due to 4K zero blocks %.3g%%\n",
- (double)(100.0*vmar->partial_zero_cluster_data) / datasize);
+ if (vmar->clusters_read) {
+ printf("total bytes read %zd, sparse bytes %zd (%.3g%%)\n",
+ vmar->clusters_read*VMA_CLUSTER_SIZE,
+ vmar->zero_cluster_data,
+ (double)(100.0*vmar->zero_cluster_data)/
+ (vmar->clusters_read*VMA_CLUSTER_SIZE));
+
+ int64_t datasize = vmar->clusters_read*VMA_CLUSTER_SIZE-vmar->zero_cluster_data;
+ if (datasize) { // this does not make sense for empty files
+ printf("space reduction due to 4K zero blocks %.3g%%\n",
+ (double)(100.0*vmar->partial_zero_cluster_data) / datasize);
+ }
+ } else {
+ printf("vma archive contains no image data\n");
}
}
return ret;
diff --git a/vma-writer.c b/vma-writer.c
index 79b7fd4..0d26fc6 100644
--- a/vma-writer.c
+++ b/vma-writer.c
@@ -252,7 +252,7 @@ vma_queue_write(VmaWriter *vmaw, const void *buf, size_t bytes)
}
vmaw->co_writer = NULL;
-
+
return (done == bytes) ? bytes : -1;
}
@@ -376,10 +376,6 @@ static int coroutine_fn vma_write_header(VmaWriter *vmaw)
time_t ctime = time(NULL);
head->ctime = GUINT64_TO_BE(ctime);
- if (!vmaw->stream_count) {
- return -1;
- }
-
for (i = 0; i < VMA_MAX_CONFIGS; i++) {
head->config_names[i] = GUINT32_TO_BE(vmaw->config_names[i]);
head->config_data[i] = GUINT32_TO_BE(vmaw->config_data[i]);
@@ -496,6 +492,23 @@ static int vma_count_open_streams(VmaWriter *vmaw)
return open_drives;
}
+
+/**
+ * You need to call this if the vma archive does not contain
+ * any data stream.
+ */
+int coroutine_fn
+vma_writer_flush_output(VmaWriter *vmaw)
+{
+ qemu_co_mutex_lock(&vmaw->flush_lock);
+ int ret = vma_writer_flush(vmaw);
+ qemu_co_mutex_unlock(&vmaw->flush_lock);
+ if (ret < 0) {
+ vma_writer_set_error(vmaw, "vma_writer_flush_header failed");
+ }
+ return ret;
+}
+
/**
* all jobs should call this when there is no more data
* Returns: number of remaining stream (0 ==> finished)
@@ -523,12 +536,7 @@ vma_writer_close_stream(VmaWriter *vmaw, uint8_t dev_id)
if (open_drives <= 0) {
DPRINTF("vma_writer_set_status all drives completed\n");
- qemu_co_mutex_lock(&vmaw->flush_lock);
- int ret = vma_writer_flush(vmaw);
- qemu_co_mutex_unlock(&vmaw->flush_lock);
- if (ret < 0) {
- vma_writer_set_error(vmaw, "vma_writer_close_stream: flush failed");
- }
+ vma_writer_flush_output(vmaw);
}
return open_drives;
diff --git a/vma.c b/vma.c
index c88a4358..08e4725 100644
--- a/vma.c
+++ b/vma.c
@@ -27,7 +27,7 @@ static void help(void)
"\n"
"vma list <filename>\n"
"vma config <filename> [-c config]\n"
- "vma create <filename> [-c config] <archive> pathname ...\n"
+ "vma create <filename> [-c config] pathname ...\n"
"vma extract <filename> [-r <fifo>] <targetdir>\n"
"vma verify <filename> [-v]\n"
;
@@ -395,6 +395,18 @@ typedef struct BackupJob {
#define BACKUP_SECTORS_PER_CLUSTER (VMA_CLUSTER_SIZE / BDRV_SECTOR_SIZE)
+static void coroutine_fn backup_run_empty(void *opaque)
+{
+ VmaWriter *vmaw = (VmaWriter *)opaque;
+
+ vma_writer_flush_output(vmaw);
+
+ Error *err = NULL;
+ if (vma_writer_close(vmaw, &err) != 0) {
+ g_warning("vma_writer_close failed %s", error_get_pretty(err));
+ }
+}
+
static void coroutine_fn backup_run(void *opaque)
{
BackupJob *job = (BackupJob *)opaque;
@@ -468,8 +480,8 @@ static int create_archive(int argc, char **argv)
}
- /* make sure we have archive name and at least one path */
- if ((optind + 2) > argc) {
+ /* make sure we an archive name */
+ if ((optind + 1) > argc) {
help();
}
@@ -504,11 +516,11 @@ static int create_archive(int argc, char **argv)
l = g_list_next(l);
}
- int ind = 0;
+ int devcount = 0;
while (optind < argc) {
const char *path = argv[optind++];
char *devname = NULL;
- path = extract_devname(path, &devname, ind++);
+ path = extract_devname(path, &devname, devcount++);
Error *errp = NULL;
BlockDriverState *bs;
@@ -539,37 +551,39 @@ static int create_archive(int argc, char **argv)
int percent = 0;
int last_percent = -1;
- while (1) {
- main_loop_wait(false);
- vma_writer_get_status(vmaw, &vmastat);
+ if (devcount) {
+ while (1) {
+ main_loop_wait(false);
+ vma_writer_get_status(vmaw, &vmastat);
+
+ if (verbose) {
- if (verbose) {
+ uint64_t total = 0;
+ uint64_t transferred = 0;
+ uint64_t zero_bytes = 0;
- uint64_t total = 0;
- uint64_t transferred = 0;
- uint64_t zero_bytes = 0;
+ int i;
+ for (i = 0; i < 256; i++) {
+ if (vmastat.stream_info[i].size) {
+ total += vmastat.stream_info[i].size;
+ transferred += vmastat.stream_info[i].transferred;
+ zero_bytes += vmastat.stream_info[i].zero_bytes;
+ }
+ }
+ percent = (transferred*100)/total;
+ if (percent != last_percent) {
+ fprintf(stderr, "progress %d%% %zd/%zd %zd\n", percent,
+ transferred, total, zero_bytes);
+ fflush(stderr);
- int i;
- for (i = 0; i < 256; i++) {
- if (vmastat.stream_info[i].size) {
- total += vmastat.stream_info[i].size;
- transferred += vmastat.stream_info[i].transferred;
- zero_bytes += vmastat.stream_info[i].zero_bytes;
+ last_percent = percent;
}
}
- percent = (transferred*100)/total;
- if (percent != last_percent) {
- fprintf(stderr, "progress %d%% %zd/%zd %zd\n", percent,
- transferred, total, zero_bytes);
- fflush(stderr);
- last_percent = percent;
+ if (vmastat.closed) {
+ break;
}
}
-
- if (vmastat.closed) {
- break;
- }
} else {
Coroutine *co = qemu_coroutine_create(backup_run_empty, vmaw);
qemu_coroutine_enter(co);
diff --git a/vma.h b/vma.h
index 98377e4..365ceb2 100644
--- a/vma.h
+++ b/vma.h
@@ -128,6 +128,7 @@ int64_t coroutine_fn vma_writer_write(VmaWriter *vmaw, uint8_t dev_id,
size_t *zero_bytes);
int coroutine_fn vma_writer_close_stream(VmaWriter *vmaw, uint8_t dev_id);
+int coroutine_fn vma_writer_flush_output(VmaWriter *vmaw);
int vma_writer_get_status(VmaWriter *vmaw, VmaStatus *status);
void vma_writer_set_error(VmaWriter *vmaw, const char *fmt, ...);
--
2.1.4

View File

@ -0,0 +1,126 @@
From e933992419bd8da2689a527ae95000891e687a2d Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 16:34:41 +0100
Subject: [PATCH 24/47] qmp: add get_link_status
---
net/net.c | 27 +++++++++++++++++++++++++++
qapi-schema.json | 15 +++++++++++++++
qmp-commands.hx | 23 +++++++++++++++++++++++
scripts/qapi.py | 2 ++
4 files changed, 67 insertions(+)
diff --git a/net/net.c b/net/net.c
index 19b4d9e..5f890b7 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1362,6 +1362,33 @@ void hmp_info_network(Monitor *mon, const QDict *qdict)
}
}
+int64_t qmp_get_link_status(const char *name, Error **errp)
+{
+ NetClientState *ncs[MAX_QUEUE_NUM];
+ NetClientState *nc;
+ int queues;
+ bool ret;
+
+ queues = qemu_find_net_clients_except(name, ncs,
+ NET_CLIENT_DRIVER__MAX,
+ MAX_QUEUE_NUM);
+
+ if (queues == 0) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", name);
+ return (int64_t) -1;
+ }
+
+ nc = ncs[0];
+ ret = ncs[0]->link_down;
+
+ if (nc->peer->info->type == NET_CLIENT_DRIVER_NIC) {
+ ret = ncs[0]->peer->link_down;
+ }
+
+ return (int64_t) ret ? 0 : 1;
+}
+
void qmp_set_link(const char *name, bool up, Error **errp)
{
NetClientState *ncs[MAX_QUEUE_NUM];
diff --git a/qapi-schema.json b/qapi-schema.json
index 0c0faf7..d75e932 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1786,6 +1786,21 @@
{ 'command': 'set_link', 'data': {'name': 'str', 'up': 'bool'} }
##
+# @get_link_status
+#
+# Get the current link state of the nics or nic.
+#
+# @name: name of the nic you get the state of
+#
+# Return: If link is up 1
+# If link is down 0
+# If an error occure an empty string.
+#
+# Notes: this is an Proxmox VE extension and not offical part of Qemu.
+##
+{ 'command': 'get_link_status', 'data': {'name': 'str'}, 'returns': 'int'}
+
+##
# @balloon:
#
# Request the balloon driver to change its balloon size.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 6342cd2..a84932a 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1883,6 +1883,29 @@ Example:
EQMP
{
+ .name = "get_link_status",
+ .args_type = "name:s",
+ .mhandler.cmd_new = qmp_marshal_get_link_status,
+ },
+
+SQMP
+get_link_status
+--------
+
+Get the link status of a network adapter.
+
+Arguments:
+
+- "name": network device name (json-string)
+
+Example:
+
+-> { "execute": "get_link_status", "arguments": { "name": "e1000.0" } }
+<- { "return": {1} }
+
+EQMP
+
+ {
.name = "getfd",
.args_type = "fdname:s",
.params = "getfd name",
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 21bc32f..f900659 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -39,6 +39,8 @@ builtin_types = {
# Whitelist of commands allowed to return a non-dictionary
returns_whitelist = [
+ 'get_link_status',
+
# From QMP:
'human-monitor-command',
'qom-get',
--
2.1.4

View File

@ -0,0 +1,26 @@
From e1682387e4bed2357e1030933481ab63f648249b Mon Sep 17 00:00:00 2001
From: Alexandre Derumier <aderumier@odiso.com>
Date: Tue, 29 Sep 2015 15:37:44 +0200
Subject: [PATCH 25/47] smm_available = false
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
hw/i386/pc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index ba8a5a1..9c206fc 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -2084,7 +2084,7 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms)
if (tcg_enabled() || qtest_enabled()) {
smm_available = true;
} else if (kvm_enabled()) {
- smm_available = kvm_has_smm();
+ smm_available = false;
}
if (smm_available) {
--
2.1.4

View File

@ -0,0 +1,27 @@
From 017016151cb8f9a364f0b0006603772620966d5a Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 16:50:05 +0100
Subject: [PATCH 26/47] use whitespace between VERSION and PKGVERSION
Our kvm version parser expects a white space or comma after
the version string, see PVE::QemuServer::kvm_user_version()
---
vl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/vl.c b/vl.c
index c01b1b5..0b5a721 100644
--- a/vl.c
+++ b/vl.c
@@ -1920,7 +1920,7 @@ static void main_loop(void)
static void version(void)
{
- printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION ", "
+ printf("QEMU emulator version " QEMU_VERSION " " QEMU_PKGVERSION ", "
QEMU_COPYRIGHT "\n");
}
--
2.1.4

View File

@ -0,0 +1,158 @@
From 3400a70a51015f119c12d3600943baae97aabb0f Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 16:51:23 +0100
Subject: [PATCH 27/47] vma: add firewall
---
blockdev.c | 78 ++++++++++++++++++++++++++++++++++----------------------
hmp.c | 2 +-
qapi-schema.json | 1 +
qmp-commands.hx | 2 +-
4 files changed, 51 insertions(+), 32 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 2371cf3..bbb1502 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3157,6 +3157,44 @@ void qmp_backup_cancel(Error **errp)
}
}
+static int config_to_vma(const char *file, BackupFormat format,
+ const char *backup_dir, VmaWriter *vmaw,
+ Error **errp)
+{
+ char *cdata = NULL;
+ gsize clen = 0;
+ GError *err = NULL;
+ if (!g_file_get_contents(file, &cdata, &clen, &err)) {
+ error_setg(errp, "unable to read file '%s'", file);
+ return 1;
+ }
+
+ char *basename = g_path_get_basename(file);
+
+ if (format == BACKUP_FORMAT_VMA) {
+ if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) {
+ error_setg(errp, "unable to add %s config data to vma archive", file);
+ g_free(cdata);
+ g_free(basename);
+ return 1;
+ }
+ } else if (format == BACKUP_FORMAT_DIR) {
+ char config_path[PATH_MAX];
+ snprintf(config_path, PATH_MAX, "%s/%s", backup_dir, basename);
+ if (!g_file_set_contents(config_path, cdata, clen, &err)) {
+ error_setg(errp, "unable to write config file '%s'", config_path);
+ g_free(cdata);
+ g_free(basename);
+ return 1;
+ }
+ }
+
+ g_free(basename);
+ g_free(cdata);
+
+ return 0;
+}
+
bool block_job_should_pause(BlockJob *job);
static void pvebackup_run_next_job(void)
{
@@ -3184,6 +3222,7 @@ static void pvebackup_run_next_job(void)
UuidInfo *qmp_backup(const char *backup_file, bool has_format,
BackupFormat format,
bool has_config_file, const char *config_file,
+ bool has_firewall_file, const char *firewall_file,
bool has_devlist, const char *devlist,
bool has_speed, int64_t speed, Error **errp)
{
@@ -3335,38 +3374,17 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
/* add configuration file to archive */
if (has_config_file) {
- char *cdata = NULL;
- gsize clen = 0;
- GError *err = NULL;
- if (!g_file_get_contents(config_file, &cdata, &clen, &err)) {
- error_setg(errp, "unable to read file '%s'", config_file);
- goto err;
- }
-
- char *basename = g_path_get_basename(config_file);
-
- if (format == BACKUP_FORMAT_VMA) {
- if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) {
- error_setg(errp, "unable to add config data to vma archive");
- g_free(cdata);
- g_free(basename);
- goto err;
- }
- } else if (format == BACKUP_FORMAT_DIR) {
- char config_path[PATH_MAX];
- snprintf(config_path, PATH_MAX, "%s/%s", backup_dir, basename);
- if (!g_file_set_contents(config_path, cdata, clen, &err)) {
- error_setg(errp, "unable to write config file '%s'", config_path);
- g_free(cdata);
- g_free(basename);
- goto err;
- }
- }
-
- g_free(basename);
- g_free(cdata);
+ if(config_to_vma(config_file, format, backup_dir, vmaw, errp) != 0) {
+ goto err;
+ }
}
+ /* add firewall file to archive */
+ if (has_firewall_file) {
+ if(config_to_vma(firewall_file, format, backup_dir, vmaw, errp) != 0) {
+ goto err;
+ }
+ }
/* initialize global backup_state now */
backup_state.cancel = false;
diff --git a/hmp.c b/hmp.c
index 030fd97..5c5e8ed 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1550,7 +1550,7 @@ void hmp_backup(Monitor *mon, const QDict *qdict)
int64_t speed = qdict_get_try_int(qdict, "speed", 0);
qmp_backup(backup_file, true, dir ? BACKUP_FORMAT_DIR : BACKUP_FORMAT_VMA,
- false, NULL, !!devlist,
+ false, NULL, false, NULL, !!devlist,
devlist, qdict_haskey(qdict, "speed"), speed, &error);
hmp_handle_error(mon, &error);
diff --git a/qapi-schema.json b/qapi-schema.json
index d75e932..7bb0ee0 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -420,6 +420,7 @@
{ 'command': 'backup', 'data': { 'backup-file': 'str',
'*format': 'BackupFormat',
'*config-file': 'str',
+ '*firewall-file': 'str',
'*devlist': 'str', '*speed': 'int' },
'returns': 'UuidInfo' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index a84932a..94cfac2 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1315,7 +1315,7 @@ EQMP
{
.name = "backup",
- .args_type = "backup-file:s,format:s?,config-file:F?,speed:o?,devlist:s?",
+ .args_type = "backup-file:s,format:s?,config-file:F?,firewall-file:F?,speed:o?,devlist:s?",
.mhandler.cmd_new = qmp_marshal_backup,
},
--
2.1.4

View File

@ -0,0 +1,101 @@
From d5ef7dd4d2b53e4868289dca3770724cb9597ec5 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Thu, 10 Dec 2015 15:14:00 +0100
Subject: [PATCH 28/47] savevm-async: migration and bdrv_open update
---
savevm-async.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/savevm-async.c b/savevm-async.c
index ae7ea84..7979435 100644
--- a/savevm-async.c
+++ b/savevm-async.c
@@ -154,10 +154,10 @@ static int block_state_close(void *opaque)
return bdrv_flush(snap_state.bs);
}
-static int block_state_put_buffer(void *opaque, const uint8_t *buf,
- int64_t pos, int size)
+static ssize_t block_state_put_buffer(void *opaque, const uint8_t *buf,
+ int64_t pos, size_t size)
{
- int ret;
+ ssize_t ret;
assert(pos == snap_state.bs_pos);
@@ -201,12 +201,13 @@ static void process_savevm_co(void *opaque)
}
while (snap_state.state == SAVE_STATE_ACTIVE) {
- uint64_t pending_size;
+ uint64_t pending_size, pend_post, pend_nonpost;
- pending_size = qemu_savevm_state_pending(snap_state.file, 0);
+ qemu_savevm_state_pending(snap_state.file, 0, &pend_nonpost, &pend_post);
+ pending_size = pend_post + pend_nonpost;
if (pending_size) {
- ret = qemu_savevm_state_iterate(snap_state.file);
+ ret = qemu_savevm_state_iterate(snap_state.file, false);
if (ret < 0) {
save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
break;
@@ -217,7 +218,7 @@ static void process_savevm_co(void *opaque)
if (store_and_stop())
break;
DPRINTF("savevm inerate finished\n");
- qemu_savevm_state_complete_precopy(snap_state.file);
+ qemu_savevm_state_complete_precopy(snap_state.file, false);
DPRINTF("save complete\n");
save_snapshot_completed();
break;
@@ -250,7 +251,6 @@ static const QEMUFileOps block_file_ops = {
void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
{
- BlockDriver *drv = NULL;
Error *local_err = NULL;
int bdrv_oflags = BDRV_O_RDWR;
@@ -289,7 +289,7 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
QDict *options = NULL;
options = qdict_new();
qdict_put(options, "driver", qstring_from_str("raw"));
- ret = bdrv_open(&snap_state.bs, statefile, NULL, options, bdrv_oflags, drv, &local_err);
+ ret = bdrv_open(&snap_state.bs, statefile, NULL, options, bdrv_oflags, &local_err);
if (ret < 0) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR, "failed to open '%s'", statefile);
goto restart;
@@ -454,8 +454,8 @@ void qmp_delete_drive_snapshot(const char *device, const char *name,
}
}
-static int loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
- int size)
+static ssize_t loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
+ size_t size)
{
BlockDriverState *bs = (BlockDriverState *)opaque;
int64_t maxlen = bdrv_getlength(bs);
@@ -478,7 +478,6 @@ static const QEMUFileOps loadstate_file_ops = {
int load_state_from_blockdev(const char *filename)
{
BlockDriverState *bs = NULL;
- BlockDriver *drv = NULL;
Error *local_err = NULL;
Error *blocker = NULL;
@@ -486,7 +485,7 @@ int load_state_from_blockdev(const char *filename)
int ret;
bs = bdrv_new();
- ret = bdrv_open(&bs, filename, NULL, NULL, 0, drv, &local_err);
+ ret = bdrv_open(&bs, filename, NULL, NULL, 0, &local_err);
error_setg(&blocker, "block device is in use by load state");
bdrv_op_block_all(bs, blocker);
--
2.1.4

View File

@ -0,0 +1,28 @@
From d42052d75321a1af75b039f8e31127b98485ec93 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Tue, 12 Jan 2016 09:09:49 +0100
Subject: [PATCH 29/47] vnc: make x509 imply tls again
---
ui/vnc.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/ui/vnc.c b/ui/vnc.c
index b9f36b5..acbe3bd 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3729,9 +3729,8 @@ void vnc_display_open(const char *id, Error **errp)
const char *path;
bool tls = false, x509 = false, x509verify = false;
tls = qemu_opt_get_bool(opts, "tls", false);
- if (tls) {
- path = qemu_opt_get(opts, "x509");
-
+ path = qemu_opt_get(opts, "x509");
+ if (tls || path) {
if (path) {
x509 = true;
} else {
--
2.1.4

View File

@ -0,0 +1,683 @@
From 51dd4df80640e1671de73c014c6273b154df920a Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Mon, 11 Jan 2016 10:40:31 +0100
Subject: [PATCH 30/47] PVE VNC authentication
---
crypto/tlscreds.c | 47 +++++++++++
crypto/tlscredspriv.h | 2 +
crypto/tlscredsx509.c | 13 ++--
crypto/tlssession.c | 1 +
include/crypto/tlscreds.h | 1 +
include/ui/console.h | 1 +
qemu-options.hx | 3 +
ui/vnc-auth-vencrypt.c | 194 ++++++++++++++++++++++++++++++++++++++--------
ui/vnc.c | 140 ++++++++++++++++++++++++++++++++-
ui/vnc.h | 4 +
vl.c | 9 +++
11 files changed, 375 insertions(+), 40 deletions(-)
diff --git a/crypto/tlscreds.c b/crypto/tlscreds.c
index a896553..e9ae13c 100644
--- a/crypto/tlscreds.c
+++ b/crypto/tlscreds.c
@@ -158,6 +158,33 @@ qcrypto_tls_creds_prop_get_verify(Object *obj,
static void
+qcrypto_tls_creds_prop_set_pve(Object *obj,
+ bool value,
+ Error **errp G_GNUC_UNUSED)
+{
+ QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
+
+ creds->pve = value;
+}
+
+
+static bool
+qcrypto_tls_creds_prop_get_pve(Object *obj,
+ Error **errp G_GNUC_UNUSED)
+{
+ QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
+
+ return creds->pve;
+}
+
+bool qcrypto_tls_creds_is_pve(QCryptoTLSCreds *creds)
+{
+ Error *errp = NULL;
+ return qcrypto_tls_creds_prop_get_pve((Object*)creds, &errp);
+}
+
+
+static void
qcrypto_tls_creds_prop_set_dir(Object *obj,
const char *value,
Error **errp G_GNUC_UNUSED)
@@ -250,6 +277,26 @@ qcrypto_tls_creds_init(Object *obj)
QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
creds->verifyPeer = true;
+ creds->pve = false;
+
+ object_property_add_bool(obj, "verify-peer",
+ qcrypto_tls_creds_prop_get_verify,
+ qcrypto_tls_creds_prop_set_verify,
+ NULL);
+ object_property_add_bool(obj, "pve",
+ qcrypto_tls_creds_prop_get_pve,
+ qcrypto_tls_creds_prop_set_pve,
+ NULL);
+ object_property_add_str(obj, "dir",
+ qcrypto_tls_creds_prop_get_dir,
+ qcrypto_tls_creds_prop_set_dir,
+ NULL);
+ object_property_add_enum(obj, "endpoint",
+ "QCryptoTLSCredsEndpoint",
+ QCryptoTLSCredsEndpoint_lookup,
+ qcrypto_tls_creds_prop_get_endpoint,
+ qcrypto_tls_creds_prop_set_endpoint,
+ NULL);
}
diff --git a/crypto/tlscredspriv.h b/crypto/tlscredspriv.h
index 13e9b6c..0356acc 100644
--- a/crypto/tlscredspriv.h
+++ b/crypto/tlscredspriv.h
@@ -36,6 +36,8 @@ int qcrypto_tls_creds_get_dh_params_file(QCryptoTLSCreds *creds,
gnutls_dh_params_t *dh_params,
Error **errp);
+bool qcrypto_tls_creds_is_pve(QCryptoTLSCreds *creds);
+
#endif
#endif /* QCRYPTO_TLSCREDSPRIV_H */
diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c
index 520d34d..1ba971c 100644
--- a/crypto/tlscredsx509.c
+++ b/crypto/tlscredsx509.c
@@ -555,22 +555,23 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
*key = NULL, *dhparams = NULL;
int ret;
int rv = -1;
+ bool pve = qcrypto_tls_creds_is_pve(&creds->parent_obj);
trace_qcrypto_tls_creds_x509_load(creds,
creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
if (qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_CA_CERT,
+ pve ? "pve-root-ca.pem" : QCRYPTO_TLS_CREDS_X509_CA_CERT,
true, &cacert, errp) < 0 ||
qcrypto_tls_creds_get_path(&creds->parent_obj,
QCRYPTO_TLS_CREDS_X509_CA_CRL,
false, &cacrl, errp) < 0 ||
qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
+ pve ? "local/pve-ssl.pem" : QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
true, &cert, errp) < 0 ||
qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
+ pve ? "local/pve-ssl.key" : QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
true, &key, errp) < 0 ||
qcrypto_tls_creds_get_path(&creds->parent_obj,
QCRYPTO_TLS_CREDS_DH_PARAMS,
@@ -579,13 +580,13 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
}
} else {
if (qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_CA_CERT,
+ pve ? "pve-root-ca.pem" : QCRYPTO_TLS_CREDS_X509_CA_CERT,
true, &cacert, errp) < 0 ||
qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
+ pve ? "local/pve-ssl.pem" : QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
false, &cert, errp) < 0 ||
qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
+ pve ? "local/pve-ssl.key" : QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
false, &key, errp) < 0) {
goto cleanup;
}
diff --git a/crypto/tlssession.c b/crypto/tlssession.c
index 2de42c6..768466a 100644
--- a/crypto/tlssession.c
+++ b/crypto/tlssession.c
@@ -23,6 +23,7 @@
#include "crypto/tlscredsanon.h"
#include "crypto/tlscredsx509.h"
#include "qapi/error.h"
+#include "crypto/tlscredspriv.h"
#include "qemu/acl.h"
#include "trace.h"
diff --git a/include/crypto/tlscreds.h b/include/crypto/tlscreds.h
index ad47d88..f86d379 100644
--- a/include/crypto/tlscreds.h
+++ b/include/crypto/tlscreds.h
@@ -55,6 +55,7 @@ struct QCryptoTLSCreds {
#endif
bool verifyPeer;
char *priority;
+ bool pve;
};
diff --git a/include/ui/console.h b/include/ui/console.h
index 2703a3a..db6dd22 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -456,6 +456,7 @@ static inline void cocoa_display_init(DisplayState *ds, int full_screen)
#endif
/* vnc.c */
+void pve_auth_setup(int vmid);
void vnc_display_init(const char *id);
void vnc_display_open(const char *id, Error **errp);
void vnc_display_add_client(const char *id, int csock, bool skipauth);
diff --git a/qemu-options.hx b/qemu-options.hx
index 37fad3b..f943ae6 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -473,6 +473,9 @@ STEXI
@table @option
ETEXI
+DEF("id", HAS_ARG, QEMU_OPTION_id,
+ "-id n set the VMID\n", QEMU_ARCH_ALL)
+
DEF("fda", HAS_ARG, QEMU_OPTION_fda,
"-fda/-fdb file use 'file' as floppy disk 0/1 image\n", QEMU_ARCH_ALL)
DEF("fdb", HAS_ARG, QEMU_OPTION_fdb, "", QEMU_ARCH_ALL)
diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c
index 11c8c9a..d11f1df 100644
--- a/ui/vnc-auth-vencrypt.c
+++ b/ui/vnc-auth-vencrypt.c
@@ -28,6 +28,107 @@
#include "vnc.h"
#include "qapi/error.h"
#include "qemu/main-loop.h"
+#include "qemu/sockets.h"
+
+static int protocol_client_auth_plain(VncState *vs, uint8_t *data, size_t len)
+{
+ const char *err = NULL;
+ char username[256];
+ char passwd[512];
+
+ char clientip[256];
+ clientip[0] = 0;
+ struct sockaddr_in client;
+ socklen_t addrlen = sizeof(client);
+ if (getpeername(vs->csock, &client, &addrlen) == 0) {
+ inet_ntop(client.sin_family, &client.sin_addr,
+ clientip, sizeof(clientip));
+ }
+
+ if ((len != (vs->username_len + vs->password_len)) ||
+ (vs->username_len >= (sizeof(username)-1)) ||
+ (vs->password_len >= (sizeof(passwd)-1)) ) {
+ err = "Got unexpected data length";
+ goto err;
+ }
+
+ strncpy(username, (char *)data, vs->username_len);
+ username[vs->username_len] = 0;
+ strncpy(passwd, (char *)data + vs->username_len, vs->password_len);
+ passwd[vs->password_len] = 0;
+
+ VNC_DEBUG("AUTH PLAIN username: %s pw: %s\n", username, passwd);
+
+ if (pve_auth_verify(clientip, username, passwd) == 0) {
+ vnc_write_u32(vs, 0); /* Accept auth completion */
+ start_client_init(vs);
+ return 0;
+ }
+
+ err = "Authentication failed";
+err:
+ if (err) {
+ VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err);
+ vnc_write_u32(vs, 1); /* Reject auth */
+ if (vs->minor >= 8) {
+ int elen = strlen(err);
+ vnc_write_u32(vs, elen);
+ vnc_write(vs, err, elen);
+ }
+ }
+ vnc_flush(vs);
+ vnc_client_error(vs);
+
+ return 0;
+
+}
+
+static int protocol_client_auth_plain_start(VncState *vs, uint8_t *data, size_t len)
+{
+ uint32_t ulen = read_u32(data, 0);
+ uint32_t pwlen = read_u32(data, 4);
+ const char *err = NULL;
+
+ VNC_DEBUG("AUTH PLAIN START %u %u\n", ulen, pwlen);
+
+ if (!ulen) {
+ err = "No User name.";
+ goto err;
+ }
+ if (ulen >= 255) {
+ err = "User name too long.";
+ goto err;
+ }
+ if (!pwlen) {
+ err = "Password too short";
+ goto err;
+ }
+ if (pwlen >= 511) {
+ err = "Password too long.";
+ goto err;
+ }
+
+ vs->username_len = ulen;
+ vs->password_len = pwlen;
+
+ vnc_read_when(vs, protocol_client_auth_plain, ulen + pwlen);
+
+ return 0;
+err:
+ if (err) {
+ VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err);
+ vnc_write_u32(vs, 1); /* Reject auth */
+ if (vs->minor >= 8) {
+ int elen = strlen(err);
+ vnc_write_u32(vs, elen);
+ vnc_write(vs, err, elen);
+ }
+ }
+ vnc_flush(vs);
+ vnc_client_error(vs);
+
+ return 0;
+}
static void start_auth_vencrypt_subauth(VncState *vs)
{
@@ -39,6 +140,17 @@ static void start_auth_vencrypt_subauth(VncState *vs)
start_client_init(vs);
break;
+ case VNC_AUTH_VENCRYPT_TLSPLAIN:
+ case VNC_AUTH_VENCRYPT_X509PLAIN:
+ VNC_DEBUG("Start TLS auth PLAIN\n");
+ vnc_read_when(vs, protocol_client_auth_plain_start, 8);
+ break;
+
+ case VNC_AUTH_VENCRYPT_PLAIN:
+ VNC_DEBUG("Start auth PLAIN\n");
+ vnc_read_when(vs, protocol_client_auth_plain_start, 8);
+ break;
+
case VNC_AUTH_VENCRYPT_TLSVNC:
case VNC_AUTH_VENCRYPT_X509VNC:
VNC_DEBUG("Start TLS auth VNC\n");
@@ -87,44 +199,63 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len
{
int auth = read_u32(data, 0);
- if (auth != vs->subauth) {
+ if (auth != vs->subauth && auth != VNC_AUTH_VENCRYPT_PLAIN) {
VNC_DEBUG("Rejecting auth %d\n", auth);
vnc_write_u8(vs, 0); /* Reject auth */
vnc_flush(vs);
vnc_client_error(vs);
} else {
- Error *err = NULL;
- QIOChannelTLS *tls;
- VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
- vnc_write_u8(vs, 1); /* Accept auth */
- vnc_flush(vs);
-
- if (vs->ioc_tag) {
- g_source_remove(vs->ioc_tag);
- vs->ioc_tag = 0;
+ if (auth == VNC_AUTH_VENCRYPT_PLAIN) {
+ vs->subauth = auth;
+ start_auth_vencrypt_subauth(vs);
}
+ else
+ {
+ Error *err = NULL;
+ QIOChannelTLS *tls;
+ VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
+ vnc_write_u8(vs, 1); /* Accept auth */
+ vnc_flush(vs);
- tls = qio_channel_tls_new_server(
- vs->ioc,
- vs->vd->tlscreds,
- vs->vd->tlsaclname,
- &err);
- if (!tls) {
- VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
- error_free(err);
- vnc_client_error(vs);
- return 0;
- }
+ if (vs->ioc_tag) {
+ g_source_remove(vs->ioc_tag);
+ vs->ioc_tag = 0;
+ }
- VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
- object_unref(OBJECT(vs->ioc));
- vs->ioc = QIO_CHANNEL(tls);
- vs->tls = qio_channel_tls_get_session(tls);
+ tls = qio_channel_tls_new_server(
+ vs->ioc,
+ vs->vd->tlscreds,
+ vs->vd->tlsaclname,
+ &err);
+ if (!tls) {
+ VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
+ error_free(err);
+ vnc_client_error(vs);
+ return 0;
+ vs->tls = qcrypto_tls_session_new(vs->vd->tlscreds,
+ NULL,
+ vs->vd->tlsaclname,
+ QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
+ &err);
+ if (!vs->tls) {
+ VNC_DEBUG("Failed to setup TLS %s\n",
+ error_get_pretty(err));
+ error_free(err);
+ vnc_client_error(vs);
+ return 0;
+ }
+ }
- qio_channel_tls_handshake(tls,
- vnc_tls_handshake_done,
- vs,
- NULL);
+ VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
+ object_unref(OBJECT(vs->ioc));
+ vs->ioc = QIO_CHANNEL(tls);
+ vs->tls = qio_channel_tls_get_session(tls);
+
+ qio_channel_tls_handshake(tls,
+ vnc_tls_handshake_done,
+ vs,
+ NULL);
+ }
}
return 0;
}
@@ -138,10 +269,11 @@ static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len
vnc_flush(vs);
vnc_client_error(vs);
} else {
- VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
+ VNC_DEBUG("Sending allowed auths %d %d\n", vs->subauth, VNC_AUTH_VENCRYPT_PLAIN);
vnc_write_u8(vs, 0); /* Accept version */
- vnc_write_u8(vs, 1); /* Number of sub-auths */
+ vnc_write_u8(vs, 2); /* Number of sub-auths */
vnc_write_u32(vs, vs->subauth); /* The supported auth */
+ vnc_write_u32(vs, VNC_AUTH_VENCRYPT_PLAIN); /* Alternative supported auth */
vnc_flush(vs);
vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
}
diff --git a/ui/vnc.c b/ui/vnc.c
index acbe3bd..2a18a20 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -55,6 +55,125 @@ static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
#include "vnc_keysym.h"
#include "crypto/cipher.h"
+static int pve_vmid = 0;
+
+void pve_auth_setup(int vmid) {
+ pve_vmid = vmid;
+}
+
+static char *
+urlencode(char *buf, const char *value)
+{
+ static const char *hexchar = "0123456789abcdef";
+ char *p = buf;
+ int i;
+ int l = strlen(value);
+ for (i = 0; i < l; i++) {
+ char c = value[i];
+ if (('a' <= c && c <= 'z') ||
+ ('A' <= c && c <= 'Z') ||
+ ('0' <= c && c <= '9')) {
+ *p++ = c;
+ } else if (c == 32) {
+ *p++ = '+';
+ } else {
+ *p++ = '%';
+ *p++ = hexchar[c >> 4];
+ *p++ = hexchar[c & 15];
+ }
+ }
+ *p = 0;
+
+ return p;
+}
+
+int
+pve_auth_verify(const char *clientip, const char *username, const char *passwd)
+{
+ struct sockaddr_in server;
+
+ int sfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sfd == -1) {
+ perror("pve_auth_verify: socket failed");
+ return -1;
+ }
+
+ struct hostent *he;
+ if ((he = gethostbyname("localhost")) == NULL) {
+ fprintf(stderr, "pve_auth_verify: error resolving hostname\n");
+ goto err;
+ }
+
+ memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length);
+ server.sin_family = AF_INET;
+ server.sin_port = htons(85);
+
+ if (connect(sfd, (struct sockaddr *)&server, sizeof(server))) {
+ perror("pve_auth_verify: error connecting to server");
+ goto err;
+ }
+
+ char buf[8192];
+ char form[8192];
+
+ char *p = form;
+ p = urlencode(p, "username");
+ *p++ = '=';
+ p = urlencode(p, username);
+
+ *p++ = '&';
+ p = urlencode(p, "password");
+ *p++ = '=';
+ p = urlencode(p, passwd);
+
+ *p++ = '&';
+ p = urlencode(p, "path");
+ *p++ = '=';
+ char authpath[256];
+ sprintf(authpath, "/vms/%d", pve_vmid);
+ p = urlencode(p, authpath);
+
+ *p++ = '&';
+ p = urlencode(p, "privs");
+ *p++ = '=';
+ p = urlencode(p, "VM.Console");
+
+ sprintf(buf, "POST /api2/json/access/ticket HTTP/1.1\n"
+ "Host: localhost:85\n"
+ "Connection: close\n"
+ "PVEClientIP: %s\n"
+ "Content-Type: application/x-www-form-urlencoded\n"
+ "Content-Length: %zd\n\n%s\n", clientip, strlen(form), form);
+ ssize_t len = strlen(buf);
+ ssize_t sb = send(sfd, buf, len, 0);
+ if (sb < 0) {
+ perror("pve_auth_verify: send failed");
+ goto err;
+ }
+ if (sb != len) {
+ fprintf(stderr, "pve_auth_verify: partial send error\n");
+ goto err;
+ }
+
+ len = recv(sfd, buf, sizeof(buf) - 1, 0);
+ if (len < 0) {
+ perror("pve_auth_verify: recv failed");
+ goto err;
+ }
+
+ buf[len] = 0;
+
+ //printf("DATA:%s\n", buf);
+
+ shutdown(sfd, SHUT_RDWR);
+
+ return strncmp(buf, "HTTP/1.1 200 OK", 15);
+
+err:
+ shutdown(sfd, SHUT_RDWR);
+ return -1;
+}
+
static QTAILQ_HEAD(, VncDisplay) vnc_displays =
QTAILQ_HEAD_INITIALIZER(vnc_displays);
@@ -3413,11 +3532,17 @@ vnc_display_setup_auth(VncDisplay *vs,
if (object_dynamic_cast(OBJECT(vs->tlscreds),
TYPE_QCRYPTO_TLS_CREDS_X509)) {
VNC_DEBUG("Initializing VNC server with x509 password auth\n");
- vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
+ if (vs->tlscreds->pve)
+ vs->subauth = VNC_AUTH_VENCRYPT_X509PLAIN;
+ else
+ vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
} else if (object_dynamic_cast(OBJECT(vs->tlscreds),
TYPE_QCRYPTO_TLS_CREDS_ANON)) {
VNC_DEBUG("Initializing VNC server with TLS password auth\n");
- vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
+ if (vs->tlscreds->pve)
+ vs->subauth = VNC_AUTH_VENCRYPT_TLSPLAIN;
+ else
+ vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
} else {
error_setg(errp,
"Unsupported TLS cred type %s",
@@ -3508,6 +3633,7 @@ vnc_display_create_creds(bool x509,
bool x509verify,
const char *dir,
const char *id,
+ bool pve,
Error **errp)
{
gchar *credsid = g_strdup_printf("tlsvnc%s", id);
@@ -3523,6 +3649,7 @@ vnc_display_create_creds(bool x509,
"endpoint", "server",
"dir", dir,
"verify-peer", x509verify ? "yes" : "no",
+ "pve", pve ? "yes" : "no",
NULL);
} else {
creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_ANON,
@@ -3530,6 +3657,7 @@ vnc_display_create_creds(bool x509,
credsid,
&err,
"endpoint", "server",
+ "pve", pve ? "yes" : "no",
NULL);
}
@@ -3727,12 +3855,17 @@ void vnc_display_open(const char *id, Error **errp)
}
} else {
const char *path;
- bool tls = false, x509 = false, x509verify = false;
+ bool tls = false, x509 = false, x509verify = false, pve = false;
tls = qemu_opt_get_bool(opts, "tls", false);
path = qemu_opt_get(opts, "x509");
if (tls || path) {
if (path) {
x509 = true;
+ if (!strcmp(path, "on")) {
+ /* magic to default to /etc/pve */
+ path = "/etc/pve";
+ pve = true;
+ }
} else {
path = qemu_opt_get(opts, "x509verify");
if (path) {
@@ -3744,6 +3877,7 @@ void vnc_display_open(const char *id, Error **errp)
x509verify,
path,
vs->id,
+ pve,
errp);
if (!vs->tlscreds) {
goto fail;
diff --git a/ui/vnc.h b/ui/vnc.h
index ab5f244..2fde9d3 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -282,6 +282,8 @@ struct VncState
int auth;
int subauth; /* Used by VeNCrypt */
char challenge[VNC_AUTH_CHALLENGE_SIZE];
+ int username_len;
+ int password_len;
QCryptoTLSSession *tls; /* Borrowed pointer from channel, don't free */
#ifdef CONFIG_VNC_SASL
VncStateSASL sasl;
@@ -577,4 +579,6 @@ int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
void vnc_zrle_clear(VncState *vs);
+int pve_auth_verify(const char *clientip, const char *username, const char *passwd);
+
#endif /* QEMU_VNC_H */
diff --git a/vl.c b/vl.c
index 0b5a721..4742300 100644
--- a/vl.c
+++ b/vl.c
@@ -2950,6 +2950,7 @@ static int global_init_func(void *opaque, QemuOpts *opts, Error **errp)
int main(int argc, char **argv, char **envp)
{
int i;
+ long int vm_id_long = 0;
int snapshot, linux_boot;
const char *initrd_filename;
const char *kernel_filename, *kernel_cmdline;
@@ -3722,6 +3723,14 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
break;
+ case QEMU_OPTION_id:
+ vm_id_long = strtol(optarg, (char **) &optarg, 10);
+ if (*optarg != 0 || vm_id_long < 100 || vm_id_long > INT_MAX) {
+ fprintf(stderr, "Invalid ID\n");
+ exit(1);
+ }
+ pve_auth_setup(vm_id_long);
+ break;
case QEMU_OPTION_vnc:
vnc_parse(optarg, &error_fatal);
break;
--
2.1.4

View File

@ -0,0 +1,24 @@
From e4958531f423dd635053559d05e8c86c208ceb02 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Mon, 8 Feb 2016 08:23:34 +0100
Subject: [PATCH 31/47] vma-writer: don't bail out on zero-length files
---
vma-writer.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/vma-writer.c b/vma-writer.c
index 0d26fc6..a378762 100644
--- a/vma-writer.c
+++ b/vma-writer.c
@@ -130,7 +130,6 @@ int vma_writer_add_config(VmaWriter *vmaw, const char *name, gpointer data,
assert(vmaw->config_count < VMA_MAX_CONFIGS);
assert(name);
assert(data);
- assert(len);
gchar *basename = g_path_get_basename(name);
uint32_t name_ptr = allocate_header_string(vmaw, basename);
--
2.1.4

View File

@ -0,0 +1,42 @@
From 2dc69ead56b7ecd60eb513ab5b6c9978e06070ef Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Tue, 23 Feb 2016 15:48:41 +0100
Subject: [PATCH 32/47] vma: better driver guessing for bdrv_open
Only use 'raw' when the file actually ends with .raw and
no protocol has been specified. With protocol pass the
BDRV_O_PROTOCOL flag to tell bdrv_fill_options() to take it
into account.
---
vma.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/vma.c b/vma.c
index 08e4725..8a27704 100644
--- a/vma.c
+++ b/vma.c
@@ -293,7 +293,20 @@ static int extract_content(int argc, char **argv)
}
BlockDriverState *bs = bdrv_new();
- if (errp || bdrv_open(&bs, devfn, NULL, NULL, flags, &errp)) {
+
+ size_t devlen = strlen(devfn);
+ bool protocol = path_has_protocol(devfn);
+ QDict *options = NULL;
+ if (devlen > 4 && strcmp(devfn+devlen-4, ".raw") == 0 && !protocol) {
+ /* explicit raw format */
+ options = qdict_new();
+ qdict_put(options, "driver", qstring_from_str("raw"));
+ } else if (protocol) {
+ /* tell bdrv_open to honor the protocol */
+ flags |= BDRV_O_PROTOCOL;
+ }
+
+ if (errp || bdrv_open(&bs, devfn, NULL, options, flags, &errp)) {
g_error("can't open file %s - %s", devfn,
error_get_pretty(errp));
}
--
2.1.4

View File

@ -0,0 +1,252 @@
From 6f6f38d2ef8f22a12f72e4d60f8a1fa978ac569a Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Thu, 17 Mar 2016 11:33:37 +0100
Subject: [PATCH 33/47] block: add the zeroinit block driver filter
---
block/Makefile.objs | 1 +
block/zeroinit.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 221 insertions(+)
create mode 100644 block/zeroinit.c
diff --git a/block/Makefile.objs b/block/Makefile.objs
index 2593a2f..930ca33 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -4,6 +4,7 @@ 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-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o
block-obj-y += quorum.o
+block-obj-y += zeroinit.o
block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o
block-obj-y += block-backend.o snapshot.o qapi.o
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
diff --git a/block/zeroinit.c b/block/zeroinit.c
new file mode 100644
index 0000000..c56a446
--- /dev/null
+++ b/block/zeroinit.c
@@ -0,0 +1,220 @@
+/*
+ * Filter to fake a zero-initialized block device.
+ *
+ * Copyright (c) 2016 Wolfgang Bumiller <w.bumiller@proxmox.com>
+ * Copyright (c) 2016 Proxmox Server Solutions GmbH
+ *
+ * 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/osdep.h"
+#include "qapi/error.h"
+#include "block/block_int.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qstring.h"
+#include "qemu/cutils.h"
+
+typedef struct {
+ bool has_zero_init;
+ int64_t extents;
+} BDRVZeroinitState;
+
+/* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */
+static void zeroinit_parse_filename(const char *filename, QDict *options,
+ Error **errp)
+{
+ QString *raw_path;
+
+ /* Parse the blkverify: prefix */
+ if (!strstart(filename, "zeroinit:", &filename)) {
+ /* There was no prefix; therefore, all options have to be already
+ present in the QDict (except for the filename) */
+ return;
+ }
+
+ raw_path = qstring_from_str(filename);
+ qdict_put(options, "x-next", raw_path);
+}
+
+static QemuOptsList runtime_opts = {
+ .name = "zeroinit",
+ .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
+ .desc = {
+ {
+ .name = "x-next",
+ .type = QEMU_OPT_STRING,
+ .help = "[internal use only, will be removed]",
+ },
+ {
+ .name = "x-zeroinit",
+ .type = QEMU_OPT_BOOL,
+ .help = "set has_initialized_zero flag",
+ },
+ { /* end of list */ }
+ },
+};
+
+static int zeroinit_open(BlockDriverState *bs, QDict *options, int flags,
+ Error **errp)
+{
+ BDRVZeroinitState *s = bs->opaque;
+ QemuOpts *opts;
+ Error *local_err = NULL;
+ int ret;
+
+ s->extents = 0;
+
+ opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
+ qemu_opts_absorb_qdict(opts, options, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ /* Open the raw file */
+ bs->file = bdrv_open_child(qemu_opt_get(opts, "x-next"), options, "next",
+ bs, &child_file, false, &local_err);
+ if (local_err) {
+ ret = -EINVAL;
+ error_propagate(errp, local_err);
+ goto fail;
+ }
+
+ /* set the options */
+ s->has_zero_init = qemu_opt_get_bool(opts, "x-zeroinit", true);
+
+ ret = 0;
+fail:
+ if (ret < 0) {
+ bdrv_unref_child(bs, bs->file);
+ }
+ qemu_opts_del(opts);
+ return ret;
+}
+
+static void zeroinit_close(BlockDriverState *bs)
+{
+ BDRVZeroinitState *s = bs->opaque;
+ (void)s;
+}
+
+static int64_t zeroinit_getlength(BlockDriverState *bs)
+{
+ return bdrv_getlength(bs->file->bs);
+}
+
+static BlockAIOCB *zeroinit_aio_readv(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockCompletionFunc *cb, void *opaque)
+{
+ return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors,
+ cb, opaque);
+}
+
+static int coroutine_fn zeroinit_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
+ int count, BdrvRequestFlags flags)
+{
+ BDRVZeroinitState *s = bs->opaque;
+ if (offset >= s->extents)
+ return 0;
+ return bdrv_pwrite_zeroes(bs->file, offset, count, flags);
+}
+
+static BlockAIOCB *zeroinit_aio_writev(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockCompletionFunc *cb, void *opaque)
+{
+ BDRVZeroinitState *s = bs->opaque;
+ int64_t extents = (sector_num << BDRV_SECTOR_BITS) + ((nb_sectors + 1) << BDRV_SECTOR_BITS);
+ if (extents > s->extents)
+ s->extents = extents;
+ return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
+ cb, opaque);
+}
+
+static BlockAIOCB *zeroinit_aio_flush(BlockDriverState *bs,
+ BlockCompletionFunc *cb,
+ void *opaque)
+{
+ return bdrv_aio_flush(bs->file->bs, cb, opaque);
+}
+
+static bool zeroinit_recurse_is_first_non_filter(BlockDriverState *bs,
+ BlockDriverState *candidate)
+{
+ return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
+}
+
+static coroutine_fn int zeroinit_co_flush(BlockDriverState *bs)
+{
+ return bdrv_co_flush(bs->file->bs);
+}
+
+static int zeroinit_has_zero_init(BlockDriverState *bs)
+{
+ BDRVZeroinitState *s = bs->opaque;
+ return s->has_zero_init;
+}
+
+static int64_t coroutine_fn zeroinit_co_get_block_status(BlockDriverState *bs,
+ int64_t sector_num,
+ int nb_sectors, int *pnum,
+ BlockDriverState **file)
+{
+ return bdrv_get_block_status(bs->file->bs, sector_num, nb_sectors, pnum, file);
+}
+
+static coroutine_fn BlockAIOCB *zeroinit_aio_pdiscard(BlockDriverState *bs,
+ int64_t offset, int count,
+ BlockCompletionFunc *cb, void *opaque)
+{
+ return bdrv_aio_pdiscard(bs->file->bs, offset, count, cb, opaque);
+}
+
+static int zeroinit_truncate(BlockDriverState *bs, int64_t offset)
+{
+ return bdrv_truncate(bs->file->bs, offset);
+}
+
+static int zeroinit_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+ return bdrv_get_info(bs->file->bs, bdi);
+}
+
+static BlockDriver bdrv_zeroinit = {
+ .format_name = "zeroinit",
+ .protocol_name = "zeroinit",
+ .instance_size = sizeof(BDRVZeroinitState),
+
+ .bdrv_parse_filename = zeroinit_parse_filename,
+ .bdrv_file_open = zeroinit_open,
+ .bdrv_close = zeroinit_close,
+ .bdrv_getlength = zeroinit_getlength,
+ .bdrv_co_flush_to_disk = zeroinit_co_flush,
+
+ .bdrv_co_pwrite_zeroes = zeroinit_co_pwrite_zeroes,
+ .bdrv_aio_writev = zeroinit_aio_writev,
+ .bdrv_aio_readv = zeroinit_aio_readv,
+ .bdrv_aio_flush = zeroinit_aio_flush,
+
+ .is_filter = true,
+ .bdrv_recurse_is_first_non_filter = zeroinit_recurse_is_first_non_filter,
+
+ .bdrv_has_zero_init = zeroinit_has_zero_init,
+
+ .bdrv_co_get_block_status = zeroinit_co_get_block_status,
+
+ .bdrv_aio_pdiscard = zeroinit_aio_pdiscard,
+
+ .bdrv_truncate = zeroinit_truncate,
+ .bdrv_get_info = zeroinit_get_info,
+};
+
+static void bdrv_zeroinit_init(void)
+{
+ bdrv_register(&bdrv_zeroinit);
+}
+
+block_init(bdrv_zeroinit_init);
--
2.1.4

View File

@ -0,0 +1,108 @@
From 10ae69c411df788752628c8950bf9e76c8cf6af1 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Tue, 12 Apr 2016 13:49:44 +0200
Subject: [PATCH 34/47] vma: add format option to device mapping
The BDRV_O_PROTOCOL option breaks non-raw protocol devices,
so we instead now allow the format to be explicitly
specified from the outside.
In other words we now too deprecate the automatic guessing
of raw formats, just like qemu already does, and have to
silence the warnings by passing the drive mapping.
---
vma.c | 34 +++++++++++++++++++++++++++-------
1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/vma.c b/vma.c
index 8a27704..c8ad6c0 100644
--- a/vma.c
+++ b/vma.c
@@ -130,6 +130,7 @@ static int list_content(int argc, char **argv)
typedef struct RestoreMap {
char *devname;
char *path;
+ char *format;
bool write_zero;
} RestoreMap;
@@ -217,13 +218,24 @@ static int extract_content(int argc, char **argv)
}
}
+ char *format = NULL;
+ if (strncmp(line, "format=", sizeof("format=")-1) == 0) {
+ format = line + sizeof("format=")-1;
+ char *colon = strchr(format, ':');
+ if (!colon) {
+ g_error("read map failed - found only a format ('%s')", inbuf);
+ }
+ format = g_strndup(format, colon - format);
+ line = colon+1;
+ }
+
const char *path;
bool write_zero;
if (line[0] == '0' && line[1] == ':') {
- path = inbuf + 2;
+ path = line + 2;
write_zero = false;
} else if (line[0] == '1' && line[1] == ':') {
- path = inbuf + 2;
+ path = line + 2;
write_zero = true;
} else {
g_error("read map failed - parse error ('%s')", inbuf);
@@ -239,6 +251,7 @@ static int extract_content(int argc, char **argv)
RestoreMap *map = g_new0(RestoreMap, 1);
map->devname = g_strdup(devname);
map->path = g_strdup(path);
+ map->format = format;
map->write_zero = write_zero;
g_hash_table_insert(devmap, map->devname, map);
@@ -263,6 +276,7 @@ static int extract_content(int argc, char **argv)
g_free(statefn);
} else if (di) {
char *devfn = NULL;
+ const char *format = NULL;
int flags = BDRV_O_RDWR;
bool write_zero = true;
@@ -273,6 +287,7 @@ static int extract_content(int argc, char **argv)
g_error("no device name mapping for %s", di->devname);
}
devfn = map->path;
+ format = map->format;
write_zero = map->write_zero;
} else {
devfn = g_strdup_printf("%s/tmp-disk-%s.raw",
@@ -295,15 +310,20 @@ static int extract_content(int argc, char **argv)
BlockDriverState *bs = bdrv_new();
size_t devlen = strlen(devfn);
- bool protocol = path_has_protocol(devfn);
QDict *options = NULL;
- if (devlen > 4 && strcmp(devfn+devlen-4, ".raw") == 0 && !protocol) {
+ if (format) {
+ /* explicit format from commandline */
+ options = qdict_new();
+ qdict_put(options, "driver", qstring_from_str(format));
+ } else if ((devlen > 4 && strcmp(devfn+devlen-4, ".raw") == 0) ||
+ strncmp(devfn, "/dev/", 5) == 0)
+ {
+ /* This part is now deprecated for PVE as well (just as qemu
+ * deprecated not specifying an explicit raw format, too.
+ */
/* explicit raw format */
options = qdict_new();
qdict_put(options, "driver", qstring_from_str("raw"));
- } else if (protocol) {
- /* tell bdrv_open to honor the protocol */
- flags |= BDRV_O_PROTOCOL;
}
if (errp || bdrv_open(&bs, devfn, NULL, options, flags, &errp)) {
--
2.1.4

View File

@ -0,0 +1,25 @@
From 927da5e2426aac5bef37c97604740deddedbda41 Mon Sep 17 00:00:00 2001
From: Thomas Lamprecht <t.lamprecht@proxmox.com>
Date: Wed, 6 Apr 2016 16:45:15 +0200
Subject: [PATCH 35/47] fix possible unitialised return value
---
migration/savevm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index b1bdfb6..cebba77 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -1020,7 +1020,7 @@ int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
QJSON *vmdesc;
int vmdesc_len;
SaveStateEntry *se;
- int ret;
+ int ret = -1;
bool in_postcopy = migration_in_postcopy(migrate_get_current());
trace_savevm_state_complete_precopy();
--
2.1.4

View File

@ -0,0 +1,87 @@
From e6af4497017e37cb31f7cbd80137f41ce297d702 Mon Sep 17 00:00:00 2001
From: Thomas Lamprecht <t.lamprecht@proxmox.com>
Date: Wed, 6 Apr 2016 16:47:54 +0200
Subject: [PATCH 36/47] vnc: refactor to QIOChannelSocket
---
ui/vnc-auth-vencrypt.c | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c
index d11f1df..a529520 100644
--- a/ui/vnc-auth-vencrypt.c
+++ b/ui/vnc-auth-vencrypt.c
@@ -28,27 +28,23 @@
#include "vnc.h"
#include "qapi/error.h"
#include "qemu/main-loop.h"
-#include "qemu/sockets.h"
+#include "io/channel-socket.h"
static int protocol_client_auth_plain(VncState *vs, uint8_t *data, size_t len)
{
- const char *err = NULL;
+ Error *err = NULL;
char username[256];
char passwd[512];
- char clientip[256];
- clientip[0] = 0;
- struct sockaddr_in client;
- socklen_t addrlen = sizeof(client);
- if (getpeername(vs->csock, &client, &addrlen) == 0) {
- inet_ntop(client.sin_family, &client.sin_addr,
- clientip, sizeof(clientip));
+ SocketAddress *clientip = qio_channel_socket_get_remote_address(vs->sioc, &err);
+ if (err) {
+ goto err;
}
if ((len != (vs->username_len + vs->password_len)) ||
(vs->username_len >= (sizeof(username)-1)) ||
(vs->password_len >= (sizeof(passwd)-1)) ) {
- err = "Got unexpected data length";
+ error_setg(&err, "Got unexpected data length");
goto err;
}
@@ -59,26 +55,31 @@ static int protocol_client_auth_plain(VncState *vs, uint8_t *data, size_t len)
VNC_DEBUG("AUTH PLAIN username: %s pw: %s\n", username, passwd);
- if (pve_auth_verify(clientip, username, passwd) == 0) {
+ if (pve_auth_verify(clientip->u.inet.data->host, username, passwd) == 0) {
vnc_write_u32(vs, 0); /* Accept auth completion */
start_client_init(vs);
+ qapi_free_SocketAddress(clientip);
return 0;
}
- err = "Authentication failed";
+ error_setg(&err, "Authentication failed");
err:
if (err) {
- VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err);
+ const char *err_msg = error_get_pretty(err);
+ VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err_msg);
vnc_write_u32(vs, 1); /* Reject auth */
if (vs->minor >= 8) {
- int elen = strlen(err);
+ int elen = strlen(err_msg);
vnc_write_u32(vs, elen);
- vnc_write(vs, err, elen);
+ vnc_write(vs, err_msg, elen);
}
+ error_free(err);
}
vnc_flush(vs);
vnc_client_error(vs);
+ qapi_free_SocketAddress(clientip);
+
return 0;
}
--
2.1.4

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