bump version to 2.11.1-1
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
db442fc8d3
commit
6838f03890
19
Makefile
19
Makefile
@ -1,6 +1,6 @@
|
||||
# also update debian/changelog
|
||||
KVMVER=2.9.1
|
||||
KVMPKGREL=9
|
||||
KVMVER=2.11.1
|
||||
KVMPKGREL=1
|
||||
|
||||
KVMPACKAGE = pve-qemu-kvm
|
||||
KVMSRC = qemu
|
||||
@ -25,18 +25,31 @@ submodule:
|
||||
.PHONY: deb kvm
|
||||
deb kvm: $(DEBS)
|
||||
$(DEB_DBG): $(DEB)
|
||||
$(DEB): | submodule
|
||||
$(DEB): keycodemapdb | submodule
|
||||
rm -f *.deb
|
||||
rm -rf $(BUILDSRC)
|
||||
mkdir $(BUILDSRC)
|
||||
cp -a $(KVMSRC)/* $(BUILDSRC)/
|
||||
cp -a debian $(BUILDSRC)/debian
|
||||
rm -rf $(BUILDSRC)/ui/keycodemapdb
|
||||
cp -a keycodemapdb $(BUILDSRC)/ui/
|
||||
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: update
|
||||
update:
|
||||
cd $(KVMSRC) && git submodule deinit ui/keycodemapdb || true
|
||||
rm -rf $(KVMSRC)/ui/keycodemapdb
|
||||
mkdir $(KVMSRC)/ui/keycodemapdb
|
||||
cd $(KVMSRC) && git submodule update --init ui/keycodemapdb
|
||||
rm -rf keycodemapdb
|
||||
mkdir keycodemapdb
|
||||
cp -R $(KVMSRC)/ui/keycodemapdb/* keycodemapdb/
|
||||
git add keycodemapdb
|
||||
|
||||
.PHONY: upload
|
||||
upload: $(DEBS)
|
||||
tar cf - ${DEBS} | ssh repoman@repo.proxmox.com upload --product pve --dist stretch
|
||||
|
6
debian/changelog
vendored
6
debian/changelog
vendored
@ -1,3 +1,9 @@
|
||||
pve-qemu-kvm (2.11.1-1) stable; urgency=medium
|
||||
|
||||
* update to 2.11.1
|
||||
|
||||
-- Proxmox Support Team <support@proxmox.com> Thu, 22 Feb 2018 12:34:43 +0100
|
||||
|
||||
pve-qemu-kvm (2.9.1-9) stable; urgency=medium
|
||||
|
||||
* add EPYC and EPYC-IPBP cpu models
|
||||
|
@ -9,7 +9,7 @@ This reverts commit b8eb5512fd8a115f164edbbe897cdf8884920ccb.
|
||||
1 file changed, 9 insertions(+)
|
||||
|
||||
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
|
||||
index 1ef56f8d10..31fb73e9fb 100644
|
||||
index 78903ea909..cdfbec5e47 100644
|
||||
--- a/hw/intc/apic_common.c
|
||||
+++ b/hw/intc/apic_common.c
|
||||
@@ -257,6 +257,15 @@ static void apic_reset_common(DeviceState *dev)
|
||||
|
@ -13,10 +13,10 @@ Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
1 file changed, 5 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/include/qemu/ratelimit.h b/include/qemu/ratelimit.h
|
||||
index 8da1232574..324ff04fe2 100644
|
||||
index 8dece483f5..1b38291823 100644
|
||||
--- a/include/qemu/ratelimit.h
|
||||
+++ b/include/qemu/ratelimit.h
|
||||
@@ -35,7 +35,7 @@ typedef struct {
|
||||
@@ -36,7 +36,7 @@ typedef struct {
|
||||
static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
|
||||
{
|
||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||
@ -25,7 +25,7 @@ index 8da1232574..324ff04fe2 100644
|
||||
|
||||
assert(limit->slice_quota && limit->slice_ns);
|
||||
|
||||
@@ -54,12 +54,11 @@ static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
|
||||
@@ -55,12 +55,11 @@ static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,74 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Fri, 2 Jun 2017 10:54:24 +0100
|
||||
Subject: [PATCH] virtio-serial: fix segfault on disconnect
|
||||
|
||||
Since commit d4c19cdeeb2f1e474bc426a6da261f1d7346eb5b ("virtio-serial:
|
||||
add missing virtio_detach_element() call") the following commands may
|
||||
cause QEMU to segfault:
|
||||
|
||||
$ qemu -M accel=kvm -cpu host -m 1G \
|
||||
-drive if=virtio,file=test.img,format=raw \
|
||||
-device virtio-serial-pci,id=virtio-serial0 \
|
||||
-chardev socket,id=channel1,path=/tmp/chardev.sock,server,nowait \
|
||||
-device virtserialport,chardev=channel1,bus=virtio-serial0.0,id=port1
|
||||
$ nc -U /tmp/chardev.sock
|
||||
^C
|
||||
|
||||
(guest)$ cat /dev/zero >/dev/vport0p1
|
||||
|
||||
The segfault is non-deterministic: if the event loop notices the socket
|
||||
has been closed then there is no crash. The disconnect has to happen
|
||||
right before QEMU attempts to write data to the socket.
|
||||
|
||||
The backtrace is as follows:
|
||||
|
||||
Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
|
||||
0x00005555557e0698 in do_flush_queued_data (port=0x5555582cedf0, vq=0x7fffcc854290, vdev=0x55555807b1d0) at hw/char/virtio-serial-bus.c:180
|
||||
180 for (i = port->iov_idx; i < port->elem->out_num; i++) {
|
||||
#1 0x000055555580d363 in virtio_queue_notify_vq (vq=0x7fffcc854290) at hw/virtio/virtio.c:1524
|
||||
#2 0x000055555580d363 in virtio_queue_host_notifier_read (n=0x7fffcc8542f8) at hw/virtio/virtio.c:2430
|
||||
#3 0x0000555555b3482c in aio_dispatch_handlers (ctx=ctx@entry=0x5555566b8c80) at util/aio-posix.c:399
|
||||
#4 0x0000555555b350d8 in aio_dispatch (ctx=0x5555566b8c80) at util/aio-posix.c:430
|
||||
#5 0x0000555555b3212e in aio_ctx_dispatch (source=<optimized out>, callback=<optimized out>, user_data=<optimized out>) at util/async.c:261
|
||||
#6 0x00007fffde71de52 in g_main_context_dispatch () at /lib64/libglib-2.0.so.0
|
||||
#7 0x0000555555b34353 in glib_pollfds_poll () at util/main-loop.c:213
|
||||
#8 0x0000555555b34353 in os_host_main_loop_wait (timeout=<optimized out>) at util/main-loop.c:261
|
||||
#9 0x0000555555b34353 in main_loop_wait (nonblocking=<optimized out>) at util/main-loop.c:517
|
||||
#10 0x0000555555773207 in main_loop () at vl.c:1917
|
||||
#11 0x0000555555773207 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at vl.c:4751
|
||||
|
||||
The do_flush_queued_data() function does not anticipate chardev close
|
||||
events during vsc->have_data(). It expects port->elem to remain
|
||||
non-NULL for the duration its for loop.
|
||||
|
||||
The fix is simply to return from do_flush_queued_data() if the port
|
||||
closes because the close event already frees port->elem and drains the
|
||||
virtqueue - there is nothing left for do_flush_queued_data() to do.
|
||||
|
||||
Reported-by: Sitong Liu <siliu@redhat.com>
|
||||
Reported-by: Min Deng <mdeng@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
hw/char/virtio-serial-bus.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
|
||||
index aa9c11ae92..f5bc173844 100644
|
||||
--- a/hw/char/virtio-serial-bus.c
|
||||
+++ b/hw/char/virtio-serial-bus.c
|
||||
@@ -186,6 +186,9 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
|
||||
port->elem->out_sg[i].iov_base
|
||||
+ port->iov_offset,
|
||||
buf_size);
|
||||
+ if (!port->elem) { /* bail if we got disconnected */
|
||||
+ return;
|
||||
+ }
|
||||
if (port->throttled) {
|
||||
port->iov_idx = i;
|
||||
if (ret > 0) {
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,125 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Thu, 1 Jun 2017 17:26:14 +0200
|
||||
Subject: [PATCH] megasas: always store SCSIRequest* into MegasasCmd
|
||||
|
||||
This ensures that the request is unref'ed properly, and avoids a
|
||||
segmentation fault in the new qtest testcase that is added.
|
||||
This is CVE-2017-9503.
|
||||
|
||||
Reported-by: Zhangyanyu <zyy4013@stu.ouc.edu.cn>
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
---
|
||||
hw/scsi/megasas.c | 31 ++++++++++++++++---------------
|
||||
1 file changed, 16 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
|
||||
index 135662df31..734fdaef90 100644
|
||||
--- a/hw/scsi/megasas.c
|
||||
+++ b/hw/scsi/megasas.c
|
||||
@@ -609,6 +609,9 @@ static void megasas_reset_frames(MegasasState *s)
|
||||
static void megasas_abort_command(MegasasCmd *cmd)
|
||||
{
|
||||
/* Never abort internal commands. */
|
||||
+ if (cmd->dcmd_opcode != -1) {
|
||||
+ return;
|
||||
+ }
|
||||
if (cmd->req != NULL) {
|
||||
scsi_req_cancel(cmd->req);
|
||||
}
|
||||
@@ -1017,7 +1020,6 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
uint64_t pd_size;
|
||||
uint16_t pd_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
|
||||
uint8_t cmdbuf[6];
|
||||
- SCSIRequest *req;
|
||||
size_t len, resid;
|
||||
|
||||
if (!cmd->iov_buf) {
|
||||
@@ -1026,8 +1028,8 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
info->inquiry_data[0] = 0x7f; /* Force PQual 0x3, PType 0x1f */
|
||||
info->vpd_page83[0] = 0x7f;
|
||||
megasas_setup_inquiry(cmdbuf, 0, sizeof(info->inquiry_data));
|
||||
- req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
|
||||
- if (!req) {
|
||||
+ cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
|
||||
+ if (!cmd->req) {
|
||||
trace_megasas_dcmd_req_alloc_failed(cmd->index,
|
||||
"PD get info std inquiry");
|
||||
g_free(cmd->iov_buf);
|
||||
@@ -1036,26 +1038,26 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
}
|
||||
trace_megasas_dcmd_internal_submit(cmd->index,
|
||||
"PD get info std inquiry", lun);
|
||||
- len = scsi_req_enqueue(req);
|
||||
+ len = scsi_req_enqueue(cmd->req);
|
||||
if (len > 0) {
|
||||
cmd->iov_size = len;
|
||||
- scsi_req_continue(req);
|
||||
+ scsi_req_continue(cmd->req);
|
||||
}
|
||||
return MFI_STAT_INVALID_STATUS;
|
||||
} else if (info->inquiry_data[0] != 0x7f && info->vpd_page83[0] == 0x7f) {
|
||||
megasas_setup_inquiry(cmdbuf, 0x83, sizeof(info->vpd_page83));
|
||||
- req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
|
||||
- if (!req) {
|
||||
+ cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
|
||||
+ if (!cmd->req) {
|
||||
trace_megasas_dcmd_req_alloc_failed(cmd->index,
|
||||
"PD get info vpd inquiry");
|
||||
return MFI_STAT_FLASH_ALLOC_FAIL;
|
||||
}
|
||||
trace_megasas_dcmd_internal_submit(cmd->index,
|
||||
"PD get info vpd inquiry", lun);
|
||||
- len = scsi_req_enqueue(req);
|
||||
+ len = scsi_req_enqueue(cmd->req);
|
||||
if (len > 0) {
|
||||
cmd->iov_size = len;
|
||||
- scsi_req_continue(req);
|
||||
+ scsi_req_continue(cmd->req);
|
||||
}
|
||||
return MFI_STAT_INVALID_STATUS;
|
||||
}
|
||||
@@ -1217,7 +1219,6 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
struct mfi_ld_info *info = cmd->iov_buf;
|
||||
size_t dcmd_size = sizeof(struct mfi_ld_info);
|
||||
uint8_t cdb[6];
|
||||
- SCSIRequest *req;
|
||||
ssize_t len, resid;
|
||||
uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
|
||||
uint64_t ld_size;
|
||||
@@ -1226,8 +1227,8 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
cmd->iov_buf = g_malloc0(dcmd_size);
|
||||
info = cmd->iov_buf;
|
||||
megasas_setup_inquiry(cdb, 0x83, sizeof(info->vpd_page83));
|
||||
- req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
|
||||
- if (!req) {
|
||||
+ cmd->req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
|
||||
+ if (!cmd->req) {
|
||||
trace_megasas_dcmd_req_alloc_failed(cmd->index,
|
||||
"LD get info vpd inquiry");
|
||||
g_free(cmd->iov_buf);
|
||||
@@ -1236,10 +1237,10 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
}
|
||||
trace_megasas_dcmd_internal_submit(cmd->index,
|
||||
"LD get info vpd inquiry", lun);
|
||||
- len = scsi_req_enqueue(req);
|
||||
+ len = scsi_req_enqueue(cmd->req);
|
||||
if (len > 0) {
|
||||
cmd->iov_size = len;
|
||||
- scsi_req_continue(req);
|
||||
+ scsi_req_continue(cmd->req);
|
||||
}
|
||||
return MFI_STAT_INVALID_STATUS;
|
||||
}
|
||||
@@ -1851,7 +1852,7 @@ static void megasas_command_complete(SCSIRequest *req, uint32_t status,
|
||||
return;
|
||||
}
|
||||
|
||||
- if (cmd->req == NULL) {
|
||||
+ if (cmd->dcmd_opcode != -1) {
|
||||
/*
|
||||
* Internal command complete
|
||||
*/
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,35 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Mon, 17 Jul 2017 17:33:26 +0530
|
||||
Subject: [PATCH] slirp: check len against dhcp options array end
|
||||
|
||||
While parsing dhcp options string in 'dhcp_decode', if an options'
|
||||
length 'len' appeared towards the end of 'bp_vend' array, ensuing
|
||||
read could lead to an OOB memory access issue. Add check to avoid it.
|
||||
|
||||
This is CVE-2017-11434.
|
||||
|
||||
Reported-by: Reno Robert <renorobert@gmail.com>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||||
---
|
||||
slirp/bootp.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/slirp/bootp.c b/slirp/bootp.c
|
||||
index 5a4646c182..5dd1a415b5 100644
|
||||
--- a/slirp/bootp.c
|
||||
+++ b/slirp/bootp.c
|
||||
@@ -123,6 +123,9 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
|
||||
if (p >= p_end)
|
||||
break;
|
||||
len = *p++;
|
||||
+ if (p + len > p_end) {
|
||||
+ break;
|
||||
+ }
|
||||
DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
|
||||
|
||||
switch(tag) {
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,44 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 9 Aug 2017 17:02:11 +0100
|
||||
Subject: [PATCH] IDE: Do not flush empty CDROM drives
|
||||
|
||||
The block backend changed in a way that flushing empty CDROM drives now
|
||||
crashes. Amend IDE to avoid doing so until the root problem can be
|
||||
addressed for 2.11.
|
||||
|
||||
Original patch by John Snow <jsnow@redhat.com>.
|
||||
|
||||
Reported-by: Kieron Shorrock <kshorrock@paloaltonetworks.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Message-id: 20170809160212.29976-2-stefanha@redhat.com
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
---
|
||||
hw/ide/core.c | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/ide/core.c b/hw/ide/core.c
|
||||
index 0b48b64d3a..bea39536b0 100644
|
||||
--- a/hw/ide/core.c
|
||||
+++ b/hw/ide/core.c
|
||||
@@ -1063,7 +1063,15 @@ static void ide_flush_cache(IDEState *s)
|
||||
s->status |= BUSY_STAT;
|
||||
ide_set_retry(s);
|
||||
block_acct_start(blk_get_stats(s->blk), &s->acct, 0, BLOCK_ACCT_FLUSH);
|
||||
- s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
|
||||
+
|
||||
+ if (blk_bs(s->blk)) {
|
||||
+ s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
|
||||
+ } else {
|
||||
+ /* XXX blk_aio_flush() crashes when blk_bs(blk) is NULL, remove this
|
||||
+ * temporary workaround when blk_aio_*() functions handle NULL blk_bs.
|
||||
+ */
|
||||
+ ide_flush_cb(s, 0);
|
||||
+ }
|
||||
}
|
||||
|
||||
static void ide_cfata_metadata_inquiry(IDEState *s)
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,51 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 21 Apr 2017 11:16:24 +0200
|
||||
Subject: [PATCH] bitmap: add bitmap_copy_and_clear_atomic
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20170421091632.30900-2-kraxel@redhat.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
include/qemu/bitmap.h | 2 ++
|
||||
util/bitmap.c | 11 +++++++++++
|
||||
2 files changed, 13 insertions(+)
|
||||
|
||||
diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h
|
||||
index 63ea2d0b1e..c318da12d7 100644
|
||||
--- a/include/qemu/bitmap.h
|
||||
+++ b/include/qemu/bitmap.h
|
||||
@@ -220,6 +220,8 @@ void bitmap_set(unsigned long *map, long i, long len);
|
||||
void bitmap_set_atomic(unsigned long *map, long i, long len);
|
||||
void bitmap_clear(unsigned long *map, long start, long nr);
|
||||
bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr);
|
||||
+void bitmap_copy_and_clear_atomic(unsigned long *dst, unsigned long *src,
|
||||
+ long nr);
|
||||
unsigned long bitmap_find_next_zero_area(unsigned long *map,
|
||||
unsigned long size,
|
||||
unsigned long start,
|
||||
diff --git a/util/bitmap.c b/util/bitmap.c
|
||||
index c1a84ca5e3..efced9a7d8 100644
|
||||
--- a/util/bitmap.c
|
||||
+++ b/util/bitmap.c
|
||||
@@ -287,6 +287,17 @@ bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr)
|
||||
return dirty != 0;
|
||||
}
|
||||
|
||||
+void bitmap_copy_and_clear_atomic(unsigned long *dst, unsigned long *src,
|
||||
+ long nr)
|
||||
+{
|
||||
+ while (nr > 0) {
|
||||
+ *dst = atomic_xchg(src, 0);
|
||||
+ dst++;
|
||||
+ src++;
|
||||
+ nr -= BITS_PER_LONG;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
#define ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
|
||||
|
||||
/**
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,241 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 21 Apr 2017 11:16:25 +0200
|
||||
Subject: [PATCH] memory: add support getting and using a dirty bitmap copy.
|
||||
|
||||
This patch adds support for getting and using a local copy of the dirty
|
||||
bitmap.
|
||||
|
||||
memory_region_snapshot_and_clear_dirty() will create a snapshot of the
|
||||
dirty bitmap for the specified range, clear the dirty bitmap and return
|
||||
the copy. The returned bitmap can be a bit larger than requested, the
|
||||
range is expanded so the code can copy unsigned longs from the bitmap
|
||||
and avoid atomic bit update operations.
|
||||
|
||||
memory_region_snapshot_get_dirty() will return the dirty status of
|
||||
pages, pretty much like memory_region_get_dirty(), but using the copy
|
||||
returned by memory_region_copy_and_clear_dirty().
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20170421091632.30900-3-kraxel@redhat.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
exec.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
include/exec/memory.h | 47 +++++++++++++++++++++++++++++++
|
||||
include/exec/ram_addr.h | 7 +++++
|
||||
include/qemu/typedefs.h | 1 +
|
||||
memory.c | 17 +++++++++++
|
||||
5 files changed, 147 insertions(+)
|
||||
|
||||
diff --git a/exec.c b/exec.c
|
||||
index fcb5b16131..07c2c8ea88 100644
|
||||
--- a/exec.c
|
||||
+++ b/exec.c
|
||||
@@ -223,6 +223,12 @@ struct CPUAddressSpace {
|
||||
MemoryListener tcg_as_listener;
|
||||
};
|
||||
|
||||
+struct DirtyBitmapSnapshot {
|
||||
+ ram_addr_t start;
|
||||
+ ram_addr_t end;
|
||||
+ unsigned long dirty[];
|
||||
+};
|
||||
+
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
@@ -1061,6 +1067,75 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
|
||||
return dirty;
|
||||
}
|
||||
|
||||
+DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
|
||||
+ (ram_addr_t start, ram_addr_t length, unsigned client)
|
||||
+{
|
||||
+ DirtyMemoryBlocks *blocks;
|
||||
+ unsigned long align = 1UL << (TARGET_PAGE_BITS + BITS_PER_LEVEL);
|
||||
+ ram_addr_t first = QEMU_ALIGN_DOWN(start, align);
|
||||
+ ram_addr_t last = QEMU_ALIGN_UP(start + length, align);
|
||||
+ DirtyBitmapSnapshot *snap;
|
||||
+ unsigned long page, end, dest;
|
||||
+
|
||||
+ snap = g_malloc0(sizeof(*snap) +
|
||||
+ ((last - first) >> (TARGET_PAGE_BITS + 3)));
|
||||
+ snap->start = first;
|
||||
+ snap->end = last;
|
||||
+
|
||||
+ page = first >> TARGET_PAGE_BITS;
|
||||
+ end = last >> TARGET_PAGE_BITS;
|
||||
+ dest = 0;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+
|
||||
+ blocks = atomic_rcu_read(&ram_list.dirty_memory[client]);
|
||||
+
|
||||
+ while (page < end) {
|
||||
+ unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE;
|
||||
+ unsigned long offset = page % DIRTY_MEMORY_BLOCK_SIZE;
|
||||
+ unsigned long num = MIN(end - page, DIRTY_MEMORY_BLOCK_SIZE - offset);
|
||||
+
|
||||
+ assert(QEMU_IS_ALIGNED(offset, (1 << BITS_PER_LEVEL)));
|
||||
+ assert(QEMU_IS_ALIGNED(num, (1 << BITS_PER_LEVEL)));
|
||||
+ offset >>= BITS_PER_LEVEL;
|
||||
+
|
||||
+ bitmap_copy_and_clear_atomic(snap->dirty + dest,
|
||||
+ blocks->blocks[idx] + offset,
|
||||
+ num);
|
||||
+ page += num;
|
||||
+ dest += num >> BITS_PER_LEVEL;
|
||||
+ }
|
||||
+
|
||||
+ rcu_read_unlock();
|
||||
+
|
||||
+ if (tcg_enabled()) {
|
||||
+ tlb_reset_dirty_range_all(start, length);
|
||||
+ }
|
||||
+
|
||||
+ return snap;
|
||||
+}
|
||||
+
|
||||
+bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
|
||||
+ ram_addr_t start,
|
||||
+ ram_addr_t length)
|
||||
+{
|
||||
+ unsigned long page, end;
|
||||
+
|
||||
+ assert(start >= snap->start);
|
||||
+ assert(start + length <= snap->end);
|
||||
+
|
||||
+ end = TARGET_PAGE_ALIGN(start + length - snap->start) >> TARGET_PAGE_BITS;
|
||||
+ page = (start - snap->start) >> TARGET_PAGE_BITS;
|
||||
+
|
||||
+ while (page < end) {
|
||||
+ if (test_bit(page, snap->dirty)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ page++;
|
||||
+ }
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
/* Called from RCU critical section */
|
||||
hwaddr memory_region_section_get_iotlb(CPUState *cpu,
|
||||
MemoryRegionSection *section,
|
||||
diff --git a/include/exec/memory.h b/include/exec/memory.h
|
||||
index f20b191793..1e15e79d00 100644
|
||||
--- a/include/exec/memory.h
|
||||
+++ b/include/exec/memory.h
|
||||
@@ -871,6 +871,53 @@ void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr,
|
||||
*/
|
||||
bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
|
||||
hwaddr size, unsigned client);
|
||||
+
|
||||
+/**
|
||||
+ * memory_region_snapshot_and_clear_dirty: Get a snapshot of the dirty
|
||||
+ * bitmap and clear it.
|
||||
+ *
|
||||
+ * Creates a snapshot of the dirty bitmap, clears the dirty bitmap and
|
||||
+ * returns the snapshot. The snapshot can then be used to query dirty
|
||||
+ * status, using memory_region_snapshot_get_dirty. Unlike
|
||||
+ * memory_region_test_and_clear_dirty this allows to query the same
|
||||
+ * page multiple times, which is especially useful for display updates
|
||||
+ * where the scanlines often are not page aligned.
|
||||
+ *
|
||||
+ * The dirty bitmap region which gets copyed into the snapshot (and
|
||||
+ * cleared afterwards) can be larger than requested. The boundaries
|
||||
+ * are rounded up/down so complete bitmap longs (covering 64 pages on
|
||||
+ * 64bit hosts) can be copied over into the bitmap snapshot. Which
|
||||
+ * isn't a problem for display updates as the extra pages are outside
|
||||
+ * the visible area, and in case the visible area changes a full
|
||||
+ * display redraw is due anyway. Should other use cases for this
|
||||
+ * function emerge we might have to revisit this implementation
|
||||
+ * detail.
|
||||
+ *
|
||||
+ * Use g_free to release DirtyBitmapSnapshot.
|
||||
+ *
|
||||
+ * @mr: the memory region being queried.
|
||||
+ * @addr: the address (relative to the start of the region) being queried.
|
||||
+ * @size: the size of the range being queried.
|
||||
+ * @client: the user of the logging information; typically %DIRTY_MEMORY_VGA.
|
||||
+ */
|
||||
+DirtyBitmapSnapshot *memory_region_snapshot_and_clear_dirty(MemoryRegion *mr,
|
||||
+ hwaddr addr,
|
||||
+ hwaddr size,
|
||||
+ unsigned client);
|
||||
+
|
||||
+/**
|
||||
+ * memory_region_snapshot_get_dirty: Check whether a range of bytes is dirty
|
||||
+ * in the specified dirty bitmap snapshot.
|
||||
+ *
|
||||
+ * @mr: the memory region being queried.
|
||||
+ * @snap: the dirty bitmap snapshot
|
||||
+ * @addr: the address (relative to the start of the region) being queried.
|
||||
+ * @size: the size of the range being queried.
|
||||
+ */
|
||||
+bool memory_region_snapshot_get_dirty(MemoryRegion *mr,
|
||||
+ DirtyBitmapSnapshot *snap,
|
||||
+ hwaddr addr, hwaddr size);
|
||||
+
|
||||
/**
|
||||
* memory_region_sync_dirty_bitmap: Synchronize a region's dirty bitmap with
|
||||
* any external TLBs (e.g. kvm)
|
||||
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
|
||||
index b05dc84ab9..2b63d7f59e 100644
|
||||
--- a/include/exec/ram_addr.h
|
||||
+++ b/include/exec/ram_addr.h
|
||||
@@ -343,6 +343,13 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
|
||||
ram_addr_t length,
|
||||
unsigned client);
|
||||
|
||||
+DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
|
||||
+ (ram_addr_t start, ram_addr_t length, unsigned client);
|
||||
+
|
||||
+bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
|
||||
+ ram_addr_t start,
|
||||
+ ram_addr_t length);
|
||||
+
|
||||
static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
|
||||
ram_addr_t length)
|
||||
{
|
||||
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
|
||||
index e95f28cfec..f08d327aec 100644
|
||||
--- a/include/qemu/typedefs.h
|
||||
+++ b/include/qemu/typedefs.h
|
||||
@@ -23,6 +23,7 @@ typedef struct CPUAddressSpace CPUAddressSpace;
|
||||
typedef struct CPUState CPUState;
|
||||
typedef struct DeviceListener DeviceListener;
|
||||
typedef struct DeviceState DeviceState;
|
||||
+typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot;
|
||||
typedef struct DisplayChangeListener DisplayChangeListener;
|
||||
typedef struct DisplayState DisplayState;
|
||||
typedef struct DisplaySurface DisplaySurface;
|
||||
diff --git a/memory.c b/memory.c
|
||||
index 4c95aaf39c..8a0648551f 100644
|
||||
--- a/memory.c
|
||||
+++ b/memory.c
|
||||
@@ -1716,6 +1716,23 @@ bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
|
||||
memory_region_get_ram_addr(mr) + addr, size, client);
|
||||
}
|
||||
|
||||
+DirtyBitmapSnapshot *memory_region_snapshot_and_clear_dirty(MemoryRegion *mr,
|
||||
+ hwaddr addr,
|
||||
+ hwaddr size,
|
||||
+ unsigned client)
|
||||
+{
|
||||
+ assert(mr->ram_block);
|
||||
+ return cpu_physical_memory_snapshot_and_clear_dirty(
|
||||
+ memory_region_get_ram_addr(mr) + addr, size, client);
|
||||
+}
|
||||
+
|
||||
+bool memory_region_snapshot_get_dirty(MemoryRegion *mr, DirtyBitmapSnapshot *snap,
|
||||
+ hwaddr addr, hwaddr size)
|
||||
+{
|
||||
+ assert(mr->ram_block);
|
||||
+ return cpu_physical_memory_snapshot_get_dirty(snap,
|
||||
+ memory_region_get_ram_addr(mr) + addr, size);
|
||||
+}
|
||||
|
||||
void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
|
||||
{
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,63 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 21 Apr 2017 11:16:26 +0200
|
||||
Subject: [PATCH] vga: add vga_scanline_invalidated helper
|
||||
|
||||
Add vga_scanline_invalidated helper to check whenever a scanline was
|
||||
invalidated. Add a sanity check to fix OOB read access for display
|
||||
heights larger than 2048.
|
||||
|
||||
Only cirrus uses this, for hardware cursor rendering, so having this
|
||||
work properly for the first 2048 scanlines only shouldn't be a problem
|
||||
as the cirrus can't handle large resolutions anyway. Also changing the
|
||||
invalidated_y_table size would break live migration.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20170421091632.30900-4-kraxel@redhat.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/display/vga.c | 14 +++++++++++---
|
||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index 69c3e1d674..3991b88aac 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1434,6 +1434,14 @@ void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
|
||||
}
|
||||
}
|
||||
|
||||
+static bool vga_scanline_invalidated(VGACommonState *s, int y)
|
||||
+{
|
||||
+ if (y >= VGA_MAX_HEIGHT) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ return s->invalidated_y_table[y >> 5] & (1 << (y & 0x1f));
|
||||
+}
|
||||
+
|
||||
void vga_sync_dirty_bitmap(VGACommonState *s)
|
||||
{
|
||||
memory_region_sync_dirty_bitmap(&s->vram);
|
||||
@@ -1638,8 +1646,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
page1 = addr + bwidth - 1;
|
||||
update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
|
||||
DIRTY_MEMORY_VGA);
|
||||
- /* explicit invalidation for the hardware cursor */
|
||||
- update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
|
||||
+ /* explicit invalidation for the hardware cursor (cirrus only) */
|
||||
+ update |= vga_scanline_invalidated(s, y);
|
||||
if (update) {
|
||||
if (y_start < 0)
|
||||
y_start = y;
|
||||
@@ -1686,7 +1694,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
page_max - page_min,
|
||||
DIRTY_MEMORY_VGA);
|
||||
}
|
||||
- memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
|
||||
+ memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table));
|
||||
}
|
||||
|
||||
static void vga_draw_blank(VGACommonState *s, int full_update)
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,114 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 21 Apr 2017 11:16:27 +0200
|
||||
Subject: [PATCH] vga: make display updates thread safe.
|
||||
|
||||
The vga code clears the dirty bits *after* reading the framebuffer
|
||||
memory. So if the guest framebuffer updates hits the race window
|
||||
between vga reading the framebuffer and vga clearing the dirty bits
|
||||
vga will miss that update
|
||||
|
||||
Fix it by using the new memory_region_copy_and_clear_dirty()
|
||||
memory_region_copy_get_dirty() functions. That way we clear the
|
||||
dirty bitmap before reading the framebuffer. Any guest display
|
||||
updates happening in parallel will be properly tracked in the
|
||||
dirty bitmap then and the next display refresh will pick them up.
|
||||
|
||||
Problem triggers with mttcg only. Before mttcg was merged tcg
|
||||
never ran in parallel to vga emulation. Using kvm will hide the
|
||||
problem too, due to qemu operating on a userspace copy of the
|
||||
kernel's dirty bitmap.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20170421091632.30900-5-kraxel@redhat.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/display/vga.c | 36 +++++++++++++++++-------------------
|
||||
1 file changed, 17 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index 3991b88aac..b2516c8d21 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1465,7 +1465,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int y1, y, update, linesize, y_start, double_scan, mask, depth;
|
||||
int width, height, shift_control, line_offset, bwidth, bits;
|
||||
- ram_addr_t page0, page1, page_min, page_max;
|
||||
+ ram_addr_t page0, page1;
|
||||
+ DirtyBitmapSnapshot *snap = NULL;
|
||||
int disp_width, multi_scan, multi_run;
|
||||
uint8_t *d;
|
||||
uint32_t v, addr1, addr;
|
||||
@@ -1480,9 +1481,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
|
||||
full_update |= update_basic_params(s);
|
||||
|
||||
- if (!full_update)
|
||||
- vga_sync_dirty_bitmap(s);
|
||||
-
|
||||
s->get_resolution(s, &width, &height);
|
||||
disp_width = width;
|
||||
|
||||
@@ -1625,11 +1623,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
addr1 = (s->start_addr * 4);
|
||||
bwidth = (width * bits + 7) / 8;
|
||||
y_start = -1;
|
||||
- page_min = -1;
|
||||
- page_max = 0;
|
||||
d = surface_data(surface);
|
||||
linesize = surface_stride(surface);
|
||||
y1 = 0;
|
||||
+
|
||||
+ if (!full_update) {
|
||||
+ vga_sync_dirty_bitmap(s);
|
||||
+ snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1,
|
||||
+ bwidth * height,
|
||||
+ DIRTY_MEMORY_VGA);
|
||||
+ }
|
||||
+
|
||||
for(y = 0; y < height; y++) {
|
||||
addr = addr1;
|
||||
if (!(s->cr[VGA_CRTC_MODE] & 1)) {
|
||||
@@ -1644,17 +1648,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
update = full_update;
|
||||
page0 = addr;
|
||||
page1 = addr + bwidth - 1;
|
||||
- update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
|
||||
- DIRTY_MEMORY_VGA);
|
||||
+ if (full_update) {
|
||||
+ update = 1;
|
||||
+ } else {
|
||||
+ update = memory_region_snapshot_get_dirty(&s->vram, snap,
|
||||
+ page0, page1 - page0);
|
||||
+ }
|
||||
/* explicit invalidation for the hardware cursor (cirrus only) */
|
||||
update |= vga_scanline_invalidated(s, y);
|
||||
if (update) {
|
||||
if (y_start < 0)
|
||||
y_start = y;
|
||||
- if (page0 < page_min)
|
||||
- page_min = page0;
|
||||
- if (page1 > page_max)
|
||||
- page_max = page1;
|
||||
if (!(is_buffer_shared(surface))) {
|
||||
vga_draw_line(s, d, s->vram_ptr + addr, width);
|
||||
if (s->cursor_draw_line)
|
||||
@@ -1687,13 +1691,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
dpy_gfx_update(s->con, 0, y_start,
|
||||
disp_width, y - y_start);
|
||||
}
|
||||
- /* reset modified pages */
|
||||
- if (page_max >= page_min) {
|
||||
- memory_region_reset_dirty(&s->vram,
|
||||
- page_min,
|
||||
- page_max - page_min,
|
||||
- DIRTY_MEMORY_VGA);
|
||||
- }
|
||||
+ g_free(snap);
|
||||
memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table));
|
||||
}
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,37 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 9 May 2017 12:48:39 +0200
|
||||
Subject: [PATCH] vga: fix display update region calculation
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
vga display update mis-calculated the region for the dirty bitmap
|
||||
snapshot in case the scanlines are padded. This can triggere an
|
||||
assert in cpu_physical_memory_snapshot_get_dirty().
|
||||
|
||||
Fixes: fec5e8c92becad223df9d972770522f64aafdb72
|
||||
Reported-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reported-by: 李强 <liqiang6-s@360.cn>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20170509104839.19415-1-kraxel@redhat.com
|
||||
---
|
||||
hw/display/vga.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index b2516c8d21..dcc95f88e2 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1630,7 +1630,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
if (!full_update) {
|
||||
vga_sync_dirty_bitmap(s);
|
||||
snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1,
|
||||
- bwidth * height,
|
||||
+ line_offset * height,
|
||||
DIRTY_MEMORY_VGA);
|
||||
}
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,46 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 1 Sep 2017 14:57:38 +0200
|
||||
Subject: [PATCH] vga: fix display update region calculation (split screen)
|
||||
|
||||
vga display update mis-calculated the region for the dirty bitmap
|
||||
snapshot in case split screen mode is used. This can trigger an
|
||||
assert in cpu_physical_memory_snapshot_get_dirty().
|
||||
|
||||
Impact: DoS for privileged guest users.
|
||||
|
||||
Fixes: CVE-2017-13673
|
||||
Fixes: fec5e8c92becad223df9d972770522f64aafdb72
|
||||
Cc: P J P <ppandit@redhat.com>
|
||||
Reported-by: David Buchanan <d@vidbuchanan.co.uk>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20170828123307.15392-1-kraxel@redhat.com
|
||||
---
|
||||
hw/display/vga.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index dcc95f88e2..533d8d7895 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1628,9 +1628,15 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
y1 = 0;
|
||||
|
||||
if (!full_update) {
|
||||
+ ram_addr_t region_start = addr1;
|
||||
+ ram_addr_t region_end = addr1 + line_offset * height;
|
||||
vga_sync_dirty_bitmap(s);
|
||||
- snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1,
|
||||
- line_offset * height,
|
||||
+ if (s->line_compare < height) {
|
||||
+ /* split screen mode */
|
||||
+ region_start = 0;
|
||||
+ }
|
||||
+ snap = memory_region_snapshot_and_clear_dirty(&s->vram, region_start,
|
||||
+ region_end - region_start,
|
||||
DIRTY_MEMORY_VGA);
|
||||
}
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,497 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 1 Sep 2017 14:57:39 +0200
|
||||
Subject: [PATCH] vga: stop passing pointers to vga_draw_line* functions
|
||||
|
||||
Instead pass around the address (aka offset into vga memory).
|
||||
Add vga_read_* helper functions which apply vbe_size_mask to
|
||||
the address, to make sure the address stays within the valid
|
||||
range, similar to the cirrus blitter fixes (commits ffaf857778
|
||||
and 026aeffcb4).
|
||||
|
||||
Impact: DoS for privileged guest users. qemu crashes with
|
||||
a segfault, when hitting the guard page after vga memory
|
||||
allocation, while reading vga memory for display updates.
|
||||
|
||||
Fixes: CVE-2017-13672
|
||||
Cc: P J P <ppandit@redhat.com>
|
||||
Reported-by: David Buchanan <d@vidbuchanan.co.uk>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20170828122906.18993-1-kraxel@redhat.com
|
||||
---
|
||||
hw/display/vga-helpers.h | 202 ++++++++++++++++++++++++++---------------------
|
||||
hw/display/vga.c | 5 +-
|
||||
hw/display/vga_int.h | 1 +
|
||||
3 files changed, 114 insertions(+), 94 deletions(-)
|
||||
|
||||
diff --git a/hw/display/vga-helpers.h b/hw/display/vga-helpers.h
|
||||
index 94f6de2046..5a752b3f9e 100644
|
||||
--- a/hw/display/vga-helpers.h
|
||||
+++ b/hw/display/vga-helpers.h
|
||||
@@ -95,20 +95,46 @@ static void vga_draw_glyph9(uint8_t *d, int linesize,
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
+static inline uint8_t vga_read_byte(VGACommonState *vga, uint32_t addr)
|
||||
+{
|
||||
+ return vga->vram_ptr[addr & vga->vbe_size_mask];
|
||||
+}
|
||||
+
|
||||
+static inline uint16_t vga_read_word_le(VGACommonState *vga, uint32_t addr)
|
||||
+{
|
||||
+ uint32_t offset = addr & vga->vbe_size_mask & ~1;
|
||||
+ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset);
|
||||
+ return lduw_le_p(ptr);
|
||||
+}
|
||||
+
|
||||
+static inline uint16_t vga_read_word_be(VGACommonState *vga, uint32_t addr)
|
||||
+{
|
||||
+ uint32_t offset = addr & vga->vbe_size_mask & ~1;
|
||||
+ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset);
|
||||
+ return lduw_be_p(ptr);
|
||||
+}
|
||||
+
|
||||
+static inline uint32_t vga_read_dword_le(VGACommonState *vga, uint32_t addr)
|
||||
+{
|
||||
+ uint32_t offset = addr & vga->vbe_size_mask & ~3;
|
||||
+ uint32_t *ptr = (uint32_t *)(vga->vram_ptr + offset);
|
||||
+ return ldl_le_p(ptr);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* 4 color mode
|
||||
*/
|
||||
-static void vga_draw_line2(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line2(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
uint32_t plane_mask, *palette, data, v;
|
||||
int x;
|
||||
|
||||
- palette = s1->last_palette;
|
||||
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
+ palette = vga->last_palette;
|
||||
+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
- data = ((uint32_t *)s)[0];
|
||||
+ data = vga_read_dword_le(vga, addr);
|
||||
data &= plane_mask;
|
||||
v = expand2[GET_PLANE(data, 0)];
|
||||
v |= expand2[GET_PLANE(data, 2)] << 2;
|
||||
@@ -124,7 +150,7 @@ static void vga_draw_line2(VGACommonState *s1, uint8_t *d,
|
||||
((uint32_t *)d)[6] = palette[(v >> 4) & 0xf];
|
||||
((uint32_t *)d)[7] = palette[(v >> 0) & 0xf];
|
||||
d += 32;
|
||||
- s += 4;
|
||||
+ addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,17 +160,17 @@ static void vga_draw_line2(VGACommonState *s1, uint8_t *d,
|
||||
/*
|
||||
* 4 color mode, dup2 horizontal
|
||||
*/
|
||||
-static void vga_draw_line2d2(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line2d2(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
uint32_t plane_mask, *palette, data, v;
|
||||
int x;
|
||||
|
||||
- palette = s1->last_palette;
|
||||
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
+ palette = vga->last_palette;
|
||||
+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
- data = ((uint32_t *)s)[0];
|
||||
+ data = vga_read_dword_le(vga, addr);
|
||||
data &= plane_mask;
|
||||
v = expand2[GET_PLANE(data, 0)];
|
||||
v |= expand2[GET_PLANE(data, 2)] << 2;
|
||||
@@ -160,24 +186,24 @@ static void vga_draw_line2d2(VGACommonState *s1, uint8_t *d,
|
||||
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
|
||||
d += 64;
|
||||
- s += 4;
|
||||
+ addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 color mode
|
||||
*/
|
||||
-static void vga_draw_line4(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line4(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
uint32_t plane_mask, data, v, *palette;
|
||||
int x;
|
||||
|
||||
- palette = s1->last_palette;
|
||||
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
+ palette = vga->last_palette;
|
||||
+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
- data = ((uint32_t *)s)[0];
|
||||
+ data = vga_read_dword_le(vga, addr);
|
||||
data &= plane_mask;
|
||||
v = expand4[GET_PLANE(data, 0)];
|
||||
v |= expand4[GET_PLANE(data, 1)] << 1;
|
||||
@@ -192,24 +218,24 @@ static void vga_draw_line4(VGACommonState *s1, uint8_t *d,
|
||||
((uint32_t *)d)[6] = palette[(v >> 4) & 0xf];
|
||||
((uint32_t *)d)[7] = palette[(v >> 0) & 0xf];
|
||||
d += 32;
|
||||
- s += 4;
|
||||
+ addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 color mode, dup2 horizontal
|
||||
*/
|
||||
-static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line4d2(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
uint32_t plane_mask, data, v, *palette;
|
||||
int x;
|
||||
|
||||
- palette = s1->last_palette;
|
||||
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
+ palette = vga->last_palette;
|
||||
+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
- data = ((uint32_t *)s)[0];
|
||||
+ data = vga_read_dword_le(vga, addr);
|
||||
data &= plane_mask;
|
||||
v = expand4[GET_PLANE(data, 0)];
|
||||
v |= expand4[GET_PLANE(data, 1)] << 1;
|
||||
@@ -224,7 +250,7 @@ static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d,
|
||||
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
|
||||
d += 64;
|
||||
- s += 4;
|
||||
+ addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,21 +259,21 @@ static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d,
|
||||
*
|
||||
* XXX: add plane_mask support (never used in standard VGA modes)
|
||||
*/
|
||||
-static void vga_draw_line8d2(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line8d2(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
uint32_t *palette;
|
||||
int x;
|
||||
|
||||
- palette = s1->last_palette;
|
||||
+ palette = vga->last_palette;
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
- PUT_PIXEL2(d, 0, palette[s[0]]);
|
||||
- PUT_PIXEL2(d, 1, palette[s[1]]);
|
||||
- PUT_PIXEL2(d, 2, palette[s[2]]);
|
||||
- PUT_PIXEL2(d, 3, palette[s[3]]);
|
||||
+ PUT_PIXEL2(d, 0, palette[vga_read_byte(vga, addr + 0)]);
|
||||
+ PUT_PIXEL2(d, 1, palette[vga_read_byte(vga, addr + 1)]);
|
||||
+ PUT_PIXEL2(d, 2, palette[vga_read_byte(vga, addr + 2)]);
|
||||
+ PUT_PIXEL2(d, 3, palette[vga_read_byte(vga, addr + 3)]);
|
||||
d += 32;
|
||||
- s += 4;
|
||||
+ addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,63 +282,63 @@ static void vga_draw_line8d2(VGACommonState *s1, uint8_t *d,
|
||||
*
|
||||
* XXX: add plane_mask support (never used in standard VGA modes)
|
||||
*/
|
||||
-static void vga_draw_line8(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line8(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
uint32_t *palette;
|
||||
int x;
|
||||
|
||||
- palette = s1->last_palette;
|
||||
+ palette = vga->last_palette;
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
- ((uint32_t *)d)[0] = palette[s[0]];
|
||||
- ((uint32_t *)d)[1] = palette[s[1]];
|
||||
- ((uint32_t *)d)[2] = palette[s[2]];
|
||||
- ((uint32_t *)d)[3] = palette[s[3]];
|
||||
- ((uint32_t *)d)[4] = palette[s[4]];
|
||||
- ((uint32_t *)d)[5] = palette[s[5]];
|
||||
- ((uint32_t *)d)[6] = palette[s[6]];
|
||||
- ((uint32_t *)d)[7] = palette[s[7]];
|
||||
+ ((uint32_t *)d)[0] = palette[vga_read_byte(vga, addr + 0)];
|
||||
+ ((uint32_t *)d)[1] = palette[vga_read_byte(vga, addr + 1)];
|
||||
+ ((uint32_t *)d)[2] = palette[vga_read_byte(vga, addr + 2)];
|
||||
+ ((uint32_t *)d)[3] = palette[vga_read_byte(vga, addr + 3)];
|
||||
+ ((uint32_t *)d)[4] = palette[vga_read_byte(vga, addr + 4)];
|
||||
+ ((uint32_t *)d)[5] = palette[vga_read_byte(vga, addr + 5)];
|
||||
+ ((uint32_t *)d)[6] = palette[vga_read_byte(vga, addr + 6)];
|
||||
+ ((uint32_t *)d)[7] = palette[vga_read_byte(vga, addr + 7)];
|
||||
d += 32;
|
||||
- s += 8;
|
||||
+ addr += 8;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 15 bit color
|
||||
*/
|
||||
-static void vga_draw_line15_le(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line15_le(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- v = lduw_le_p((void *)s);
|
||||
+ v = vga_read_word_le(vga, addr);
|
||||
r = (v >> 7) & 0xf8;
|
||||
g = (v >> 2) & 0xf8;
|
||||
b = (v << 3) & 0xf8;
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 2;
|
||||
+ addr += 2;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
}
|
||||
|
||||
-static void vga_draw_line15_be(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line15_be(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- v = lduw_be_p((void *)s);
|
||||
+ v = vga_read_word_be(vga, addr);
|
||||
r = (v >> 7) & 0xf8;
|
||||
g = (v >> 2) & 0xf8;
|
||||
b = (v << 3) & 0xf8;
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 2;
|
||||
+ addr += 2;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
}
|
||||
@@ -320,38 +346,38 @@ static void vga_draw_line15_be(VGACommonState *s1, uint8_t *d,
|
||||
/*
|
||||
* 16 bit color
|
||||
*/
|
||||
-static void vga_draw_line16_le(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line16_le(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- v = lduw_le_p((void *)s);
|
||||
+ v = vga_read_word_le(vga, addr);
|
||||
r = (v >> 8) & 0xf8;
|
||||
g = (v >> 3) & 0xfc;
|
||||
b = (v << 3) & 0xf8;
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 2;
|
||||
+ addr += 2;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
}
|
||||
|
||||
-static void vga_draw_line16_be(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line16_be(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- v = lduw_be_p((void *)s);
|
||||
+ v = vga_read_word_be(vga, addr);
|
||||
r = (v >> 8) & 0xf8;
|
||||
g = (v >> 3) & 0xfc;
|
||||
b = (v << 3) & 0xf8;
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 2;
|
||||
+ addr += 2;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
}
|
||||
@@ -359,36 +385,36 @@ static void vga_draw_line16_be(VGACommonState *s1, uint8_t *d,
|
||||
/*
|
||||
* 24 bit color
|
||||
*/
|
||||
-static void vga_draw_line24_le(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line24_le(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- b = s[0];
|
||||
- g = s[1];
|
||||
- r = s[2];
|
||||
+ b = vga_read_byte(vga, addr + 0);
|
||||
+ g = vga_read_byte(vga, addr + 1);
|
||||
+ r = vga_read_byte(vga, addr + 2);
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 3;
|
||||
+ addr += 3;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
}
|
||||
|
||||
-static void vga_draw_line24_be(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line24_be(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- r = s[0];
|
||||
- g = s[1];
|
||||
- b = s[2];
|
||||
+ r = vga_read_byte(vga, addr + 0);
|
||||
+ g = vga_read_byte(vga, addr + 1);
|
||||
+ b = vga_read_byte(vga, addr + 2);
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 3;
|
||||
+ addr += 3;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
}
|
||||
@@ -396,44 +422,36 @@ static void vga_draw_line24_be(VGACommonState *s1, uint8_t *d,
|
||||
/*
|
||||
* 32 bit color
|
||||
*/
|
||||
-static void vga_draw_line32_le(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line32_le(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
-#ifndef HOST_WORDS_BIGENDIAN
|
||||
- memcpy(d, s, width * 4);
|
||||
-#else
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- b = s[0];
|
||||
- g = s[1];
|
||||
- r = s[2];
|
||||
+ b = vga_read_byte(vga, addr + 0);
|
||||
+ g = vga_read_byte(vga, addr + 1);
|
||||
+ r = vga_read_byte(vga, addr + 2);
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 4;
|
||||
+ addr += 4;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
-#endif
|
||||
}
|
||||
|
||||
-static void vga_draw_line32_be(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line32_be(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
-#ifdef HOST_WORDS_BIGENDIAN
|
||||
- memcpy(d, s, width * 4);
|
||||
-#else
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- r = s[1];
|
||||
- g = s[2];
|
||||
- b = s[3];
|
||||
+ r = vga_read_byte(vga, addr + 1);
|
||||
+ g = vga_read_byte(vga, addr + 2);
|
||||
+ b = vga_read_byte(vga, addr + 3);
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 4;
|
||||
+ addr += 4;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
-#endif
|
||||
}
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index 533d8d7895..13e4a5d55d 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1005,7 +1005,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
|
||||
}
|
||||
|
||||
typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width);
|
||||
+ uint32_t srcaddr, int width);
|
||||
|
||||
#include "vga-helpers.h"
|
||||
|
||||
@@ -1666,7 +1666,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
if (y_start < 0)
|
||||
y_start = y;
|
||||
if (!(is_buffer_shared(surface))) {
|
||||
- vga_draw_line(s, d, s->vram_ptr + addr, width);
|
||||
+ vga_draw_line(s, d, addr, width);
|
||||
if (s->cursor_draw_line)
|
||||
s->cursor_draw_line(s, d, y);
|
||||
}
|
||||
@@ -2170,6 +2170,7 @@ void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
|
||||
if (!s->vbe_size) {
|
||||
s->vbe_size = s->vram_size;
|
||||
}
|
||||
+ s->vbe_size_mask = s->vbe_size - 1;
|
||||
|
||||
s->is_vbe_vmstate = 1;
|
||||
memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size,
|
||||
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
|
||||
index dd6c958da3..ad34a1f048 100644
|
||||
--- a/hw/display/vga_int.h
|
||||
+++ b/hw/display/vga_int.h
|
||||
@@ -94,6 +94,7 @@ typedef struct VGACommonState {
|
||||
uint32_t vram_size;
|
||||
uint32_t vram_size_mb; /* property */
|
||||
uint32_t vbe_size;
|
||||
+ uint32_t vbe_size_mask;
|
||||
uint32_t latch;
|
||||
bool has_chain4_alias;
|
||||
MemoryRegion chain4_alias;
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,61 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Thu, 7 Sep 2017 12:02:56 +0530
|
||||
Subject: [PATCH] multiboot: validate multiboot header address values
|
||||
|
||||
While loading kernel via multiboot-v1 image, (flags & 0x00010000)
|
||||
indicates that multiboot header contains valid addresses to load
|
||||
the kernel image. These addresses are used to compute kernel
|
||||
size and kernel text offset in the OS image. Validate these
|
||||
address values to avoid an OOB access issue.
|
||||
|
||||
This is CVE-2017-14167.
|
||||
|
||||
Reported-by: Thomas Garnier <thgarnie@google.com>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
---
|
||||
hw/i386/multiboot.c | 19 +++++++++++++++++++
|
||||
1 file changed, 19 insertions(+)
|
||||
|
||||
diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c
|
||||
index f13e23139b..22688d376d 100644
|
||||
--- a/hw/i386/multiboot.c
|
||||
+++ b/hw/i386/multiboot.c
|
||||
@@ -221,15 +221,34 @@ int load_multiboot(FWCfgState *fw_cfg,
|
||||
uint32_t mh_header_addr = ldl_p(header+i+12);
|
||||
uint32_t mh_load_end_addr = ldl_p(header+i+20);
|
||||
uint32_t mh_bss_end_addr = ldl_p(header+i+24);
|
||||
+
|
||||
mh_load_addr = ldl_p(header+i+16);
|
||||
+ if (mh_header_addr < mh_load_addr) {
|
||||
+ fprintf(stderr, "invalid mh_load_addr address\n");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
|
||||
uint32_t mb_load_size = 0;
|
||||
mh_entry_addr = ldl_p(header+i+28);
|
||||
|
||||
if (mh_load_end_addr) {
|
||||
+ if (mh_bss_end_addr < mh_load_addr) {
|
||||
+ fprintf(stderr, "invalid mh_bss_end_addr address\n");
|
||||
+ exit(1);
|
||||
+ }
|
||||
mb_kernel_size = mh_bss_end_addr - mh_load_addr;
|
||||
+
|
||||
+ if (mh_load_end_addr < mh_load_addr) {
|
||||
+ fprintf(stderr, "invalid mh_load_end_addr address\n");
|
||||
+ exit(1);
|
||||
+ }
|
||||
mb_load_size = mh_load_end_addr - mh_load_addr;
|
||||
} else {
|
||||
+ if (kernel_file_size < mb_kernel_text_offset) {
|
||||
+ fprintf(stderr, "invalid kernel_file_size\n");
|
||||
+ exit(1);
|
||||
+ }
|
||||
mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
|
||||
mb_load_size = mb_kernel_size;
|
||||
}
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,57 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
Date: Wed, 20 Sep 2017 08:09:33 +0200
|
||||
Subject: [PATCH] virtio: fix descriptor counting in virtqueue_pop
|
||||
|
||||
While changing the s/g list allocation, commit 3b3b0628
|
||||
also changed the descriptor counting to count iovec entries
|
||||
as split by cpu_physical_memory_map(). Previously only the
|
||||
actual descriptor entries were counted and the split into
|
||||
the iovec happened afterwards in virtqueue_map().
|
||||
Count the entries again instead to avoid erroneous
|
||||
"Looped descriptor" errors.
|
||||
|
||||
Reported-by: Hans Middelhoek <h.middelhoek@ospito.nl>
|
||||
Link: https://forum.proxmox.com/threads/vm-crash-with-memory-hotplug.35904/
|
||||
Fixes: 3b3b0628217e ("virtio: slim down allocation of VirtQueueElements")
|
||||
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
hw/virtio/virtio.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
|
||||
index 890b4d7eb7..33bb770177 100644
|
||||
--- a/hw/virtio/virtio.c
|
||||
+++ b/hw/virtio/virtio.c
|
||||
@@ -834,7 +834,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
|
||||
int64_t len;
|
||||
VirtIODevice *vdev = vq->vdev;
|
||||
VirtQueueElement *elem = NULL;
|
||||
- unsigned out_num, in_num;
|
||||
+ unsigned out_num, in_num, elem_entries;
|
||||
hwaddr addr[VIRTQUEUE_MAX_SIZE];
|
||||
struct iovec iov[VIRTQUEUE_MAX_SIZE];
|
||||
VRingDesc desc;
|
||||
@@ -852,7 +852,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
|
||||
smp_rmb();
|
||||
|
||||
/* When we start there are none of either input nor output. */
|
||||
- out_num = in_num = 0;
|
||||
+ out_num = in_num = elem_entries = 0;
|
||||
|
||||
max = vq->vring.num;
|
||||
|
||||
@@ -922,7 +922,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
|
||||
}
|
||||
|
||||
/* If we've got too many, that implies a descriptor loop. */
|
||||
- if ((in_num + out_num) > max) {
|
||||
+ if (++elem_entries > max) {
|
||||
virtio_error(vdev, "Looped descriptor");
|
||||
goto err_undo_map;
|
||||
}
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,30 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
Date: Wed, 29 Nov 2017 09:39:55 +0100
|
||||
Subject: [PATCH] nbd/server: CVE-2017-15119 Reject options larger than 32M
|
||||
|
||||
Backported-from: fdad35ef6c58
|
||||
---
|
||||
nbd/server.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/nbd/server.c b/nbd/server.c
|
||||
index a98bb21a0a..4d6da8ac06 100644
|
||||
--- a/nbd/server.c
|
||||
+++ b/nbd/server.c
|
||||
@@ -489,6 +489,12 @@ static int nbd_negotiate_options(NBDClient *client)
|
||||
}
|
||||
length = be32_to_cpu(length);
|
||||
|
||||
+ if (length > NBD_MAX_BUFFER_SIZE) {
|
||||
+ LOG("len (%" PRIu32" ) is larger than max len (%u)",
|
||||
+ length, NBD_MAX_BUFFER_SIZE);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
TRACE("Checking option 0x%" PRIx32, clientflags);
|
||||
if (client->tlscreds &&
|
||||
client->ioc == (QIOChannel *)client->sioc) {
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,32 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
|
||||
Date: Fri, 4 Aug 2017 12:33:29 +0100
|
||||
Subject: [PATCH] vga/migration: Update memory map in post_load
|
||||
|
||||
After migration the chain4 alias mapping added by 80763888 (in 2011)
|
||||
might be missing, since there's no call to vga_update_memory_access
|
||||
in the post_load after the registers are updated. Add it back.
|
||||
|
||||
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
Reviewed-by: Juan Quintela <quintela@redhat.com>
|
||||
Message-id: 20170804113329.13609-1-dgilbert@redhat.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/display/vga.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index 13e4a5d55d..a99d831e04 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -2050,6 +2050,7 @@ static int vga_common_post_load(void *opaque, int version_id)
|
||||
/* force refresh */
|
||||
s->graphic_mode = -1;
|
||||
vbe_update_vgaregs(s);
|
||||
+ vga_update_memory_access(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,52 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 10 Oct 2017 16:13:21 +0200
|
||||
Subject: [PATCH] vga: drop line_offset variable
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/display/vga.c | 7 +++----
|
||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index a99d831e04..77af807a51 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1464,7 +1464,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
{
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int y1, y, update, linesize, y_start, double_scan, mask, depth;
|
||||
- int width, height, shift_control, line_offset, bwidth, bits;
|
||||
+ int width, height, shift_control, bwidth, bits;
|
||||
ram_addr_t page0, page1;
|
||||
DirtyBitmapSnapshot *snap = NULL;
|
||||
int disp_width, multi_scan, multi_run;
|
||||
@@ -1614,7 +1614,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
s->cursor_invalidate(s);
|
||||
}
|
||||
|
||||
- line_offset = s->line_offset;
|
||||
#if 0
|
||||
printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
|
||||
width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
|
||||
@@ -1629,7 +1628,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
|
||||
if (!full_update) {
|
||||
ram_addr_t region_start = addr1;
|
||||
- ram_addr_t region_end = addr1 + line_offset * height;
|
||||
+ ram_addr_t region_end = addr1 + s->line_offset * height;
|
||||
vga_sync_dirty_bitmap(s);
|
||||
if (s->line_compare < height) {
|
||||
/* split screen mode */
|
||||
@@ -1681,7 +1680,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
if (!multi_run) {
|
||||
mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
|
||||
if ((y1 & mask) == mask)
|
||||
- addr1 += line_offset;
|
||||
+ addr1 += s->line_offset;
|
||||
y1++;
|
||||
multi_run = multi_scan;
|
||||
} else {
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,103 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 10 Oct 2017 16:13:22 +0200
|
||||
Subject: [PATCH] vga: handle cirrus vbe mode wraparounds.
|
||||
|
||||
Commit "3d90c62548 vga: stop passing pointers to vga_draw_line*
|
||||
functions" is incomplete. It doesn't handle the case that the vga
|
||||
rendering code tries to create a shared surface, i.e. a pixman image
|
||||
backed by vga video memory. That can not work in case the guest display
|
||||
wraps from end of video memory to the start. So force shadowing in that
|
||||
case. Also adjust the snapshot region calculation.
|
||||
|
||||
Can trigger with cirrus only, when programming vbe modes using the bochs
|
||||
api (stdvga, also qxl and virtio-vga in vga compat mode) wrap arounds
|
||||
can't happen.
|
||||
|
||||
Fixes: CVE-2017-13672
|
||||
Fixes: 3d90c6254863693a6b13d918d2b8682e08bbc681
|
||||
Cc: P J P <ppandit@redhat.com>
|
||||
Reported-by: David Buchanan <d@vidbuchanan.co.uk>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20171010141323.14049-3-kraxel@redhat.com
|
||||
---
|
||||
hw/display/vga.c | 28 +++++++++++++++++++++-------
|
||||
1 file changed, 21 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index 77af807a51..7bdbf7441e 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1465,13 +1465,13 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int y1, y, update, linesize, y_start, double_scan, mask, depth;
|
||||
int width, height, shift_control, bwidth, bits;
|
||||
- ram_addr_t page0, page1;
|
||||
+ ram_addr_t page0, page1, region_start, region_end;
|
||||
DirtyBitmapSnapshot *snap = NULL;
|
||||
int disp_width, multi_scan, multi_run;
|
||||
uint8_t *d;
|
||||
uint32_t v, addr1, addr;
|
||||
vga_draw_line_func *vga_draw_line = NULL;
|
||||
- bool share_surface;
|
||||
+ bool share_surface, force_shadow = false;
|
||||
pixman_format_code_t format;
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
bool byteswap = !s->big_endian_fb;
|
||||
@@ -1484,6 +1484,15 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
s->get_resolution(s, &width, &height);
|
||||
disp_width = width;
|
||||
|
||||
+ region_start = (s->start_addr * 4);
|
||||
+ region_end = region_start + s->line_offset * height;
|
||||
+ if (region_end > s->vbe_size) {
|
||||
+ /* wraps around (can happen with cirrus vbe modes) */
|
||||
+ region_start = 0;
|
||||
+ region_end = s->vbe_size;
|
||||
+ force_shadow = true;
|
||||
+ }
|
||||
+
|
||||
shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
|
||||
double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
|
||||
if (shift_control != 1) {
|
||||
@@ -1523,7 +1532,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
format = qemu_default_pixman_format(depth, !byteswap);
|
||||
if (format) {
|
||||
share_surface = dpy_gfx_check_format(s->con, format)
|
||||
- && !s->force_shadow;
|
||||
+ && !s->force_shadow && !force_shadow;
|
||||
} else {
|
||||
share_surface = false;
|
||||
}
|
||||
@@ -1627,8 +1636,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
y1 = 0;
|
||||
|
||||
if (!full_update) {
|
||||
- ram_addr_t region_start = addr1;
|
||||
- ram_addr_t region_end = addr1 + s->line_offset * height;
|
||||
vga_sync_dirty_bitmap(s);
|
||||
if (s->line_compare < height) {
|
||||
/* split screen mode */
|
||||
@@ -1651,10 +1658,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
addr = (addr & ~0x8000) | ((y1 & 2) << 14);
|
||||
}
|
||||
update = full_update;
|
||||
- page0 = addr;
|
||||
- page1 = addr + bwidth - 1;
|
||||
+ page0 = addr & s->vbe_size_mask;
|
||||
+ page1 = (addr + bwidth - 1) & s->vbe_size_mask;
|
||||
if (full_update) {
|
||||
update = 1;
|
||||
+ } else if (page1 < page0) {
|
||||
+ /* scanline wraps from end of video memory to the start */
|
||||
+ assert(force_shadow);
|
||||
+ update = memory_region_snapshot_get_dirty(&s->vram, snap,
|
||||
+ page0, 0);
|
||||
+ update |= memory_region_snapshot_get_dirty(&s->vram, snap,
|
||||
+ page1, 0);
|
||||
} else {
|
||||
update = memory_region_snapshot_get_dirty(&s->vram, snap,
|
||||
page0, page1 - page0);
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,30 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 10 Oct 2017 16:13:23 +0200
|
||||
Subject: [PATCH] vga: add ram_addr_t cast
|
||||
|
||||
Reported by Coverity.
|
||||
|
||||
Fixes: CID 1381409
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20171010141323.14049-4-kraxel@redhat.com
|
||||
---
|
||||
hw/display/vga.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index 7bdbf7441e..63ba404ef2 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1485,7 +1485,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
disp_width = width;
|
||||
|
||||
region_start = (s->start_addr * 4);
|
||||
- region_end = region_start + s->line_offset * height;
|
||||
+ region_end = region_start + (ram_addr_t)s->line_offset * height;
|
||||
if (region_end > s->vbe_size) {
|
||||
/* wraps around (can happen with cirrus vbe modes) */
|
||||
region_start = 0;
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,32 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Mon, 30 Oct 2017 11:28:30 +0100
|
||||
Subject: [PATCH] vga: fix region checks in wraparound case
|
||||
|
||||
Cc: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
Message-id: 20171030102830.4469-1-kraxel@redhat.com
|
||||
---
|
||||
hw/display/vga.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index 63ba404ef2..a58d8bcd67 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1666,9 +1666,9 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
/* scanline wraps from end of video memory to the start */
|
||||
assert(force_shadow);
|
||||
update = memory_region_snapshot_get_dirty(&s->vram, snap,
|
||||
- page0, 0);
|
||||
+ page0, s->vbe_size - page0);
|
||||
update |= memory_region_snapshot_get_dirty(&s->vram, snap,
|
||||
- page1, 0);
|
||||
+ 0, page1);
|
||||
} else {
|
||||
update = memory_region_snapshot_get_dirty(&s->vram, snap,
|
||||
page0, page1 - page0);
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,54 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: "Daniel P. Berrange" <berrange@redhat.com>
|
||||
Date: Mon, 9 Oct 2017 14:43:42 +0100
|
||||
Subject: [PATCH] io: monitor encoutput buffer size from websocket GSource
|
||||
|
||||
The websocket GSource is monitoring the size of the rawoutput
|
||||
buffer to determine if the channel can accepts more writes.
|
||||
The rawoutput buffer, however, is merely a temporary staging
|
||||
buffer before data is copied into the encoutput buffer. Thus
|
||||
its size will always be zero when the GSource runs.
|
||||
|
||||
This flaw causes the encoutput buffer to grow without bound
|
||||
if the other end of the underlying data channel doesn't
|
||||
read data being sent. This can be seen with VNC if a client
|
||||
is on a slow WAN link and the guest OS is sending many screen
|
||||
updates. A malicious VNC client can act like it is on a slow
|
||||
link by playing a video in the guest and then reading data
|
||||
very slowly, causing QEMU host memory to expand arbitrarily.
|
||||
|
||||
This issue is assigned CVE-2017-15268, publically reported in
|
||||
|
||||
https://bugs.launchpad.net/qemu/+bug/1718964
|
||||
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
|
||||
---
|
||||
io/channel-websock.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/io/channel-websock.c b/io/channel-websock.c
|
||||
index 8fabadea2f..882bbb4cbc 100644
|
||||
--- a/io/channel-websock.c
|
||||
+++ b/io/channel-websock.c
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
-/* Max amount to allow in rawinput/rawoutput buffers */
|
||||
+/* Max amount to allow in rawinput/encoutput buffers */
|
||||
#define QIO_CHANNEL_WEBSOCK_MAX_BUFFER 8192
|
||||
|
||||
#define QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN 24
|
||||
@@ -1006,7 +1006,7 @@ qio_channel_websock_source_prepare(GSource *source,
|
||||
if (wsource->wioc->rawinput.offset) {
|
||||
cond |= G_IO_IN;
|
||||
}
|
||||
- if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) {
|
||||
+ if (wsource->wioc->encoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) {
|
||||
cond |= G_IO_OUT;
|
||||
}
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,43 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Mon, 16 Oct 2017 14:21:59 +0200
|
||||
Subject: [PATCH] 9pfs: use g_malloc0 to allocate space for xattr
|
||||
|
||||
9p back-end first queries the size of an extended attribute,
|
||||
allocates space for it via g_malloc() and then retrieves its
|
||||
value into allocated buffer. Race between querying attribute
|
||||
size and retrieving its could lead to memory bytes disclosure.
|
||||
Use g_malloc0() to avoid it.
|
||||
|
||||
Reported-by: Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.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 c80ba67389..aaf9935ef4 100644
|
||||
--- a/hw/9pfs/9p.c
|
||||
+++ b/hw/9pfs/9p.c
|
||||
@@ -3220,7 +3220,7 @@ static void coroutine_fn v9fs_xattrwalk(void *opaque)
|
||||
xattr_fidp->fid_type = P9_FID_XATTR;
|
||||
xattr_fidp->fs.xattr.xattrwalk_fid = true;
|
||||
if (size) {
|
||||
- xattr_fidp->fs.xattr.value = g_malloc(size);
|
||||
+ xattr_fidp->fs.xattr.value = g_malloc0(size);
|
||||
err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
|
||||
xattr_fidp->fs.xattr.value,
|
||||
xattr_fidp->fs.xattr.len);
|
||||
@@ -3253,7 +3253,7 @@ static void coroutine_fn v9fs_xattrwalk(void *opaque)
|
||||
xattr_fidp->fid_type = P9_FID_XATTR;
|
||||
xattr_fidp->fs.xattr.xattrwalk_fid = true;
|
||||
if (size) {
|
||||
- xattr_fidp->fs.xattr.value = g_malloc(size);
|
||||
+ xattr_fidp->fs.xattr.value = g_malloc0(size);
|
||||
err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
|
||||
&name, xattr_fidp->fs.xattr.value,
|
||||
xattr_fidp->fs.xattr.len);
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,58 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Wed, 11 Oct 2017 10:43:14 +0200
|
||||
Subject: [PATCH] cirrus: fix oob access in mode4and5 write functions
|
||||
|
||||
Move dst calculation into the loop, so we apply the mask on each
|
||||
interation and will not overflow vga memory.
|
||||
|
||||
Cc: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Reported-by: Niu Guoxiang <niuguoxiang@huawei.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20171011084314.21752-1-kraxel@redhat.com
|
||||
---
|
||||
hw/display/cirrus_vga.c | 6 ++----
|
||||
1 file changed, 2 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
|
||||
index afc290ab91..077a8cb74f 100644
|
||||
--- a/hw/display/cirrus_vga.c
|
||||
+++ b/hw/display/cirrus_vga.c
|
||||
@@ -2038,15 +2038,14 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
|
||||
unsigned val = mem_value;
|
||||
uint8_t *dst;
|
||||
|
||||
- dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask);
|
||||
for (x = 0; x < 8; x++) {
|
||||
+ dst = s->vga.vram_ptr + ((offset + x) & s->cirrus_addr_mask);
|
||||
if (val & 0x80) {
|
||||
*dst = s->cirrus_shadow_gr1;
|
||||
} else if (mode == 5) {
|
||||
*dst = s->cirrus_shadow_gr0;
|
||||
}
|
||||
val <<= 1;
|
||||
- dst++;
|
||||
}
|
||||
memory_region_set_dirty(&s->vga.vram, offset, 8);
|
||||
}
|
||||
@@ -2060,8 +2059,8 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
|
||||
unsigned val = mem_value;
|
||||
uint8_t *dst;
|
||||
|
||||
- dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask);
|
||||
for (x = 0; x < 8; x++) {
|
||||
+ dst = s->vga.vram_ptr + ((offset + 2 * x) & s->cirrus_addr_mask & ~1);
|
||||
if (val & 0x80) {
|
||||
*dst = s->cirrus_shadow_gr1;
|
||||
*(dst + 1) = s->vga.gr[0x11];
|
||||
@@ -2070,7 +2069,6 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
|
||||
*(dst + 1) = s->vga.gr[0x10];
|
||||
}
|
||||
val <<= 1;
|
||||
- dst += 2;
|
||||
}
|
||||
memory_region_set_dirty(&s->vga.vram, offset, 16);
|
||||
}
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,68 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Wed, 29 Nov 2017 23:14:27 +0530
|
||||
Subject: [PATCH] virtio: check VirtQueue Vring object is set
|
||||
|
||||
A guest could attempt to use an uninitialised VirtQueue object
|
||||
or unset Vring.align leading to a arithmetic exception. Add check
|
||||
to avoid it.
|
||||
|
||||
Reported-by: Zhangboxian <zhangboxian@huawei.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: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
|
||||
---
|
||||
hw/virtio/virtio.c | 14 +++++++++++---
|
||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
|
||||
index 33bb770177..76b9a9907c 100644
|
||||
--- a/hw/virtio/virtio.c
|
||||
+++ b/hw/virtio/virtio.c
|
||||
@@ -183,7 +183,7 @@ void virtio_queue_update_rings(VirtIODevice *vdev, int n)
|
||||
{
|
||||
VRing *vring = &vdev->vq[n].vring;
|
||||
|
||||
- if (!vring->desc) {
|
||||
+ if (!vring->num || !vring->desc || !vring->align) {
|
||||
/* not yet setup -> nothing to do */
|
||||
return;
|
||||
}
|
||||
@@ -1416,6 +1416,9 @@ void virtio_config_modern_writel(VirtIODevice *vdev,
|
||||
|
||||
void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr)
|
||||
{
|
||||
+ if (!vdev->vq[n].vring.num) {
|
||||
+ return;
|
||||
+ }
|
||||
vdev->vq[n].vring.desc = addr;
|
||||
virtio_queue_update_rings(vdev, n);
|
||||
}
|
||||
@@ -1428,6 +1431,9 @@ hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n)
|
||||
void virtio_queue_set_rings(VirtIODevice *vdev, int n, hwaddr desc,
|
||||
hwaddr avail, hwaddr used)
|
||||
{
|
||||
+ if (!vdev->vq[n].vring.num) {
|
||||
+ return;
|
||||
+ }
|
||||
vdev->vq[n].vring.desc = desc;
|
||||
vdev->vq[n].vring.avail = avail;
|
||||
vdev->vq[n].vring.used = used;
|
||||
@@ -1496,8 +1502,10 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
|
||||
*/
|
||||
assert(k->has_variable_vring_alignment);
|
||||
|
||||
- vdev->vq[n].vring.align = align;
|
||||
- virtio_queue_update_rings(vdev, n);
|
||||
+ if (align) {
|
||||
+ vdev->vq[n].vring.align = align;
|
||||
+ virtio_queue_update_rings(vdev, n);
|
||||
+ }
|
||||
}
|
||||
|
||||
static bool virtio_queue_notify_aio_vq(VirtQueue *vq)
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,107 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jeff Cody <jcody@redhat.com>
|
||||
Date: Tue, 23 May 2017 13:27:50 -0400
|
||||
Subject: [PATCH] block/gluster: glfs_lseek() workaround
|
||||
|
||||
On current released versions of glusterfs, glfs_lseek() will sometimes
|
||||
return invalid values for SEEK_DATA or SEEK_HOLE. For SEEK_DATA and
|
||||
SEEK_HOLE, the returned value should be >= the passed offset, or < 0 in
|
||||
the case of error:
|
||||
|
||||
LSEEK(2):
|
||||
|
||||
off_t lseek(int fd, off_t offset, int whence);
|
||||
|
||||
[...]
|
||||
|
||||
SEEK_HOLE
|
||||
Adjust the file offset to the next hole in the file greater
|
||||
than or equal to offset. If offset points into the middle of
|
||||
a hole, then the file offset is set to offset. If there is no
|
||||
hole past offset, then the file offset is adjusted to the end
|
||||
of the file (i.e., there is an implicit hole at the end of
|
||||
any file).
|
||||
|
||||
[...]
|
||||
|
||||
RETURN VALUE
|
||||
Upon successful completion, lseek() returns the resulting
|
||||
offset location as measured in bytes from the beginning of the
|
||||
file. On error, the value (off_t) -1 is returned and errno is
|
||||
set to indicate the error
|
||||
|
||||
However, occasionally glfs_lseek() for SEEK_HOLE/DATA will return a
|
||||
value less than the passed offset, yet greater than zero.
|
||||
|
||||
For instance, here are example values observed from this call:
|
||||
|
||||
offs = glfs_lseek(s->fd, start, SEEK_HOLE);
|
||||
if (offs < 0) {
|
||||
return -errno; /* D1 and (H3 or H4) */
|
||||
}
|
||||
|
||||
start == 7608336384
|
||||
offs == 7607877632
|
||||
|
||||
This causes QEMU to abort on the assert test. When this value is
|
||||
returned, errno is also 0.
|
||||
|
||||
This is a reported and known bug to glusterfs:
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1425293
|
||||
|
||||
Although this is being fixed in gluster, we still should work around it
|
||||
in QEMU, given that multiple released versions of gluster behave this
|
||||
way.
|
||||
|
||||
This patch treats the return case of (offs < start) the same as if an
|
||||
error value other than ENXIO is returned; we will assume we learned
|
||||
nothing, and there are no holes in the file.
|
||||
|
||||
Signed-off-by: Jeff Cody <jcody@redhat.com>
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Reviewed-by: Niels de Vos <ndevos@redhat.com>
|
||||
Message-id: 87c0140e9407c08f6e74b04131b610f2e27c014c.1495560397.git.jcody@redhat.com
|
||||
Signed-off-by: Jeff Cody <jcody@redhat.com>
|
||||
---
|
||||
block/gluster.c | 18 ++++++++++++++++--
|
||||
1 file changed, 16 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/block/gluster.c b/block/gluster.c
|
||||
index 4fdf68f1fc..06421ef79d 100644
|
||||
--- a/block/gluster.c
|
||||
+++ b/block/gluster.c
|
||||
@@ -1287,7 +1287,14 @@ static int find_allocation(BlockDriverState *bs, off_t start,
|
||||
if (offs < 0) {
|
||||
return -errno; /* D3 or D4 */
|
||||
}
|
||||
- assert(offs >= start);
|
||||
+
|
||||
+ if (offs < start) {
|
||||
+ /* This is not a valid return by lseek(). We are safe to just return
|
||||
+ * -EIO in this case, and we'll treat it like D4. Unfortunately some
|
||||
+ * versions of gluster server will return offs < start, so an assert
|
||||
+ * here will unnecessarily abort QEMU. */
|
||||
+ return -EIO;
|
||||
+ }
|
||||
|
||||
if (offs > start) {
|
||||
/* D2: in hole, next data at offs */
|
||||
@@ -1319,7 +1326,14 @@ static int find_allocation(BlockDriverState *bs, off_t start,
|
||||
if (offs < 0) {
|
||||
return -errno; /* D1 and (H3 or H4) */
|
||||
}
|
||||
- assert(offs >= start);
|
||||
+
|
||||
+ if (offs < start) {
|
||||
+ /* This is not a valid return by lseek(). We are safe to just return
|
||||
+ * -EIO in this case, and we'll treat it like H4. Unfortunately some
|
||||
+ * versions of gluster server will return offs < start, so an assert
|
||||
+ * here will unnecessarily abort QEMU. */
|
||||
+ return -EIO;
|
||||
+ }
|
||||
|
||||
if (offs > start) {
|
||||
/*
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,180 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Niels de Vos <ndevos@redhat.com>
|
||||
Date: Sun, 28 May 2017 12:01:14 +0530
|
||||
Subject: [PATCH] gluster: add support for PREALLOC_MODE_FALLOC
|
||||
|
||||
Add missing support for "preallocation=falloc" to the Gluster block
|
||||
driver. This change bases its logic on that of block/file-posix.c and
|
||||
removed the gluster_supports_zerofill() and qemu_gluster_zerofill()
|
||||
functions in favour of #ifdef checks in an easy to read
|
||||
switch-statement.
|
||||
|
||||
Both glfs_zerofill() and glfs_fallocate() have been introduced with
|
||||
GlusterFS 3.5.0 (pkg-config glusterfs-api = 6). A #define for the
|
||||
availability of glfs_fallocate() has been added to ./configure.
|
||||
|
||||
Reported-by: Satheesaran Sundaramoorthi <sasundar@redhat.com>
|
||||
Signed-off-by: Niels de Vos <ndevos@redhat.com>
|
||||
Message-id: 20170528063114.28691-1-ndevos@redhat.com
|
||||
URL: https://bugzilla.redhat.com/1450759
|
||||
Signed-off-by: Niels de Vos <ndevos@redhat.com>
|
||||
Signed-off-by: Jeff Cody <jcody@redhat.com>
|
||||
---
|
||||
block/gluster.c | 76 ++++++++++++++++++++++++++++++---------------------------
|
||||
configure | 6 +++++
|
||||
2 files changed, 46 insertions(+), 36 deletions(-)
|
||||
|
||||
diff --git a/block/gluster.c b/block/gluster.c
|
||||
index 06421ef79d..8108c89c7f 100644
|
||||
--- a/block/gluster.c
|
||||
+++ b/block/gluster.c
|
||||
@@ -975,29 +975,6 @@ static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
qemu_coroutine_yield();
|
||||
return acb.ret;
|
||||
}
|
||||
-
|
||||
-static inline bool gluster_supports_zerofill(void)
|
||||
-{
|
||||
- return 1;
|
||||
-}
|
||||
-
|
||||
-static inline int qemu_gluster_zerofill(struct glfs_fd *fd, int64_t offset,
|
||||
- int64_t size)
|
||||
-{
|
||||
- return glfs_zerofill(fd, offset, size);
|
||||
-}
|
||||
-
|
||||
-#else
|
||||
-static inline bool gluster_supports_zerofill(void)
|
||||
-{
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static inline int qemu_gluster_zerofill(struct glfs_fd *fd, int64_t offset,
|
||||
- int64_t size)
|
||||
-{
|
||||
- return 0;
|
||||
-}
|
||||
#endif
|
||||
|
||||
static int qemu_gluster_create(const char *filename,
|
||||
@@ -1007,9 +984,10 @@ static int qemu_gluster_create(const char *filename,
|
||||
struct glfs *glfs;
|
||||
struct glfs_fd *fd;
|
||||
int ret = 0;
|
||||
- int prealloc = 0;
|
||||
+ PreallocMode prealloc;
|
||||
int64_t total_size = 0;
|
||||
char *tmp = NULL;
|
||||
+ Error *local_err = NULL;
|
||||
|
||||
gconf = g_new0(BlockdevOptionsGluster, 1);
|
||||
gconf->debug = qemu_opt_get_number_del(opts, GLUSTER_OPT_DEBUG,
|
||||
@@ -1037,13 +1015,12 @@ static int qemu_gluster_create(const char *filename,
|
||||
BDRV_SECTOR_SIZE);
|
||||
|
||||
tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
|
||||
- if (!tmp || !strcmp(tmp, "off")) {
|
||||
- prealloc = 0;
|
||||
- } else if (!strcmp(tmp, "full") && gluster_supports_zerofill()) {
|
||||
- prealloc = 1;
|
||||
- } else {
|
||||
- error_setg(errp, "Invalid preallocation mode: '%s'"
|
||||
- " or GlusterFS doesn't support zerofill API", tmp);
|
||||
+ prealloc = qapi_enum_parse(PreallocMode_lookup, tmp,
|
||||
+ PREALLOC_MODE__MAX, PREALLOC_MODE_OFF,
|
||||
+ &local_err);
|
||||
+ g_free(tmp);
|
||||
+ if (local_err) {
|
||||
+ error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1052,21 +1029,48 @@ static int qemu_gluster_create(const char *filename,
|
||||
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
|
||||
if (!fd) {
|
||||
ret = -errno;
|
||||
- } else {
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ switch (prealloc) {
|
||||
+#ifdef CONFIG_GLUSTERFS_FALLOCATE
|
||||
+ case PREALLOC_MODE_FALLOC:
|
||||
+ if (glfs_fallocate(fd, 0, 0, total_size)) {
|
||||
+ error_setg(errp, "Could not preallocate data for the new file");
|
||||
+ ret = -errno;
|
||||
+ }
|
||||
+ break;
|
||||
+#endif /* CONFIG_GLUSTERFS_FALLOCATE */
|
||||
+#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||
+ case PREALLOC_MODE_FULL:
|
||||
if (!glfs_ftruncate(fd, total_size)) {
|
||||
- if (prealloc && qemu_gluster_zerofill(fd, 0, total_size)) {
|
||||
+ if (glfs_zerofill(fd, 0, total_size)) {
|
||||
+ error_setg(errp, "Could not zerofill the new file");
|
||||
ret = -errno;
|
||||
}
|
||||
} else {
|
||||
+ error_setg(errp, "Could not resize file");
|
||||
ret = -errno;
|
||||
}
|
||||
-
|
||||
- if (glfs_close(fd) != 0) {
|
||||
+ break;
|
||||
+#endif /* CONFIG_GLUSTERFS_ZEROFILL */
|
||||
+ case PREALLOC_MODE_OFF:
|
||||
+ if (glfs_ftruncate(fd, total_size) != 0) {
|
||||
ret = -errno;
|
||||
+ error_setg(errp, "Could not resize file");
|
||||
}
|
||||
+ break;
|
||||
+ default:
|
||||
+ ret = -EINVAL;
|
||||
+ error_setg(errp, "Unsupported preallocation mode: %s",
|
||||
+ PreallocMode_lookup[prealloc]);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (glfs_close(fd) != 0) {
|
||||
+ ret = -errno;
|
||||
}
|
||||
out:
|
||||
- g_free(tmp);
|
||||
qapi_free_BlockdevOptionsGluster(gconf);
|
||||
glfs_clear_preopened(glfs);
|
||||
return ret;
|
||||
diff --git a/configure b/configure
|
||||
index 841f7a8fae..3667da6f07 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -300,6 +300,7 @@ seccomp=""
|
||||
glusterfs=""
|
||||
glusterfs_xlator_opt="no"
|
||||
glusterfs_discard="no"
|
||||
+glusterfs_fallocate="no"
|
||||
glusterfs_zerofill="no"
|
||||
gtk=""
|
||||
gtkabi=""
|
||||
@@ -3537,6 +3538,7 @@ if test "$glusterfs" != "no" ; then
|
||||
glusterfs_discard="yes"
|
||||
fi
|
||||
if $pkg_config --atleast-version=6 glusterfs-api; then
|
||||
+ glusterfs_fallocate="yes"
|
||||
glusterfs_zerofill="yes"
|
||||
fi
|
||||
else
|
||||
@@ -5717,6 +5719,10 @@ if test "$glusterfs_discard" = "yes" ; then
|
||||
echo "CONFIG_GLUSTERFS_DISCARD=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
+if test "$glusterfs_fallocate" = "yes" ; then
|
||||
+ echo "CONFIG_GLUSTERFS_FALLOCATE=y" >> $config_host_mak
|
||||
+fi
|
||||
+
|
||||
if test "$glusterfs_zerofill" = "yes" ; then
|
||||
echo "CONFIG_GLUSTERFS_ZEROFILL=y" >> $config_host_mak
|
||||
fi
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,39 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eduardo Habkost <ehabkost@redhat.com>
|
||||
Date: Wed, 12 Jul 2017 13:20:56 -0300
|
||||
Subject: [PATCH] target/i386: Use host_vendor_fms() in max_x86_cpu_initfn()
|
||||
|
||||
The existing code duplicated the logic in host_vendor_fms(), so
|
||||
reuse the helper function instead.
|
||||
|
||||
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
Message-Id: <20170712162058.10538-3-ehabkost@redhat.com>
|
||||
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
---
|
||||
target/i386/cpu.c | 9 ++-------
|
||||
1 file changed, 2 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
|
||||
index 4b3bfb3802..1affd3bb5b 100644
|
||||
--- a/target/i386/cpu.c
|
||||
+++ b/target/i386/cpu.c
|
||||
@@ -1592,13 +1592,8 @@ static void max_x86_cpu_initfn(Object *obj)
|
||||
X86CPUDefinition host_cpudef = { };
|
||||
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
|
||||
|
||||
- host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
|
||||
- x86_cpu_vendor_words2str(host_cpudef.vendor, ebx, edx, ecx);
|
||||
-
|
||||
- host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
|
||||
- host_cpudef.family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
|
||||
- host_cpudef.model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
|
||||
- host_cpudef.stepping = eax & 0x0F;
|
||||
+ host_vendor_fms(host_cpudef.vendor, &host_cpudef.family,
|
||||
+ &host_cpudef.model, &host_cpudef.stepping);
|
||||
|
||||
cpu_x86_fill_model_id(host_cpudef.model_id);
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,40 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eduardo Habkost <ehabkost@redhat.com>
|
||||
Date: Wed, 12 Jul 2017 13:20:57 -0300
|
||||
Subject: [PATCH] target/i386: Define CPUID_MODEL_ID_SZ macro
|
||||
|
||||
Document cpu_x86_fill_model_id() and define CPUID_MODEL_ID_SZ to
|
||||
help callers use the right buffer size.
|
||||
|
||||
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
Message-Id: <20170712162058.10538-4-ehabkost@redhat.com>
|
||||
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
---
|
||||
target/i386/cpu.c | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
|
||||
index 1affd3bb5b..54832dd591 100644
|
||||
--- a/target/i386/cpu.c
|
||||
+++ b/target/i386/cpu.c
|
||||
@@ -1541,6 +1541,17 @@ static bool lmce_supported(void)
|
||||
return !!(mce_cap & MCG_LMCE_P);
|
||||
}
|
||||
|
||||
+#define CPUID_MODEL_ID_SZ 48
|
||||
+
|
||||
+/**
|
||||
+ * cpu_x86_fill_model_id:
|
||||
+ * Get CPUID model ID string from host CPU.
|
||||
+ *
|
||||
+ * @str should have at least CPUID_MODEL_ID_SZ bytes
|
||||
+ *
|
||||
+ * The function does NOT add a null terminator to the string
|
||||
+ * automatically.
|
||||
+ */
|
||||
static int cpu_x86_fill_model_id(char *str)
|
||||
{
|
||||
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,92 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eduardo Habkost <ehabkost@redhat.com>
|
||||
Date: Wed, 12 Jul 2017 13:20:58 -0300
|
||||
Subject: [PATCH] target/i386: Don't use x86_cpu_load_def() on "max" CPU model
|
||||
|
||||
When commit 0bacd8b3046f ('i386: Don't set CPUClass::cpu_def on
|
||||
"max" model') removed the CPUClass::cpu_def field, we kept using
|
||||
the x86_cpu_load_def() helper directly in max_x86_cpu_initfn(),
|
||||
emulating the previous behavior when CPUClass::cpu_def was set.
|
||||
|
||||
However, x86_cpu_load_def() is intended to help initialization of
|
||||
CPU models from the builtin_x86_defs table, and does lots of
|
||||
other steps that are not necessary for "max".
|
||||
|
||||
One of the things x86_cpu_load_def() do is to set the properties
|
||||
listed at tcg_default_props/kvm_default_props. We must not do
|
||||
that on the "max" CPU model, otherwise under KVM we will
|
||||
incorrectly report all KVM features as always available, and the
|
||||
"svm" feature as always unavailable. The latter caused the bug
|
||||
reported at:
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1467599
|
||||
("Unable to start domain: the CPU is incompatible with host CPU:
|
||||
Host CPU does not provide required features: svm")
|
||||
|
||||
Replace x86_cpu_load_def() with simple object_property_set*()
|
||||
calls. In addition to fixing the above bug, this makes the KVM
|
||||
branch in max_x86_cpu_initfn() very similar to the existing TCG
|
||||
branch.
|
||||
|
||||
For reference, the full list of steps performed by
|
||||
x86_cpu_load_def() is:
|
||||
|
||||
* Setting min-level and min-xlevel. Already done by
|
||||
max_x86_cpu_initfn().
|
||||
* Setting family/model/stepping/model-id. Done by the code added
|
||||
to max_x86_cpu_initfn() in this patch.
|
||||
* Copying def->features. Wrong because "-cpu max" features need to
|
||||
be calculated at realize time. This was not a problem in the
|
||||
current code because host_cpudef.features was all zeroes.
|
||||
* x86_cpu_apply_props() calls. This causes the bug above, and
|
||||
shouldn't be done.
|
||||
* Setting CPUID_EXT_HYPERVISOR. Not needed because it is already
|
||||
reported by x86_cpu_get_supported_feature_word(), and because
|
||||
"-cpu max" features need to be calculated at realize time.
|
||||
* Setting CPU vendor to host CPU vendor if on KVM mode.
|
||||
Redundant, because max_x86_cpu_initfn() already sets it to the
|
||||
host CPU vendor.
|
||||
|
||||
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
Message-Id: <20170712162058.10538-5-ehabkost@redhat.com>
|
||||
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
---
|
||||
target/i386/cpu.c | 18 ++++++++++++------
|
||||
1 file changed, 12 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
|
||||
index 54832dd591..3d53cb4c86 100644
|
||||
--- a/target/i386/cpu.c
|
||||
+++ b/target/i386/cpu.c
|
||||
@@ -1600,15 +1600,21 @@ static void max_x86_cpu_initfn(Object *obj)
|
||||
cpu->max_features = true;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
- X86CPUDefinition host_cpudef = { };
|
||||
- uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
|
||||
+ char vendor[CPUID_VENDOR_SZ + 1] = { 0 };
|
||||
+ char model_id[CPUID_MODEL_ID_SZ + 1] = { 0 };
|
||||
+ int family, model, stepping;
|
||||
|
||||
- host_vendor_fms(host_cpudef.vendor, &host_cpudef.family,
|
||||
- &host_cpudef.model, &host_cpudef.stepping);
|
||||
+ host_vendor_fms(vendor, &family, &model, &stepping);
|
||||
|
||||
- cpu_x86_fill_model_id(host_cpudef.model_id);
|
||||
+ cpu_x86_fill_model_id(model_id);
|
||||
|
||||
- x86_cpu_load_def(cpu, &host_cpudef, &error_abort);
|
||||
+ object_property_set_str(OBJECT(cpu), vendor, "vendor", &error_abort);
|
||||
+ object_property_set_int(OBJECT(cpu), family, "family", &error_abort);
|
||||
+ object_property_set_int(OBJECT(cpu), model, "model", &error_abort);
|
||||
+ object_property_set_int(OBJECT(cpu), stepping, "stepping",
|
||||
+ &error_abort);
|
||||
+ object_property_set_str(OBJECT(cpu), model_id, "model-id",
|
||||
+ &error_abort);
|
||||
|
||||
env->cpuid_min_level =
|
||||
kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,85 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eduardo Habkost <ehabkost@redhat.com>
|
||||
Date: Tue, 9 Jan 2018 13:45:13 -0200
|
||||
Subject: [PATCH] i386: Change X86CPUDefinition::model_id to const char*
|
||||
|
||||
It is valid to have a 48-character model ID on CPUID, however the
|
||||
definition of X86CPUDefinition::model_id is char[48], which can
|
||||
make the compiler drop the null terminator from the string.
|
||||
|
||||
If a CPU model happens to have 48 bytes on model_id, "-cpu help"
|
||||
will print garbage and the object_property_set_str() call at
|
||||
x86_cpu_load_def() will read data outside the model_id array.
|
||||
|
||||
We could increase the array size to 49, but this would mean the
|
||||
compiler would not issue a warning if a 49-char string is used by
|
||||
mistake for model_id.
|
||||
|
||||
To make things simpler, simply change model_id to be const char*,
|
||||
and validate the string length using an assert() on
|
||||
x86_cpu_cpudef_class_init.
|
||||
|
||||
Reported-by: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
|
||||
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
---
|
||||
target/i386/cpu.c | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
|
||||
index 3d53cb4c86..c673521016 100644
|
||||
--- a/target/i386/cpu.c
|
||||
+++ b/target/i386/cpu.c
|
||||
@@ -753,7 +753,7 @@ struct X86CPUDefinition {
|
||||
int model;
|
||||
int stepping;
|
||||
FeatureWordArray features;
|
||||
- char model_id[48];
|
||||
+ const char *model_id;
|
||||
};
|
||||
|
||||
static X86CPUDefinition builtin_x86_defs[] = {
|
||||
@@ -922,6 +922,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
.features[FEAT_1_EDX] =
|
||||
I486_FEATURES,
|
||||
.xlevel = 0,
|
||||
+ .model_id = "",
|
||||
},
|
||||
{
|
||||
.name = "pentium",
|
||||
@@ -933,6 +934,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
.features[FEAT_1_EDX] =
|
||||
PENTIUM_FEATURES,
|
||||
.xlevel = 0,
|
||||
+ .model_id = "",
|
||||
},
|
||||
{
|
||||
.name = "pentium2",
|
||||
@@ -944,6 +946,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
.features[FEAT_1_EDX] =
|
||||
PENTIUM2_FEATURES,
|
||||
.xlevel = 0,
|
||||
+ .model_id = "",
|
||||
},
|
||||
{
|
||||
.name = "pentium3",
|
||||
@@ -955,6 +958,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
.features[FEAT_1_EDX] =
|
||||
PENTIUM3_FEATURES,
|
||||
.xlevel = 0,
|
||||
+ .model_id = "",
|
||||
},
|
||||
{
|
||||
.name = "athlon",
|
||||
@@ -2617,6 +2621,9 @@ static void x86_register_cpudef_type(X86CPUDefinition *def)
|
||||
* they shouldn't be set on the CPU model table.
|
||||
*/
|
||||
assert(!(def->features[FEAT_8000_0001_EDX] & CPUID_EXT2_AMD_ALIASES));
|
||||
+ /* catch mistakes instead of silently truncating model_id when too long */
|
||||
+ assert(def->model_id && strlen(def->model_id) <= 48);
|
||||
+
|
||||
|
||||
type_register(&ti);
|
||||
g_free(typename);
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,135 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Tue, 9 Jan 2018 13:45:14 -0200
|
||||
Subject: [PATCH] i386: Add support for SPEC_CTRL MSR
|
||||
|
||||
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
---
|
||||
target/i386/cpu.h | 3 +++
|
||||
target/i386/kvm.c | 15 +++++++++++++++
|
||||
target/i386/machine.c | 20 ++++++++++++++++++++
|
||||
3 files changed, 38 insertions(+)
|
||||
|
||||
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
|
||||
index c4602ca80d..cc322d6b39 100644
|
||||
--- a/target/i386/cpu.h
|
||||
+++ b/target/i386/cpu.h
|
||||
@@ -333,6 +333,7 @@
|
||||
#define MSR_IA32_APICBASE_BASE (0xfffffU<<12)
|
||||
#define MSR_IA32_FEATURE_CONTROL 0x0000003a
|
||||
#define MSR_TSC_ADJUST 0x0000003b
|
||||
+#define MSR_IA32_SPEC_CTRL 0x48
|
||||
#define MSR_IA32_TSCDEADLINE 0x6e0
|
||||
|
||||
#define FEATURE_CONTROL_LOCKED (1<<0)
|
||||
@@ -1080,6 +1081,8 @@ typedef struct CPUX86State {
|
||||
|
||||
uint32_t pkru;
|
||||
|
||||
+ uint64_t spec_ctrl;
|
||||
+
|
||||
/* End of state preserved by INIT (dummy marker). */
|
||||
struct {} end_init_save;
|
||||
|
||||
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
|
||||
index 55865dbee0..9f83c79338 100644
|
||||
--- a/target/i386/kvm.c
|
||||
+++ b/target/i386/kvm.c
|
||||
@@ -89,6 +89,7 @@ static bool has_msr_hv_runtime;
|
||||
static bool has_msr_hv_synic;
|
||||
static bool has_msr_hv_stimer;
|
||||
static bool has_msr_xss;
|
||||
+static bool has_msr_spec_ctrl;
|
||||
|
||||
static bool has_msr_architectural_pmu;
|
||||
static uint32_t num_architectural_pmu_counters;
|
||||
@@ -1140,6 +1141,10 @@ static int kvm_get_supported_msrs(KVMState *s)
|
||||
has_msr_hv_stimer = true;
|
||||
continue;
|
||||
}
|
||||
+ if (kvm_msr_list->indices[i] == MSR_IA32_SPEC_CTRL) {
|
||||
+ has_msr_spec_ctrl = true;
|
||||
+ continue;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1667,6 +1672,9 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
|
||||
if (has_msr_xss) {
|
||||
kvm_msr_entry_add(cpu, MSR_IA32_XSS, env->xss);
|
||||
}
|
||||
+ if (has_msr_spec_ctrl) {
|
||||
+ kvm_msr_entry_add(cpu, MSR_IA32_SPEC_CTRL, env->spec_ctrl);
|
||||
+ }
|
||||
#ifdef TARGET_X86_64
|
||||
if (lm_capable_kernel) {
|
||||
kvm_msr_entry_add(cpu, MSR_CSTAR, env->cstar);
|
||||
@@ -1675,6 +1683,7 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
|
||||
kvm_msr_entry_add(cpu, MSR_LSTAR, env->lstar);
|
||||
}
|
||||
#endif
|
||||
+
|
||||
/*
|
||||
* The following MSRs have side effects on the guest or are too heavy
|
||||
* for normal writeback. Limit them to reset or full state updates.
|
||||
@@ -2081,6 +2090,9 @@ static int kvm_get_msrs(X86CPU *cpu)
|
||||
if (has_msr_xss) {
|
||||
kvm_msr_entry_add(cpu, MSR_IA32_XSS, 0);
|
||||
}
|
||||
+ if (has_msr_spec_ctrl) {
|
||||
+ kvm_msr_entry_add(cpu, MSR_IA32_SPEC_CTRL, 0);
|
||||
+ }
|
||||
|
||||
|
||||
if (!env->tsc_valid) {
|
||||
@@ -2430,6 +2442,9 @@ static int kvm_get_msrs(X86CPU *cpu)
|
||||
env->mtrr_var[MSR_MTRRphysIndex(index)].base = msrs[i].data;
|
||||
}
|
||||
break;
|
||||
+ case MSR_IA32_SPEC_CTRL:
|
||||
+ env->spec_ctrl = msrs[i].data;
|
||||
+ break;
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/target/i386/machine.c b/target/i386/machine.c
|
||||
index 78ae2f986b..8c0d5437fa 100644
|
||||
--- a/target/i386/machine.c
|
||||
+++ b/target/i386/machine.c
|
||||
@@ -927,6 +927,25 @@ static const VMStateDescription vmstate_mcg_ext_ctl = {
|
||||
}
|
||||
};
|
||||
|
||||
+static bool spec_ctrl_needed(void *opaque)
|
||||
+{
|
||||
+ X86CPU *cpu = opaque;
|
||||
+ CPUX86State *env = &cpu->env;
|
||||
+
|
||||
+ return env->spec_ctrl != 0;
|
||||
+}
|
||||
+
|
||||
+static const VMStateDescription vmstate_spec_ctrl = {
|
||||
+ .name = "cpu/spec_ctrl",
|
||||
+ .version_id = 1,
|
||||
+ .minimum_version_id = 1,
|
||||
+ .needed = spec_ctrl_needed,
|
||||
+ .fields = (VMStateField[]){
|
||||
+ VMSTATE_UINT64(env.spec_ctrl, X86CPU),
|
||||
+ VMSTATE_END_OF_LIST()
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
VMStateDescription vmstate_x86_cpu = {
|
||||
.name = "cpu",
|
||||
.version_id = 12,
|
||||
@@ -1053,6 +1072,7 @@ VMStateDescription vmstate_x86_cpu = {
|
||||
#ifdef TARGET_X86_64
|
||||
&vmstate_pkru,
|
||||
#endif
|
||||
+ &vmstate_spec_ctrl,
|
||||
&vmstate_mcg_ext_ctl,
|
||||
NULL
|
||||
}
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,41 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eduardo Habkost <ehabkost@redhat.com>
|
||||
Date: Tue, 9 Jan 2018 13:45:15 -0200
|
||||
Subject: [PATCH] i386: Add spec-ctrl CPUID bit
|
||||
|
||||
Add the feature name and a CPUID_7_0_EDX_SPEC_CTRL macro.
|
||||
|
||||
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
---
|
||||
target/i386/cpu.c | 2 +-
|
||||
target/i386/cpu.h | 1 +
|
||||
2 files changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
|
||||
index c673521016..faf1ff6dcc 100644
|
||||
--- a/target/i386/cpu.c
|
||||
+++ b/target/i386/cpu.c
|
||||
@@ -460,7 +460,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
- NULL, NULL, NULL, NULL,
|
||||
+ NULL, NULL, "spec-ctrl", NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
},
|
||||
.cpuid_eax = 7,
|
||||
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
|
||||
index cc322d6b39..71261f4819 100644
|
||||
--- a/target/i386/cpu.h
|
||||
+++ b/target/i386/cpu.h
|
||||
@@ -640,6 +640,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
|
||||
|
||||
#define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2) /* AVX512 Neural Network Instructions */
|
||||
#define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Multiply Accumulation Single Precision */
|
||||
+#define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Speculation Control */
|
||||
|
||||
#define CPUID_XSAVE_XSAVEOPT (1U << 0)
|
||||
#define CPUID_XSAVE_XSAVEC (1U << 1)
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,83 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eduardo Habkost <ehabkost@redhat.com>
|
||||
Date: Tue, 9 Jan 2018 13:45:16 -0200
|
||||
Subject: [PATCH] i386: Add FEAT_8000_0008_EBX CPUID feature word
|
||||
|
||||
Add the new feature word and the "ibpb" feature flag.
|
||||
|
||||
Based on a patch by Paolo Bonzini.
|
||||
|
||||
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
---
|
||||
target/i386/cpu.c | 19 ++++++++++++++++++-
|
||||
target/i386/cpu.h | 3 +++
|
||||
2 files changed, 21 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
|
||||
index faf1ff6dcc..eee365b78d 100644
|
||||
--- a/target/i386/cpu.c
|
||||
+++ b/target/i386/cpu.c
|
||||
@@ -484,6 +484,22 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
||||
.tcg_features = TCG_APM_FEATURES,
|
||||
.unmigratable_flags = CPUID_APM_INVTSC,
|
||||
},
|
||||
+ [FEAT_8000_0008_EBX] = {
|
||||
+ .feat_names = {
|
||||
+ NULL, NULL, NULL, NULL,
|
||||
+ NULL, NULL, NULL, NULL,
|
||||
+ NULL, NULL, NULL, NULL,
|
||||
+ "ibpb", NULL, NULL, NULL,
|
||||
+ NULL, NULL, NULL, NULL,
|
||||
+ NULL, NULL, NULL, NULL,
|
||||
+ NULL, NULL, NULL, NULL,
|
||||
+ NULL, NULL, NULL, NULL,
|
||||
+ },
|
||||
+ .cpuid_eax = 0x80000008,
|
||||
+ .cpuid_reg = R_EBX,
|
||||
+ .tcg_features = 0,
|
||||
+ .unmigratable_flags = 0,
|
||||
+ },
|
||||
[FEAT_XSAVE] = {
|
||||
.feat_names = {
|
||||
"xsaveopt", "xsavec", "xgetbv1", "xsaves",
|
||||
@@ -2984,7 +3000,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||
} else {
|
||||
*eax = cpu->phys_bits;
|
||||
}
|
||||
- *ebx = 0;
|
||||
+ *ebx = env->features[FEAT_8000_0008_EBX];
|
||||
*ecx = 0;
|
||||
*edx = 0;
|
||||
if (cs->nr_cores * cs->nr_threads > 1) {
|
||||
@@ -3440,6 +3456,7 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
|
||||
x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX);
|
||||
x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_ECX);
|
||||
x86_cpu_adjust_feat_level(cpu, FEAT_8000_0007_EDX);
|
||||
+ x86_cpu_adjust_feat_level(cpu, FEAT_8000_0008_EBX);
|
||||
x86_cpu_adjust_feat_level(cpu, FEAT_C000_0001_EDX);
|
||||
x86_cpu_adjust_feat_level(cpu, FEAT_SVM);
|
||||
x86_cpu_adjust_feat_level(cpu, FEAT_XSAVE);
|
||||
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
|
||||
index 71261f4819..1ebee91930 100644
|
||||
--- a/target/i386/cpu.h
|
||||
+++ b/target/i386/cpu.h
|
||||
@@ -452,6 +452,7 @@ typedef enum FeatureWord {
|
||||
FEAT_8000_0001_EDX, /* CPUID[8000_0001].EDX */
|
||||
FEAT_8000_0001_ECX, /* CPUID[8000_0001].ECX */
|
||||
FEAT_8000_0007_EDX, /* CPUID[8000_0007].EDX */
|
||||
+ FEAT_8000_0008_EBX, /* CPUID[8000_0008].EBX */
|
||||
FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */
|
||||
FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */
|
||||
FEAT_HYPERV_EAX, /* CPUID[4000_0003].EAX */
|
||||
@@ -642,6 +643,8 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
|
||||
#define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Multiply Accumulation Single Precision */
|
||||
#define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Speculation Control */
|
||||
|
||||
+#define CPUID_8000_0008_EBX_IBPB (1U << 12) /* Indirect Branch Prediction Barrier */
|
||||
+
|
||||
#define CPUID_XSAVE_XSAVEOPT (1U << 0)
|
||||
#define CPUID_XSAVE_XSAVEC (1U << 1)
|
||||
#define CPUID_XSAVE_XGETBV1 (1U << 2)
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,518 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eduardo Habkost <ehabkost@redhat.com>
|
||||
Date: Tue, 9 Jan 2018 13:45:17 -0200
|
||||
Subject: [PATCH] i386: Add new -IBRS versions of Intel CPU models
|
||||
|
||||
The new MSR IA32_SPEC_CTRL MSR was introduced by a recent Intel
|
||||
microcode updated and can be used by OSes to mitigate
|
||||
CVE-2017-5715. Unfortunately we can't change the existing CPU
|
||||
models without breaking existing setups, so users need to
|
||||
explicitly update their VM configuration to use the new *-IBRS
|
||||
CPU model if they want to expose IBRS to guests.
|
||||
|
||||
The new CPU models are simple copies of the existing CPU models,
|
||||
with just CPUID_7_0_EDX_SPEC_CTRL added and model_id updated.
|
||||
|
||||
Cc: Jiri Denemark <jdenemar@redhat.com>
|
||||
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
---
|
||||
target/i386/cpu.c | 427 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 426 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
|
||||
index eee365b78d..e4a2d5a012 100644
|
||||
--- a/target/i386/cpu.c
|
||||
+++ b/target/i386/cpu.c
|
||||
@@ -1085,6 +1085,31 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
.model_id = "Intel Core i7 9xx (Nehalem Class Core i7)",
|
||||
},
|
||||
{
|
||||
+ .name = "Nehalem-IBRS",
|
||||
+ .level = 11,
|
||||
+ .vendor = CPUID_VENDOR_INTEL,
|
||||
+ .family = 6,
|
||||
+ .model = 26,
|
||||
+ .stepping = 3,
|
||||
+ .features[FEAT_1_EDX] =
|
||||
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
||||
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
|
||||
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
|
||||
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
|
||||
+ CPUID_DE | CPUID_FP87,
|
||||
+ .features[FEAT_1_ECX] =
|
||||
+ CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
|
||||
+ CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_SSE3,
|
||||
+ .features[FEAT_7_0_EDX] =
|
||||
+ CPUID_7_0_EDX_SPEC_CTRL,
|
||||
+ .features[FEAT_8000_0001_EDX] =
|
||||
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
|
||||
+ .features[FEAT_8000_0001_ECX] =
|
||||
+ CPUID_EXT3_LAHF_LM,
|
||||
+ .xlevel = 0x80000008,
|
||||
+ .model_id = "Intel Core i7 9xx (Nehalem Core i7, IBRS update)",
|
||||
+ },
|
||||
+ {
|
||||
.name = "Westmere",
|
||||
.level = 11,
|
||||
.vendor = CPUID_VENDOR_INTEL,
|
||||
@@ -1111,6 +1136,34 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
.model_id = "Westmere E56xx/L56xx/X56xx (Nehalem-C)",
|
||||
},
|
||||
{
|
||||
+ .name = "Westmere-IBRS",
|
||||
+ .level = 11,
|
||||
+ .vendor = CPUID_VENDOR_INTEL,
|
||||
+ .family = 6,
|
||||
+ .model = 44,
|
||||
+ .stepping = 1,
|
||||
+ .features[FEAT_1_EDX] =
|
||||
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
||||
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
|
||||
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
|
||||
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
|
||||
+ CPUID_DE | CPUID_FP87,
|
||||
+ .features[FEAT_1_ECX] =
|
||||
+ CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
|
||||
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
||||
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
|
||||
+ .features[FEAT_8000_0001_EDX] =
|
||||
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
|
||||
+ .features[FEAT_8000_0001_ECX] =
|
||||
+ CPUID_EXT3_LAHF_LM,
|
||||
+ .features[FEAT_7_0_EDX] =
|
||||
+ CPUID_7_0_EDX_SPEC_CTRL,
|
||||
+ .features[FEAT_6_EAX] =
|
||||
+ CPUID_6_EAX_ARAT,
|
||||
+ .xlevel = 0x80000008,
|
||||
+ .model_id = "Westmere E56xx/L56xx/X56xx (IBRS update)",
|
||||
+ },
|
||||
+ {
|
||||
.name = "SandyBridge",
|
||||
.level = 0xd,
|
||||
.vendor = CPUID_VENDOR_INTEL,
|
||||
@@ -1142,6 +1195,39 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
.model_id = "Intel Xeon E312xx (Sandy Bridge)",
|
||||
},
|
||||
{
|
||||
+ .name = "SandyBridge-IBRS",
|
||||
+ .level = 0xd,
|
||||
+ .vendor = CPUID_VENDOR_INTEL,
|
||||
+ .family = 6,
|
||||
+ .model = 42,
|
||||
+ .stepping = 1,
|
||||
+ .features[FEAT_1_EDX] =
|
||||
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
||||
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
|
||||
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
|
||||
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
|
||||
+ CPUID_DE | CPUID_FP87,
|
||||
+ .features[FEAT_1_ECX] =
|
||||
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
||||
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_POPCNT |
|
||||
+ CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
|
||||
+ CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
|
||||
+ CPUID_EXT_SSE3,
|
||||
+ .features[FEAT_8000_0001_EDX] =
|
||||
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
||||
+ CPUID_EXT2_SYSCALL,
|
||||
+ .features[FEAT_8000_0001_ECX] =
|
||||
+ CPUID_EXT3_LAHF_LM,
|
||||
+ .features[FEAT_7_0_EDX] =
|
||||
+ CPUID_7_0_EDX_SPEC_CTRL,
|
||||
+ .features[FEAT_XSAVE] =
|
||||
+ CPUID_XSAVE_XSAVEOPT,
|
||||
+ .features[FEAT_6_EAX] =
|
||||
+ CPUID_6_EAX_ARAT,
|
||||
+ .xlevel = 0x80000008,
|
||||
+ .model_id = "Intel Xeon E312xx (Sandy Bridge, IBRS update)",
|
||||
+ },
|
||||
+ {
|
||||
.name = "IvyBridge",
|
||||
.level = 0xd,
|
||||
.vendor = CPUID_VENDOR_INTEL,
|
||||
@@ -1176,6 +1262,42 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
.model_id = "Intel Xeon E3-12xx v2 (Ivy Bridge)",
|
||||
},
|
||||
{
|
||||
+ .name = "IvyBridge-IBRS",
|
||||
+ .level = 0xd,
|
||||
+ .vendor = CPUID_VENDOR_INTEL,
|
||||
+ .family = 6,
|
||||
+ .model = 58,
|
||||
+ .stepping = 9,
|
||||
+ .features[FEAT_1_EDX] =
|
||||
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
||||
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
|
||||
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
|
||||
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
|
||||
+ CPUID_DE | CPUID_FP87,
|
||||
+ .features[FEAT_1_ECX] =
|
||||
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
||||
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_POPCNT |
|
||||
+ CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
|
||||
+ CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
|
||||
+ CPUID_EXT_SSE3 | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
||||
+ .features[FEAT_7_0_EBX] =
|
||||
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_SMEP |
|
||||
+ CPUID_7_0_EBX_ERMS,
|
||||
+ .features[FEAT_8000_0001_EDX] =
|
||||
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
||||
+ CPUID_EXT2_SYSCALL,
|
||||
+ .features[FEAT_8000_0001_ECX] =
|
||||
+ CPUID_EXT3_LAHF_LM,
|
||||
+ .features[FEAT_7_0_EDX] =
|
||||
+ CPUID_7_0_EDX_SPEC_CTRL,
|
||||
+ .features[FEAT_XSAVE] =
|
||||
+ CPUID_XSAVE_XSAVEOPT,
|
||||
+ .features[FEAT_6_EAX] =
|
||||
+ CPUID_6_EAX_ARAT,
|
||||
+ .xlevel = 0x80000008,
|
||||
+ .model_id = "Intel Xeon E3-12xx v2 (Ivy Bridge, IBRS)",
|
||||
+ },
|
||||
+ {
|
||||
.name = "Haswell-noTSX",
|
||||
.level = 0xd,
|
||||
.vendor = CPUID_VENDOR_INTEL,
|
||||
@@ -1210,7 +1332,46 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
CPUID_6_EAX_ARAT,
|
||||
.xlevel = 0x80000008,
|
||||
.model_id = "Intel Core Processor (Haswell, no TSX)",
|
||||
- }, {
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "Haswell-noTSX-IBRS",
|
||||
+ .level = 0xd,
|
||||
+ .vendor = CPUID_VENDOR_INTEL,
|
||||
+ .family = 6,
|
||||
+ .model = 60,
|
||||
+ .stepping = 1,
|
||||
+ .features[FEAT_1_EDX] =
|
||||
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
||||
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
|
||||
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
|
||||
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
|
||||
+ CPUID_DE | CPUID_FP87,
|
||||
+ .features[FEAT_1_ECX] =
|
||||
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
||||
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
|
||||
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
||||
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
|
||||
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
|
||||
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
||||
+ .features[FEAT_8000_0001_EDX] =
|
||||
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
||||
+ CPUID_EXT2_SYSCALL,
|
||||
+ .features[FEAT_8000_0001_ECX] =
|
||||
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM,
|
||||
+ .features[FEAT_7_0_EDX] =
|
||||
+ CPUID_7_0_EDX_SPEC_CTRL,
|
||||
+ .features[FEAT_7_0_EBX] =
|
||||
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
|
||||
+ CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
|
||||
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID,
|
||||
+ .features[FEAT_XSAVE] =
|
||||
+ CPUID_XSAVE_XSAVEOPT,
|
||||
+ .features[FEAT_6_EAX] =
|
||||
+ CPUID_6_EAX_ARAT,
|
||||
+ .xlevel = 0x80000008,
|
||||
+ .model_id = "Intel Core Processor (Haswell, no TSX, IBRS)",
|
||||
+ },
|
||||
+ {
|
||||
.name = "Haswell",
|
||||
.level = 0xd,
|
||||
.vendor = CPUID_VENDOR_INTEL,
|
||||
@@ -1248,6 +1409,45 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
.model_id = "Intel Core Processor (Haswell)",
|
||||
},
|
||||
{
|
||||
+ .name = "Haswell-IBRS",
|
||||
+ .level = 0xd,
|
||||
+ .vendor = CPUID_VENDOR_INTEL,
|
||||
+ .family = 6,
|
||||
+ .model = 60,
|
||||
+ .stepping = 4,
|
||||
+ .features[FEAT_1_EDX] =
|
||||
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
||||
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
|
||||
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
|
||||
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
|
||||
+ CPUID_DE | CPUID_FP87,
|
||||
+ .features[FEAT_1_ECX] =
|
||||
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
||||
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
|
||||
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
||||
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
|
||||
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
|
||||
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
||||
+ .features[FEAT_8000_0001_EDX] =
|
||||
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
||||
+ CPUID_EXT2_SYSCALL,
|
||||
+ .features[FEAT_8000_0001_ECX] =
|
||||
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM,
|
||||
+ .features[FEAT_7_0_EDX] =
|
||||
+ CPUID_7_0_EDX_SPEC_CTRL,
|
||||
+ .features[FEAT_7_0_EBX] =
|
||||
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
|
||||
+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
|
||||
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
|
||||
+ CPUID_7_0_EBX_RTM,
|
||||
+ .features[FEAT_XSAVE] =
|
||||
+ CPUID_XSAVE_XSAVEOPT,
|
||||
+ .features[FEAT_6_EAX] =
|
||||
+ CPUID_6_EAX_ARAT,
|
||||
+ .xlevel = 0x80000008,
|
||||
+ .model_id = "Intel Core Processor (Haswell, IBRS)",
|
||||
+ },
|
||||
+ {
|
||||
.name = "Broadwell-noTSX",
|
||||
.level = 0xd,
|
||||
.vendor = CPUID_VENDOR_INTEL,
|
||||
@@ -1286,6 +1486,46 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
.model_id = "Intel Core Processor (Broadwell, no TSX)",
|
||||
},
|
||||
{
|
||||
+ .name = "Broadwell-noTSX-IBRS",
|
||||
+ .level = 0xd,
|
||||
+ .vendor = CPUID_VENDOR_INTEL,
|
||||
+ .family = 6,
|
||||
+ .model = 61,
|
||||
+ .stepping = 2,
|
||||
+ .features[FEAT_1_EDX] =
|
||||
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
||||
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
|
||||
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
|
||||
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
|
||||
+ CPUID_DE | CPUID_FP87,
|
||||
+ .features[FEAT_1_ECX] =
|
||||
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
||||
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
|
||||
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
||||
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
|
||||
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
|
||||
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
||||
+ .features[FEAT_8000_0001_EDX] =
|
||||
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
||||
+ CPUID_EXT2_SYSCALL,
|
||||
+ .features[FEAT_8000_0001_ECX] =
|
||||
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
|
||||
+ .features[FEAT_7_0_EDX] =
|
||||
+ CPUID_7_0_EDX_SPEC_CTRL,
|
||||
+ .features[FEAT_7_0_EBX] =
|
||||
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
|
||||
+ CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
|
||||
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
|
||||
+ CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
|
||||
+ CPUID_7_0_EBX_SMAP,
|
||||
+ .features[FEAT_XSAVE] =
|
||||
+ CPUID_XSAVE_XSAVEOPT,
|
||||
+ .features[FEAT_6_EAX] =
|
||||
+ CPUID_6_EAX_ARAT,
|
||||
+ .xlevel = 0x80000008,
|
||||
+ .model_id = "Intel Core Processor (Broadwell, no TSX, IBRS)",
|
||||
+ },
|
||||
+ {
|
||||
.name = "Broadwell",
|
||||
.level = 0xd,
|
||||
.vendor = CPUID_VENDOR_INTEL,
|
||||
@@ -1324,6 +1564,46 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
.model_id = "Intel Core Processor (Broadwell)",
|
||||
},
|
||||
{
|
||||
+ .name = "Broadwell-IBRS",
|
||||
+ .level = 0xd,
|
||||
+ .vendor = CPUID_VENDOR_INTEL,
|
||||
+ .family = 6,
|
||||
+ .model = 61,
|
||||
+ .stepping = 2,
|
||||
+ .features[FEAT_1_EDX] =
|
||||
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
||||
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
|
||||
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
|
||||
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
|
||||
+ CPUID_DE | CPUID_FP87,
|
||||
+ .features[FEAT_1_ECX] =
|
||||
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
||||
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
|
||||
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
||||
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
|
||||
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
|
||||
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
||||
+ .features[FEAT_8000_0001_EDX] =
|
||||
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
||||
+ CPUID_EXT2_SYSCALL,
|
||||
+ .features[FEAT_8000_0001_ECX] =
|
||||
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
|
||||
+ .features[FEAT_7_0_EDX] =
|
||||
+ CPUID_7_0_EDX_SPEC_CTRL,
|
||||
+ .features[FEAT_7_0_EBX] =
|
||||
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
|
||||
+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
|
||||
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
|
||||
+ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
|
||||
+ CPUID_7_0_EBX_SMAP,
|
||||
+ .features[FEAT_XSAVE] =
|
||||
+ CPUID_XSAVE_XSAVEOPT,
|
||||
+ .features[FEAT_6_EAX] =
|
||||
+ CPUID_6_EAX_ARAT,
|
||||
+ .xlevel = 0x80000008,
|
||||
+ .model_id = "Intel Core Processor (Broadwell, IBRS)",
|
||||
+ },
|
||||
+ {
|
||||
.name = "Skylake-Client",
|
||||
.level = 0xd,
|
||||
.vendor = CPUID_VENDOR_INTEL,
|
||||
@@ -1369,6 +1649,151 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
.model_id = "Intel Core Processor (Skylake)",
|
||||
},
|
||||
{
|
||||
+ .name = "Skylake-Client-IBRS",
|
||||
+ .level = 0xd,
|
||||
+ .vendor = CPUID_VENDOR_INTEL,
|
||||
+ .family = 6,
|
||||
+ .model = 94,
|
||||
+ .stepping = 3,
|
||||
+ .features[FEAT_1_EDX] =
|
||||
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
||||
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
|
||||
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
|
||||
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
|
||||
+ CPUID_DE | CPUID_FP87,
|
||||
+ .features[FEAT_1_ECX] =
|
||||
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
||||
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
|
||||
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
||||
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
|
||||
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
|
||||
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
||||
+ .features[FEAT_8000_0001_EDX] =
|
||||
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
||||
+ CPUID_EXT2_SYSCALL,
|
||||
+ .features[FEAT_8000_0001_ECX] =
|
||||
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
|
||||
+ .features[FEAT_7_0_EDX] =
|
||||
+ CPUID_7_0_EDX_SPEC_CTRL,
|
||||
+ .features[FEAT_7_0_EBX] =
|
||||
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
|
||||
+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
|
||||
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
|
||||
+ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
|
||||
+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX,
|
||||
+ /* Missing: XSAVES (not supported by some Linux versions,
|
||||
+ * including v4.1 to v4.12).
|
||||
+ * KVM doesn't yet expose any XSAVES state save component,
|
||||
+ * and the only one defined in Skylake (processor tracing)
|
||||
+ * probably will block migration anyway.
|
||||
+ */
|
||||
+ .features[FEAT_XSAVE] =
|
||||
+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
|
||||
+ CPUID_XSAVE_XGETBV1,
|
||||
+ .features[FEAT_6_EAX] =
|
||||
+ CPUID_6_EAX_ARAT,
|
||||
+ .xlevel = 0x80000008,
|
||||
+ .model_id = "Intel Core Processor (Skylake, IBRS)",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "Skylake-Server",
|
||||
+ .level = 0xd,
|
||||
+ .vendor = CPUID_VENDOR_INTEL,
|
||||
+ .family = 6,
|
||||
+ .model = 85,
|
||||
+ .stepping = 4,
|
||||
+ .features[FEAT_1_EDX] =
|
||||
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
||||
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
|
||||
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
|
||||
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
|
||||
+ CPUID_DE | CPUID_FP87,
|
||||
+ .features[FEAT_1_ECX] =
|
||||
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
||||
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
|
||||
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
||||
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
|
||||
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
|
||||
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
||||
+ .features[FEAT_8000_0001_EDX] =
|
||||
+ CPUID_EXT2_LM | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP |
|
||||
+ CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
|
||||
+ .features[FEAT_8000_0001_ECX] =
|
||||
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
|
||||
+ .features[FEAT_7_0_EBX] =
|
||||
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
|
||||
+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
|
||||
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
|
||||
+ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
|
||||
+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_CLWB |
|
||||
+ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ |
|
||||
+ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD |
|
||||
+ CPUID_7_0_EBX_AVX512VL,
|
||||
+ /* Missing: XSAVES (not supported by some Linux versions,
|
||||
+ * including v4.1 to v4.12).
|
||||
+ * KVM doesn't yet expose any XSAVES state save component,
|
||||
+ * and the only one defined in Skylake (processor tracing)
|
||||
+ * probably will block migration anyway.
|
||||
+ */
|
||||
+ .features[FEAT_XSAVE] =
|
||||
+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
|
||||
+ CPUID_XSAVE_XGETBV1,
|
||||
+ .features[FEAT_6_EAX] =
|
||||
+ CPUID_6_EAX_ARAT,
|
||||
+ .xlevel = 0x80000008,
|
||||
+ .model_id = "Intel Xeon Processor (Skylake)",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "Skylake-Server-IBRS",
|
||||
+ .level = 0xd,
|
||||
+ .vendor = CPUID_VENDOR_INTEL,
|
||||
+ .family = 6,
|
||||
+ .model = 85,
|
||||
+ .stepping = 4,
|
||||
+ .features[FEAT_1_EDX] =
|
||||
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
||||
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
|
||||
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
|
||||
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
|
||||
+ CPUID_DE | CPUID_FP87,
|
||||
+ .features[FEAT_1_ECX] =
|
||||
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
||||
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
|
||||
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
||||
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
|
||||
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
|
||||
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
||||
+ .features[FEAT_8000_0001_EDX] =
|
||||
+ CPUID_EXT2_LM | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP |
|
||||
+ CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
|
||||
+ .features[FEAT_8000_0001_ECX] =
|
||||
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
|
||||
+ .features[FEAT_7_0_EDX] =
|
||||
+ CPUID_7_0_EDX_SPEC_CTRL,
|
||||
+ .features[FEAT_7_0_EBX] =
|
||||
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
|
||||
+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
|
||||
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
|
||||
+ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
|
||||
+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_CLWB |
|
||||
+ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ |
|
||||
+ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD |
|
||||
+ CPUID_7_0_EBX_AVX512VL,
|
||||
+ /* Missing: XSAVES (not supported by some Linux versions,
|
||||
+ * including v4.1 to v4.12).
|
||||
+ * KVM doesn't yet expose any XSAVES state save component,
|
||||
+ * and the only one defined in Skylake (processor tracing)
|
||||
+ * probably will block migration anyway.
|
||||
+ */
|
||||
+ .features[FEAT_XSAVE] =
|
||||
+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
|
||||
+ CPUID_XSAVE_XGETBV1,
|
||||
+ .features[FEAT_6_EAX] =
|
||||
+ CPUID_6_EAX_ARAT,
|
||||
+ .xlevel = 0x80000008,
|
||||
+ .model_id = "Intel Xeon Processor (Skylake, IBRS)",
|
||||
+ },
|
||||
+ {
|
||||
.name = "Opteron_G1",
|
||||
.level = 5,
|
||||
.vendor = CPUID_VENDOR_AMD,
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,121 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Thu, 1 Jun 2017 12:44:56 +0200
|
||||
Subject: [PATCH] nbd: make it thread-safe, fix qcow2 over nbd
|
||||
|
||||
NBD is not thread safe, because it accesses s->in_flight without
|
||||
a CoMutex. Fixing this will be required for multiqueue.
|
||||
CoQueue doesn't have spurious wakeups but, when another coroutine can
|
||||
run between qemu_co_queue_next's wakeup and qemu_co_queue_wait's
|
||||
re-locking of the mutex, the wait condition can become false and
|
||||
a loop is necessary.
|
||||
|
||||
In fact, it turns out that the loop is necessary even without this
|
||||
multi-threaded scenario. A particular sequence of coroutine wakeups
|
||||
is happening ~80% of the time when starting a guest with qcow2 image
|
||||
served over NBD (i.e. qemu-nbd --format=raw, and QEMU's -drive option
|
||||
has -format=qcow2). This patch fixes that issue too.
|
||||
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
---
|
||||
block/nbd-client.c | 30 +++++++++---------------------
|
||||
1 file changed, 9 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/block/nbd-client.c b/block/nbd-client.c
|
||||
index 56eb0e2e16..282679b4f8 100644
|
||||
--- a/block/nbd-client.c
|
||||
+++ b/block/nbd-client.c
|
||||
@@ -114,6 +114,10 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
int rc, ret, i;
|
||||
|
||||
qemu_co_mutex_lock(&s->send_mutex);
|
||||
+ while (s->in_flight == MAX_NBD_REQUESTS) {
|
||||
+ qemu_co_queue_wait(&s->free_sema, &s->send_mutex);
|
||||
+ }
|
||||
+ s->in_flight++;
|
||||
|
||||
for (i = 0; i < MAX_NBD_REQUESTS; i++) {
|
||||
if (s->recv_coroutine[i] == NULL) {
|
||||
@@ -176,20 +180,6 @@ static void nbd_co_receive_reply(NBDClientSession *s,
|
||||
}
|
||||
}
|
||||
|
||||
-static void nbd_coroutine_start(NBDClientSession *s,
|
||||
- NBDRequest *request)
|
||||
-{
|
||||
- /* Poor man semaphore. The free_sema is locked when no other request
|
||||
- * can be accepted, and unlocked after receiving one reply. */
|
||||
- if (s->in_flight == MAX_NBD_REQUESTS) {
|
||||
- qemu_co_queue_wait(&s->free_sema, NULL);
|
||||
- assert(s->in_flight < MAX_NBD_REQUESTS);
|
||||
- }
|
||||
- s->in_flight++;
|
||||
-
|
||||
- /* s->recv_coroutine[i] is set as soon as we get the send_lock. */
|
||||
-}
|
||||
-
|
||||
static void nbd_coroutine_end(BlockDriverState *bs,
|
||||
NBDRequest *request)
|
||||
{
|
||||
@@ -197,13 +187,16 @@ static void nbd_coroutine_end(BlockDriverState *bs,
|
||||
int i = HANDLE_TO_INDEX(s, request->handle);
|
||||
|
||||
s->recv_coroutine[i] = NULL;
|
||||
- s->in_flight--;
|
||||
- qemu_co_queue_next(&s->free_sema);
|
||||
|
||||
/* Kick the read_reply_co to get the next reply. */
|
||||
if (s->read_reply_co) {
|
||||
aio_co_wake(s->read_reply_co);
|
||||
}
|
||||
+
|
||||
+ qemu_co_mutex_lock(&s->send_mutex);
|
||||
+ s->in_flight--;
|
||||
+ qemu_co_queue_next(&s->free_sema);
|
||||
+ qemu_co_mutex_unlock(&s->send_mutex);
|
||||
}
|
||||
|
||||
int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
@@ -221,7 +214,6 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
assert(bytes <= NBD_MAX_BUFFER_SIZE);
|
||||
assert(!flags);
|
||||
|
||||
- nbd_coroutine_start(client, &request);
|
||||
ret = nbd_co_send_request(bs, &request, NULL);
|
||||
if (ret < 0) {
|
||||
reply.error = -ret;
|
||||
@@ -251,7 +243,6 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
|
||||
assert(bytes <= NBD_MAX_BUFFER_SIZE);
|
||||
|
||||
- nbd_coroutine_start(client, &request);
|
||||
ret = nbd_co_send_request(bs, &request, qiov);
|
||||
if (ret < 0) {
|
||||
reply.error = -ret;
|
||||
@@ -286,7 +277,6 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
||||
request.flags |= NBD_CMD_FLAG_NO_HOLE;
|
||||
}
|
||||
|
||||
- nbd_coroutine_start(client, &request);
|
||||
ret = nbd_co_send_request(bs, &request, NULL);
|
||||
if (ret < 0) {
|
||||
reply.error = -ret;
|
||||
@@ -311,7 +301,6 @@ int nbd_client_co_flush(BlockDriverState *bs)
|
||||
request.from = 0;
|
||||
request.len = 0;
|
||||
|
||||
- nbd_coroutine_start(client, &request);
|
||||
ret = nbd_co_send_request(bs, &request, NULL);
|
||||
if (ret < 0) {
|
||||
reply.error = -ret;
|
||||
@@ -337,7 +326,6 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
|
||||
return 0;
|
||||
}
|
||||
|
||||
- nbd_coroutine_start(client, &request);
|
||||
ret = nbd_co_send_request(bs, &request, NULL);
|
||||
if (ret < 0) {
|
||||
reply.error = -ret;
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,52 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||||
Date: Tue, 16 May 2017 12:45:29 +0300
|
||||
Subject: [PATCH] nbd: strict nbd_wr_syncv
|
||||
|
||||
nbd_wr_syncv is called either from coroutine or from client negotiation
|
||||
code, when socket is in blocking mode. So, -EAGAIN is impossible.
|
||||
|
||||
Furthermore, EAGAIN is confusing, as, what to read/write again? With
|
||||
EAGAIN as a return code we don't know how much data is already
|
||||
read or written by the function, so in case of EAGAIN the whole
|
||||
communication is broken.
|
||||
|
||||
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||||
Message-Id: <20170516094533.6160-2-vsementsov@virtuozzo.com>
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
---
|
||||
nbd/common.c | 11 ++++++-----
|
||||
1 file changed, 6 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/nbd/common.c b/nbd/common.c
|
||||
index dccbb8e9de..4db45b3ede 100644
|
||||
--- a/nbd/common.c
|
||||
+++ b/nbd/common.c
|
||||
@@ -20,6 +20,10 @@
|
||||
#include "qapi/error.h"
|
||||
#include "nbd-internal.h"
|
||||
|
||||
+/* nbd_wr_syncv
|
||||
+ * The function may be called from coroutine or from non-coroutine context.
|
||||
+ * When called from non-coroutine context @ioc must be in blocking mode.
|
||||
+ */
|
||||
ssize_t nbd_wr_syncv(QIOChannel *ioc,
|
||||
struct iovec *iov,
|
||||
size_t niov,
|
||||
@@ -42,11 +46,8 @@ ssize_t nbd_wr_syncv(QIOChannel *ioc,
|
||||
len = qio_channel_writev(ioc, local_iov, nlocal_iov, &local_err);
|
||||
}
|
||||
if (len == QIO_CHANNEL_ERR_BLOCK) {
|
||||
- if (qemu_in_coroutine()) {
|
||||
- qio_channel_yield(ioc, do_read ? G_IO_IN : G_IO_OUT);
|
||||
- } else {
|
||||
- return -EAGAIN;
|
||||
- }
|
||||
+ assert(qemu_in_coroutine());
|
||||
+ qio_channel_yield(ioc, do_read ? G_IO_IN : G_IO_OUT);
|
||||
continue;
|
||||
}
|
||||
if (len < 0) {
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,606 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||||
Date: Tue, 16 May 2017 12:45:30 +0300
|
||||
Subject: [PATCH] nbd: read_sync and friends: return 0 on success
|
||||
|
||||
functions read_sync, drop_sync, write_sync, and also
|
||||
nbd_negotiate_write, nbd_negotiate_read, nbd_negotiate_drop_sync
|
||||
returns number of processed bytes. But what this number can be,
|
||||
except requested number of bytes?
|
||||
|
||||
Actually, underlying nbd_wr_syncv function returns a value >= 0 and
|
||||
!= requested_bytes only on eof on read operation. So, firstly, it is
|
||||
impossible on write (let's add an assert) and on read it actually
|
||||
means, that communication is broken (except nbd_receive_reply, see
|
||||
below).
|
||||
|
||||
Most of callers operate like this:
|
||||
if (func(..., size) != size) {
|
||||
/* error path */
|
||||
}
|
||||
, i.e.:
|
||||
1. They are not interested in partial success
|
||||
2. Extra duplications in code (especially bad are duplications of
|
||||
magic numbers)
|
||||
3. User doesn't see actual error message, as return code is lost.
|
||||
(this patch doesn't fix this point, but it makes fixing easier)
|
||||
|
||||
Several callers handles ret >= 0 and != requested-size separately, by
|
||||
just returning EINVAL in this case. This patch makes read_sync and
|
||||
friends return EINVAL in this case, so final behavior is the same.
|
||||
|
||||
And only one caller - nbd_receive_reply() does something not so
|
||||
obvious. It returns EINVAL for ret > 0 and != requested-size, like
|
||||
previous group, but for ret == 0 it returns 0. The only caller of
|
||||
nbd_receive_reply() - nbd_read_reply_entry() handles ret == 0 in the
|
||||
same way as ret < 0, so for now it doesn't matter. However, in
|
||||
following commits error path handling will be improved and we'll need
|
||||
to distinguish success from fail in this case too. So, this patch adds
|
||||
separate helper for this case - read_sync_eof.
|
||||
|
||||
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||||
Message-Id: <20170516094533.6160-3-vsementsov@virtuozzo.com>
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
---
|
||||
nbd/client.c | 63 ++++++++++++++++------------------------
|
||||
nbd/nbd-internal.h | 34 +++++++++++++++++++---
|
||||
nbd/server.c | 84 +++++++++++++++++++++---------------------------------
|
||||
3 files changed, 88 insertions(+), 93 deletions(-)
|
||||
|
||||
diff --git a/nbd/client.c b/nbd/client.c
|
||||
index a58fb02cb4..6b74a628f1 100644
|
||||
--- a/nbd/client.c
|
||||
+++ b/nbd/client.c
|
||||
@@ -86,9 +86,9 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
|
||||
|
||||
*/
|
||||
|
||||
-/* Discard length bytes from channel. Return -errno on failure, or
|
||||
- * the amount of bytes consumed. */
|
||||
-static ssize_t drop_sync(QIOChannel *ioc, size_t size)
|
||||
+/* Discard length bytes from channel. Return -errno on failure and 0 on
|
||||
+ * success*/
|
||||
+static int drop_sync(QIOChannel *ioc, size_t size)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
char small[1024];
|
||||
@@ -96,14 +96,13 @@ static ssize_t drop_sync(QIOChannel *ioc, size_t size)
|
||||
|
||||
buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size));
|
||||
while (size > 0) {
|
||||
- ssize_t count = read_sync(ioc, buffer, MIN(65536, size));
|
||||
+ ssize_t count = MIN(65536, size);
|
||||
+ ret = read_sync(ioc, buffer, MIN(65536, size));
|
||||
|
||||
- if (count <= 0) {
|
||||
+ if (ret < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
- assert(count <= size);
|
||||
size -= count;
|
||||
- ret += count;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
@@ -136,12 +135,12 @@ static int nbd_send_option_request(QIOChannel *ioc, uint32_t opt,
|
||||
stl_be_p(&req.option, opt);
|
||||
stl_be_p(&req.length, len);
|
||||
|
||||
- if (write_sync(ioc, &req, sizeof(req)) != sizeof(req)) {
|
||||
+ if (write_sync(ioc, &req, sizeof(req)) < 0) {
|
||||
error_setg(errp, "Failed to send option request header");
|
||||
return -1;
|
||||
}
|
||||
|
||||
- if (len && write_sync(ioc, (char *) data, len) != len) {
|
||||
+ if (len && write_sync(ioc, (char *) data, len) < 0) {
|
||||
error_setg(errp, "Failed to send option request data");
|
||||
return -1;
|
||||
}
|
||||
@@ -170,7 +169,7 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt,
|
||||
nbd_opt_reply *reply, Error **errp)
|
||||
{
|
||||
QEMU_BUILD_BUG_ON(sizeof(*reply) != 20);
|
||||
- if (read_sync(ioc, reply, sizeof(*reply)) != sizeof(*reply)) {
|
||||
+ if (read_sync(ioc, reply, sizeof(*reply)) < 0) {
|
||||
error_setg(errp, "failed to read option reply");
|
||||
nbd_send_opt_abort(ioc);
|
||||
return -1;
|
||||
@@ -219,7 +218,7 @@ static int nbd_handle_reply_err(QIOChannel *ioc, nbd_opt_reply *reply,
|
||||
goto cleanup;
|
||||
}
|
||||
msg = g_malloc(reply->length + 1);
|
||||
- if (read_sync(ioc, msg, reply->length) != reply->length) {
|
||||
+ if (read_sync(ioc, msg, reply->length) < 0) {
|
||||
error_setg(errp, "failed to read option error message");
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -321,7 +320,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
|
||||
nbd_send_opt_abort(ioc);
|
||||
return -1;
|
||||
}
|
||||
- if (read_sync(ioc, &namelen, sizeof(namelen)) != sizeof(namelen)) {
|
||||
+ if (read_sync(ioc, &namelen, sizeof(namelen)) < 0) {
|
||||
error_setg(errp, "failed to read option name length");
|
||||
nbd_send_opt_abort(ioc);
|
||||
return -1;
|
||||
@@ -334,7 +333,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
|
||||
return -1;
|
||||
}
|
||||
if (namelen != strlen(want)) {
|
||||
- if (drop_sync(ioc, len) != len) {
|
||||
+ if (drop_sync(ioc, len) < 0) {
|
||||
error_setg(errp, "failed to skip export name with wrong length");
|
||||
nbd_send_opt_abort(ioc);
|
||||
return -1;
|
||||
@@ -343,14 +342,14 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
|
||||
}
|
||||
|
||||
assert(namelen < sizeof(name));
|
||||
- if (read_sync(ioc, name, namelen) != namelen) {
|
||||
+ if (read_sync(ioc, name, namelen) < 0) {
|
||||
error_setg(errp, "failed to read export name");
|
||||
nbd_send_opt_abort(ioc);
|
||||
return -1;
|
||||
}
|
||||
name[namelen] = '\0';
|
||||
len -= namelen;
|
||||
- if (drop_sync(ioc, len) != len) {
|
||||
+ if (drop_sync(ioc, len) < 0) {
|
||||
error_setg(errp, "failed to read export description");
|
||||
nbd_send_opt_abort(ioc);
|
||||
return -1;
|
||||
@@ -477,7 +476,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- if (read_sync(ioc, buf, 8) != 8) {
|
||||
+ if (read_sync(ioc, buf, 8) < 0) {
|
||||
error_setg(errp, "Failed to read data");
|
||||
goto fail;
|
||||
}
|
||||
@@ -503,7 +502,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- if (read_sync(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
|
||||
+ if (read_sync(ioc, &magic, sizeof(magic)) < 0) {
|
||||
error_setg(errp, "Failed to read magic");
|
||||
goto fail;
|
||||
}
|
||||
@@ -515,8 +514,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
|
||||
uint16_t globalflags;
|
||||
bool fixedNewStyle = false;
|
||||
|
||||
- if (read_sync(ioc, &globalflags, sizeof(globalflags)) !=
|
||||
- sizeof(globalflags)) {
|
||||
+ if (read_sync(ioc, &globalflags, sizeof(globalflags)) < 0) {
|
||||
error_setg(errp, "Failed to read server flags");
|
||||
goto fail;
|
||||
}
|
||||
@@ -534,8 +532,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
|
||||
}
|
||||
/* client requested flags */
|
||||
clientflags = cpu_to_be32(clientflags);
|
||||
- if (write_sync(ioc, &clientflags, sizeof(clientflags)) !=
|
||||
- sizeof(clientflags)) {
|
||||
+ if (write_sync(ioc, &clientflags, sizeof(clientflags)) < 0) {
|
||||
error_setg(errp, "Failed to send clientflags field");
|
||||
goto fail;
|
||||
}
|
||||
@@ -573,13 +570,13 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
|
||||
}
|
||||
|
||||
/* Read the response */
|
||||
- if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) {
|
||||
+ if (read_sync(ioc, &s, sizeof(s)) < 0) {
|
||||
error_setg(errp, "Failed to read export length");
|
||||
goto fail;
|
||||
}
|
||||
*size = be64_to_cpu(s);
|
||||
|
||||
- if (read_sync(ioc, flags, sizeof(*flags)) != sizeof(*flags)) {
|
||||
+ if (read_sync(ioc, flags, sizeof(*flags)) < 0) {
|
||||
error_setg(errp, "Failed to read export flags");
|
||||
goto fail;
|
||||
}
|
||||
@@ -596,14 +593,14 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) {
|
||||
+ if (read_sync(ioc, &s, sizeof(s)) < 0) {
|
||||
error_setg(errp, "Failed to read export length");
|
||||
goto fail;
|
||||
}
|
||||
*size = be64_to_cpu(s);
|
||||
TRACE("Size is %" PRIu64, *size);
|
||||
|
||||
- if (read_sync(ioc, &oldflags, sizeof(oldflags)) != sizeof(oldflags)) {
|
||||
+ if (read_sync(ioc, &oldflags, sizeof(oldflags)) < 0) {
|
||||
error_setg(errp, "Failed to read export flags");
|
||||
goto fail;
|
||||
}
|
||||
@@ -619,7 +616,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
|
||||
}
|
||||
|
||||
TRACE("Size is %" PRIu64 ", export flags %" PRIx16, *size, *flags);
|
||||
- if (zeroes && drop_sync(ioc, 124) != 124) {
|
||||
+ if (zeroes && drop_sync(ioc, 124) < 0) {
|
||||
error_setg(errp, "Failed to read reserved block");
|
||||
goto fail;
|
||||
}
|
||||
@@ -744,7 +741,6 @@ int nbd_disconnect(int fd)
|
||||
ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request)
|
||||
{
|
||||
uint8_t buf[NBD_REQUEST_SIZE];
|
||||
- ssize_t ret;
|
||||
|
||||
TRACE("Sending request to server: "
|
||||
"{ .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64
|
||||
@@ -759,16 +755,7 @@ ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request)
|
||||
stq_be_p(buf + 16, request->from);
|
||||
stl_be_p(buf + 24, request->len);
|
||||
|
||||
- ret = write_sync(ioc, buf, sizeof(buf));
|
||||
- if (ret < 0) {
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- if (ret != sizeof(buf)) {
|
||||
- LOG("writing to socket failed");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
- return 0;
|
||||
+ return write_sync(ioc, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply)
|
||||
@@ -777,7 +764,7 @@ ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply)
|
||||
uint32_t magic;
|
||||
ssize_t ret;
|
||||
|
||||
- ret = read_sync(ioc, buf, sizeof(buf));
|
||||
+ ret = read_sync_eof(ioc, buf, sizeof(buf));
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
}
|
||||
diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
|
||||
index f43d990a05..e6bbc7c4b4 100644
|
||||
--- a/nbd/nbd-internal.h
|
||||
+++ b/nbd/nbd-internal.h
|
||||
@@ -94,7 +94,13 @@
|
||||
#define NBD_ENOSPC 28
|
||||
#define NBD_ESHUTDOWN 108
|
||||
|
||||
-static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size)
|
||||
+/* read_sync_eof
|
||||
+ * Tries to read @size bytes from @ioc. Returns number of bytes actually read.
|
||||
+ * May return a value >= 0 and < size only on EOF, i.e. when iteratively called
|
||||
+ * qio_channel_readv() returns 0. So, there are no needs to call read_sync_eof
|
||||
+ * iteratively.
|
||||
+ */
|
||||
+static inline ssize_t read_sync_eof(QIOChannel *ioc, void *buffer, size_t size)
|
||||
{
|
||||
struct iovec iov = { .iov_base = buffer, .iov_len = size };
|
||||
/* Sockets are kept in blocking mode in the negotiation phase. After
|
||||
@@ -105,12 +111,32 @@ static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size)
|
||||
return nbd_wr_syncv(ioc, &iov, 1, size, true);
|
||||
}
|
||||
|
||||
-static inline ssize_t write_sync(QIOChannel *ioc, const void *buffer,
|
||||
- size_t size)
|
||||
+/* read_sync
|
||||
+ * Reads @size bytes from @ioc. Returns 0 on success.
|
||||
+ */
|
||||
+static inline int read_sync(QIOChannel *ioc, void *buffer, size_t size)
|
||||
+{
|
||||
+ ssize_t ret = read_sync_eof(ioc, buffer, size);
|
||||
+
|
||||
+ if (ret >= 0 && ret != size) {
|
||||
+ ret = -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return ret < 0 ? ret : 0;
|
||||
+}
|
||||
+
|
||||
+/* write_sync
|
||||
+ * Writes @size bytes to @ioc. Returns 0 on success.
|
||||
+ */
|
||||
+static inline int write_sync(QIOChannel *ioc, const void *buffer, size_t size)
|
||||
{
|
||||
struct iovec iov = { .iov_base = (void *) buffer, .iov_len = size };
|
||||
|
||||
- return nbd_wr_syncv(ioc, &iov, 1, size, false);
|
||||
+ ssize_t ret = nbd_wr_syncv(ioc, &iov, 1, size, false);
|
||||
+
|
||||
+ assert(ret < 0 || ret == size);
|
||||
+
|
||||
+ return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
struct NBDTLSHandshakeData {
|
||||
diff --git a/nbd/server.c b/nbd/server.c
|
||||
index 4d6da8ac06..c2a5909ad6 100644
|
||||
--- a/nbd/server.c
|
||||
+++ b/nbd/server.c
|
||||
@@ -112,7 +112,7 @@ static gboolean nbd_negotiate_continue(QIOChannel *ioc,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
-static ssize_t nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size)
|
||||
+static int nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size)
|
||||
{
|
||||
ssize_t ret;
|
||||
guint watch;
|
||||
@@ -130,8 +130,7 @@ static ssize_t nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size)
|
||||
|
||||
}
|
||||
|
||||
-static ssize_t nbd_negotiate_write(QIOChannel *ioc, const void *buffer,
|
||||
- size_t size)
|
||||
+static int nbd_negotiate_write(QIOChannel *ioc, const void *buffer, size_t size)
|
||||
{
|
||||
ssize_t ret;
|
||||
guint watch;
|
||||
@@ -148,24 +147,24 @@ static ssize_t nbd_negotiate_write(QIOChannel *ioc, const void *buffer,
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static ssize_t nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size)
|
||||
+static int nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size)
|
||||
{
|
||||
- ssize_t ret, dropped = size;
|
||||
+ ssize_t ret;
|
||||
uint8_t *buffer = g_malloc(MIN(65536, size));
|
||||
|
||||
while (size > 0) {
|
||||
- ret = nbd_negotiate_read(ioc, buffer, MIN(65536, size));
|
||||
+ size_t count = MIN(65536, size);
|
||||
+ ret = nbd_negotiate_read(ioc, buffer, count);
|
||||
if (ret < 0) {
|
||||
g_free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
- assert(ret <= size);
|
||||
- size -= ret;
|
||||
+ size -= count;
|
||||
}
|
||||
|
||||
g_free(buffer);
|
||||
- return dropped;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/* Basic flow for negotiation
|
||||
@@ -206,22 +205,22 @@ static int nbd_negotiate_send_rep_len(QIOChannel *ioc, uint32_t type,
|
||||
type, opt, len);
|
||||
|
||||
magic = cpu_to_be64(NBD_REP_MAGIC);
|
||||
- if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
|
||||
+ if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) < 0) {
|
||||
LOG("write failed (rep magic)");
|
||||
return -EINVAL;
|
||||
}
|
||||
opt = cpu_to_be32(opt);
|
||||
- if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) != sizeof(opt)) {
|
||||
+ if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) < 0) {
|
||||
LOG("write failed (rep opt)");
|
||||
return -EINVAL;
|
||||
}
|
||||
type = cpu_to_be32(type);
|
||||
- if (nbd_negotiate_write(ioc, &type, sizeof(type)) != sizeof(type)) {
|
||||
+ if (nbd_negotiate_write(ioc, &type, sizeof(type)) < 0) {
|
||||
LOG("write failed (rep type)");
|
||||
return -EINVAL;
|
||||
}
|
||||
len = cpu_to_be32(len);
|
||||
- if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) {
|
||||
+ if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) {
|
||||
LOG("write failed (rep data length)");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -256,7 +255,7 @@ nbd_negotiate_send_rep_err(QIOChannel *ioc, uint32_t type,
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
- if (nbd_negotiate_write(ioc, msg, len) != len) {
|
||||
+ if (nbd_negotiate_write(ioc, msg, len) < 0) {
|
||||
LOG("write failed (error message)");
|
||||
ret = -EIO;
|
||||
} else {
|
||||
@@ -287,15 +286,15 @@ static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp)
|
||||
}
|
||||
|
||||
len = cpu_to_be32(name_len);
|
||||
- if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) {
|
||||
+ if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) {
|
||||
LOG("write failed (name length)");
|
||||
return -EINVAL;
|
||||
}
|
||||
- if (nbd_negotiate_write(ioc, name, name_len) != name_len) {
|
||||
+ if (nbd_negotiate_write(ioc, name, name_len) < 0) {
|
||||
LOG("write failed (name buffer)");
|
||||
return -EINVAL;
|
||||
}
|
||||
- if (nbd_negotiate_write(ioc, desc, desc_len) != desc_len) {
|
||||
+ if (nbd_negotiate_write(ioc, desc, desc_len) < 0) {
|
||||
LOG("write failed (description buffer)");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -309,7 +308,7 @@ static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length)
|
||||
NBDExport *exp;
|
||||
|
||||
if (length) {
|
||||
- if (nbd_negotiate_drop_sync(client->ioc, length) != length) {
|
||||
+ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
return nbd_negotiate_send_rep_err(client->ioc,
|
||||
@@ -340,7 +339,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t length)
|
||||
LOG("Bad length received");
|
||||
goto fail;
|
||||
}
|
||||
- if (nbd_negotiate_read(client->ioc, name, length) != length) {
|
||||
+ if (nbd_negotiate_read(client->ioc, name, length) < 0) {
|
||||
LOG("read failed");
|
||||
goto fail;
|
||||
}
|
||||
@@ -373,7 +372,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
|
||||
TRACE("Setting up TLS");
|
||||
ioc = client->ioc;
|
||||
if (length) {
|
||||
- if (nbd_negotiate_drop_sync(ioc, length) != length) {
|
||||
+ if (nbd_negotiate_drop_sync(ioc, length) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
nbd_negotiate_send_rep_err(ioc, NBD_REP_ERR_INVALID, NBD_OPT_STARTTLS,
|
||||
@@ -437,8 +436,7 @@ static int nbd_negotiate_options(NBDClient *client)
|
||||
... Rest of request
|
||||
*/
|
||||
|
||||
- if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) !=
|
||||
- sizeof(flags)) {
|
||||
+ if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) < 0) {
|
||||
LOG("read failed");
|
||||
return -EIO;
|
||||
}
|
||||
@@ -464,8 +462,7 @@ static int nbd_negotiate_options(NBDClient *client)
|
||||
uint32_t clientflags, length;
|
||||
uint64_t magic;
|
||||
|
||||
- if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) !=
|
||||
- sizeof(magic)) {
|
||||
+ if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) < 0) {
|
||||
LOG("read failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -476,14 +473,14 @@ static int nbd_negotiate_options(NBDClient *client)
|
||||
}
|
||||
|
||||
if (nbd_negotiate_read(client->ioc, &clientflags,
|
||||
- sizeof(clientflags)) != sizeof(clientflags)) {
|
||||
+ sizeof(clientflags)) < 0)
|
||||
+ {
|
||||
LOG("read failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
clientflags = be32_to_cpu(clientflags);
|
||||
|
||||
- if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) !=
|
||||
- sizeof(length)) {
|
||||
+ if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) < 0) {
|
||||
LOG("read failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -519,7 +516,7 @@ static int nbd_negotiate_options(NBDClient *client)
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
- if (nbd_negotiate_drop_sync(client->ioc, length) != length) {
|
||||
+ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
ret = nbd_negotiate_send_rep_err(client->ioc,
|
||||
@@ -557,7 +554,7 @@ static int nbd_negotiate_options(NBDClient *client)
|
||||
return nbd_negotiate_handle_export_name(client, length);
|
||||
|
||||
case NBD_OPT_STARTTLS:
|
||||
- if (nbd_negotiate_drop_sync(client->ioc, length) != length) {
|
||||
+ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
if (client->tlscreds) {
|
||||
@@ -576,7 +573,7 @@ static int nbd_negotiate_options(NBDClient *client)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
- if (nbd_negotiate_drop_sync(client->ioc, length) != length) {
|
||||
+ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
ret = nbd_negotiate_send_rep_err(client->ioc,
|
||||
@@ -665,12 +662,12 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data)
|
||||
TRACE("TLS cannot be enabled with oldstyle protocol");
|
||||
goto fail;
|
||||
}
|
||||
- if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) != sizeof(buf)) {
|
||||
+ if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) < 0) {
|
||||
LOG("write failed");
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
- if (nbd_negotiate_write(client->ioc, buf, 18) != 18) {
|
||||
+ if (nbd_negotiate_write(client->ioc, buf, 18) < 0) {
|
||||
LOG("write failed");
|
||||
goto fail;
|
||||
}
|
||||
@@ -685,7 +682,7 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data)
|
||||
stq_be_p(buf + 18, client->exp->size);
|
||||
stw_be_p(buf + 26, client->exp->nbdflags | myflags);
|
||||
len = client->no_zeroes ? 10 : sizeof(buf) - 18;
|
||||
- if (nbd_negotiate_write(client->ioc, buf + 18, len) != len) {
|
||||
+ if (nbd_negotiate_write(client->ioc, buf + 18, len) < 0) {
|
||||
LOG("write failed");
|
||||
goto fail;
|
||||
}
|
||||
@@ -708,11 +705,6 @@ static ssize_t nbd_receive_request(QIOChannel *ioc, NBDRequest *request)
|
||||
return ret;
|
||||
}
|
||||
|
||||
- if (ret != sizeof(buf)) {
|
||||
- LOG("read failed");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
/* Request
|
||||
[ 0 .. 3] magic (NBD_REQUEST_MAGIC)
|
||||
[ 4 .. 5] flags (NBD_CMD_FLAG_FUA, ...)
|
||||
@@ -743,7 +735,6 @@ static ssize_t nbd_receive_request(QIOChannel *ioc, NBDRequest *request)
|
||||
static ssize_t nbd_send_reply(QIOChannel *ioc, NBDReply *reply)
|
||||
{
|
||||
uint8_t buf[NBD_REPLY_SIZE];
|
||||
- ssize_t ret;
|
||||
|
||||
reply->error = system_errno_to_nbd_errno(reply->error);
|
||||
|
||||
@@ -760,16 +751,7 @@ static ssize_t nbd_send_reply(QIOChannel *ioc, NBDReply *reply)
|
||||
stl_be_p(buf + 4, reply->error);
|
||||
stq_be_p(buf + 8, reply->handle);
|
||||
|
||||
- ret = write_sync(ioc, buf, sizeof(buf));
|
||||
- if (ret < 0) {
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- if (ret != sizeof(buf)) {
|
||||
- LOG("writing to socket failed");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
- return 0;
|
||||
+ return write_sync(ioc, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
#define MAX_NBD_REQUESTS 16
|
||||
@@ -1073,7 +1055,7 @@ static ssize_t nbd_co_send_reply(NBDRequestData *req, NBDReply *reply,
|
||||
rc = nbd_send_reply(client->ioc, reply);
|
||||
if (rc >= 0) {
|
||||
ret = write_sync(client->ioc, req->data, len);
|
||||
- if (ret != len) {
|
||||
+ if (ret < 0) {
|
||||
rc = -EIO;
|
||||
}
|
||||
}
|
||||
@@ -1147,7 +1129,7 @@ static ssize_t nbd_co_receive_request(NBDRequestData *req,
|
||||
if (request->type == NBD_CMD_WRITE) {
|
||||
TRACE("Reading %" PRIu32 " byte(s)", request->len);
|
||||
|
||||
- if (read_sync(client->ioc, req->data, request->len) != request->len) {
|
||||
+ if (read_sync(client->ioc, req->data, request->len) < 0) {
|
||||
LOG("reading from socket failed");
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,151 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Wed, 19 Jul 2017 18:02:01 +0200
|
||||
Subject: [PATCH] nbd: make nbd_drop public
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
Message-id: <20170719180202.23329-4-eblake@redhat.com>
|
||||
Patchwork-id: 75814
|
||||
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 3/4] nbd: make nbd_drop public
|
||||
Bugzilla: 1467509
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
|
||||
|
||||
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||||
|
||||
Following commit will reuse it for nbd server too.
|
||||
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||||
Message-Id: <20170602150150.258222-3-vsementsov@virtuozzo.com>
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
(cherry picked from commit 44298024d30ad36439707b89715a76333f58791b)
|
||||
|
||||
Conflicts:
|
||||
nbd/client.c, nbd/nbd_internal.h, nbd/common.c - missing errp
|
||||
addition (e44ed99) and bulk rename (d1fdf25)
|
||||
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
---
|
||||
nbd/client.c | 32 +++-----------------------------
|
||||
nbd/common.c | 26 ++++++++++++++++++++++++++
|
||||
nbd/nbd-internal.h | 2 ++
|
||||
3 files changed, 31 insertions(+), 29 deletions(-)
|
||||
|
||||
diff --git a/nbd/client.c b/nbd/client.c
|
||||
index 6b74a628f1..1652f28e9f 100644
|
||||
--- a/nbd/client.c
|
||||
+++ b/nbd/client.c
|
||||
@@ -86,32 +86,6 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
|
||||
|
||||
*/
|
||||
|
||||
-/* Discard length bytes from channel. Return -errno on failure and 0 on
|
||||
- * success*/
|
||||
-static int drop_sync(QIOChannel *ioc, size_t size)
|
||||
-{
|
||||
- ssize_t ret = 0;
|
||||
- char small[1024];
|
||||
- char *buffer;
|
||||
-
|
||||
- buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size));
|
||||
- while (size > 0) {
|
||||
- ssize_t count = MIN(65536, size);
|
||||
- ret = read_sync(ioc, buffer, MIN(65536, size));
|
||||
-
|
||||
- if (ret < 0) {
|
||||
- goto cleanup;
|
||||
- }
|
||||
- size -= count;
|
||||
- }
|
||||
-
|
||||
- cleanup:
|
||||
- if (buffer != small) {
|
||||
- g_free(buffer);
|
||||
- }
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
/* Send an option request.
|
||||
*
|
||||
* The request is for option @opt, with @data containing @len bytes of
|
||||
@@ -333,7 +307,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
|
||||
return -1;
|
||||
}
|
||||
if (namelen != strlen(want)) {
|
||||
- if (drop_sync(ioc, len) < 0) {
|
||||
+ if (nbd_drop(ioc, len) < 0) {
|
||||
error_setg(errp, "failed to skip export name with wrong length");
|
||||
nbd_send_opt_abort(ioc);
|
||||
return -1;
|
||||
@@ -349,7 +323,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
|
||||
}
|
||||
name[namelen] = '\0';
|
||||
len -= namelen;
|
||||
- if (drop_sync(ioc, len) < 0) {
|
||||
+ if (nbd_drop(ioc, len) < 0) {
|
||||
error_setg(errp, "failed to read export description");
|
||||
nbd_send_opt_abort(ioc);
|
||||
return -1;
|
||||
@@ -616,7 +590,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
|
||||
}
|
||||
|
||||
TRACE("Size is %" PRIu64 ", export flags %" PRIx16, *size, *flags);
|
||||
- if (zeroes && drop_sync(ioc, 124) < 0) {
|
||||
+ if (zeroes && nbd_drop(ioc, 124) < 0) {
|
||||
error_setg(errp, "Failed to read reserved block");
|
||||
goto fail;
|
||||
}
|
||||
diff --git a/nbd/common.c b/nbd/common.c
|
||||
index 4db45b3ede..9a54010c25 100644
|
||||
--- a/nbd/common.c
|
||||
+++ b/nbd/common.c
|
||||
@@ -71,6 +71,32 @@ ssize_t nbd_wr_syncv(QIOChannel *ioc,
|
||||
return done;
|
||||
}
|
||||
|
||||
+/* Discard length bytes from channel. Return -errno on failure and 0 on
|
||||
+ * success */
|
||||
+int nbd_drop(QIOChannel *ioc, size_t size)
|
||||
+{
|
||||
+ ssize_t ret = 0;
|
||||
+ char small[1024];
|
||||
+ char *buffer;
|
||||
+
|
||||
+ buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size));
|
||||
+ while (size > 0) {
|
||||
+ ssize_t count = MIN(65536, size);
|
||||
+ ret = read_sync(ioc, buffer, MIN(65536, size));
|
||||
+
|
||||
+ if (ret < 0) {
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ size -= count;
|
||||
+ }
|
||||
+
|
||||
+ cleanup:
|
||||
+ if (buffer != small) {
|
||||
+ g_free(buffer);
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
|
||||
void nbd_tls_handshake(QIOTask *task,
|
||||
void *opaque)
|
||||
diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
|
||||
index e6bbc7c4b4..c02378c553 100644
|
||||
--- a/nbd/nbd-internal.h
|
||||
+++ b/nbd/nbd-internal.h
|
||||
@@ -149,4 +149,6 @@ struct NBDTLSHandshakeData {
|
||||
void nbd_tls_handshake(QIOTask *task,
|
||||
void *opaque);
|
||||
|
||||
+int nbd_drop(QIOChannel *ioc, size_t size);
|
||||
+
|
||||
#endif
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,292 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Wed, 19 Jul 2017 18:02:02 +0200
|
||||
Subject: [PATCH] nbd/server: get rid of nbd_negotiate_read and friends
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
Message-id: <20170719180202.23329-5-eblake@redhat.com>
|
||||
Patchwork-id: 75816
|
||||
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 4/4] nbd/server: get rid of nbd_negotiate_read and friends
|
||||
Bugzilla: 1467509
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
|
||||
|
||||
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||||
|
||||
Functions nbd_negotiate_{read,write,drop_sync} were introduced in
|
||||
1a6245a5b, when nbd_rwv (was nbd_wr_sync) was working through
|
||||
qemu_co_sendv_recvv (the path is nbd_wr_sync -> qemu_co_{recv/send} ->
|
||||
qemu_co_send_recv -> qemu_co_sendv_recvv), which just yields, without
|
||||
setting any handlers. But starting from ff82911cd nbd_rwv (was
|
||||
nbd_wr_syncv) works through qio_channel_yield() which sets handlers, so
|
||||
watchers are redundant in nbd_negotiate_{read,write,drop_sync}, then,
|
||||
let's just use nbd_{read,write,drop} functions.
|
||||
|
||||
Functions nbd_{read,write,drop} has errp parameter, which is unused in
|
||||
this patch. This will be fixed later.
|
||||
|
||||
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Message-Id: <20170602150150.258222-4-vsementsov@virtuozzo.com>
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
(cherry picked from commit 2b0bbc4f8809c972bad134bc1a2570dbb01dea0b)
|
||||
|
||||
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
nbd/server.c - missing errp addition (e44ed99) and bulk
|
||||
rename (d1fdf25)
|
||||
Fixes CVE-2017-7539
|
||||
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
---
|
||||
nbd/server.c | 106 ++++++++++++-----------------------------------------------
|
||||
1 file changed, 21 insertions(+), 85 deletions(-)
|
||||
|
||||
diff --git a/nbd/server.c b/nbd/server.c
|
||||
index c2a5909ad6..ddf93d4717 100644
|
||||
--- a/nbd/server.c
|
||||
+++ b/nbd/server.c
|
||||
@@ -104,69 +104,6 @@ struct NBDClient {
|
||||
|
||||
static void nbd_client_receive_next_request(NBDClient *client);
|
||||
|
||||
-static gboolean nbd_negotiate_continue(QIOChannel *ioc,
|
||||
- GIOCondition condition,
|
||||
- void *opaque)
|
||||
-{
|
||||
- qemu_coroutine_enter(opaque);
|
||||
- return TRUE;
|
||||
-}
|
||||
-
|
||||
-static int nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size)
|
||||
-{
|
||||
- ssize_t ret;
|
||||
- guint watch;
|
||||
-
|
||||
- assert(qemu_in_coroutine());
|
||||
- /* Negotiation are always in main loop. */
|
||||
- watch = qio_channel_add_watch(ioc,
|
||||
- G_IO_IN,
|
||||
- nbd_negotiate_continue,
|
||||
- qemu_coroutine_self(),
|
||||
- NULL);
|
||||
- ret = read_sync(ioc, buffer, size);
|
||||
- g_source_remove(watch);
|
||||
- return ret;
|
||||
-
|
||||
-}
|
||||
-
|
||||
-static int nbd_negotiate_write(QIOChannel *ioc, const void *buffer, size_t size)
|
||||
-{
|
||||
- ssize_t ret;
|
||||
- guint watch;
|
||||
-
|
||||
- assert(qemu_in_coroutine());
|
||||
- /* Negotiation are always in main loop. */
|
||||
- watch = qio_channel_add_watch(ioc,
|
||||
- G_IO_OUT,
|
||||
- nbd_negotiate_continue,
|
||||
- qemu_coroutine_self(),
|
||||
- NULL);
|
||||
- ret = write_sync(ioc, buffer, size);
|
||||
- g_source_remove(watch);
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static int nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size)
|
||||
-{
|
||||
- ssize_t ret;
|
||||
- uint8_t *buffer = g_malloc(MIN(65536, size));
|
||||
-
|
||||
- while (size > 0) {
|
||||
- size_t count = MIN(65536, size);
|
||||
- ret = nbd_negotiate_read(ioc, buffer, count);
|
||||
- if (ret < 0) {
|
||||
- g_free(buffer);
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- size -= count;
|
||||
- }
|
||||
-
|
||||
- g_free(buffer);
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
/* Basic flow for negotiation
|
||||
|
||||
Server Client
|
||||
@@ -205,22 +142,22 @@ static int nbd_negotiate_send_rep_len(QIOChannel *ioc, uint32_t type,
|
||||
type, opt, len);
|
||||
|
||||
magic = cpu_to_be64(NBD_REP_MAGIC);
|
||||
- if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) < 0) {
|
||||
+ if (write_sync(ioc, &magic, sizeof(magic)) < 0) {
|
||||
LOG("write failed (rep magic)");
|
||||
return -EINVAL;
|
||||
}
|
||||
opt = cpu_to_be32(opt);
|
||||
- if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) < 0) {
|
||||
+ if (write_sync(ioc, &opt, sizeof(opt)) < 0) {
|
||||
LOG("write failed (rep opt)");
|
||||
return -EINVAL;
|
||||
}
|
||||
type = cpu_to_be32(type);
|
||||
- if (nbd_negotiate_write(ioc, &type, sizeof(type)) < 0) {
|
||||
+ if (write_sync(ioc, &type, sizeof(type)) < 0) {
|
||||
LOG("write failed (rep type)");
|
||||
return -EINVAL;
|
||||
}
|
||||
len = cpu_to_be32(len);
|
||||
- if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) {
|
||||
+ if (write_sync(ioc, &len, sizeof(len)) < 0) {
|
||||
LOG("write failed (rep data length)");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -255,7 +192,7 @@ nbd_negotiate_send_rep_err(QIOChannel *ioc, uint32_t type,
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
- if (nbd_negotiate_write(ioc, msg, len) < 0) {
|
||||
+ if (write_sync(ioc, msg, len) < 0) {
|
||||
LOG("write failed (error message)");
|
||||
ret = -EIO;
|
||||
} else {
|
||||
@@ -286,15 +223,15 @@ static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp)
|
||||
}
|
||||
|
||||
len = cpu_to_be32(name_len);
|
||||
- if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) {
|
||||
+ if (write_sync(ioc, &len, sizeof(len)) < 0) {
|
||||
LOG("write failed (name length)");
|
||||
return -EINVAL;
|
||||
}
|
||||
- if (nbd_negotiate_write(ioc, name, name_len) < 0) {
|
||||
+ if (write_sync(ioc, name, name_len) < 0) {
|
||||
LOG("write failed (name buffer)");
|
||||
return -EINVAL;
|
||||
}
|
||||
- if (nbd_negotiate_write(ioc, desc, desc_len) < 0) {
|
||||
+ if (write_sync(ioc, desc, desc_len) < 0) {
|
||||
LOG("write failed (description buffer)");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -308,7 +245,7 @@ static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length)
|
||||
NBDExport *exp;
|
||||
|
||||
if (length) {
|
||||
- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
|
||||
+ if (nbd_drop(client->ioc, length) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
return nbd_negotiate_send_rep_err(client->ioc,
|
||||
@@ -339,7 +276,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t length)
|
||||
LOG("Bad length received");
|
||||
goto fail;
|
||||
}
|
||||
- if (nbd_negotiate_read(client->ioc, name, length) < 0) {
|
||||
+ if (read_sync(client->ioc, name, length) < 0) {
|
||||
LOG("read failed");
|
||||
goto fail;
|
||||
}
|
||||
@@ -372,7 +309,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
|
||||
TRACE("Setting up TLS");
|
||||
ioc = client->ioc;
|
||||
if (length) {
|
||||
- if (nbd_negotiate_drop_sync(ioc, length) < 0) {
|
||||
+ if (nbd_drop(ioc, length) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
nbd_negotiate_send_rep_err(ioc, NBD_REP_ERR_INVALID, NBD_OPT_STARTTLS,
|
||||
@@ -436,7 +373,7 @@ static int nbd_negotiate_options(NBDClient *client)
|
||||
... Rest of request
|
||||
*/
|
||||
|
||||
- if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) < 0) {
|
||||
+ if (read_sync(client->ioc, &flags, sizeof(flags)) < 0) {
|
||||
LOG("read failed");
|
||||
return -EIO;
|
||||
}
|
||||
@@ -462,7 +399,7 @@ static int nbd_negotiate_options(NBDClient *client)
|
||||
uint32_t clientflags, length;
|
||||
uint64_t magic;
|
||||
|
||||
- if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) < 0) {
|
||||
+ if (read_sync(client->ioc, &magic, sizeof(magic)) < 0) {
|
||||
LOG("read failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -472,15 +409,14 @@ static int nbd_negotiate_options(NBDClient *client)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- if (nbd_negotiate_read(client->ioc, &clientflags,
|
||||
- sizeof(clientflags)) < 0)
|
||||
+ if (read_sync(client->ioc, &clientflags, sizeof(clientflags)) < 0)
|
||||
{
|
||||
LOG("read failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
clientflags = be32_to_cpu(clientflags);
|
||||
|
||||
- if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) < 0) {
|
||||
+ if (read_sync(client->ioc, &length, sizeof(length)) < 0) {
|
||||
LOG("read failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -516,7 +452,7 @@ static int nbd_negotiate_options(NBDClient *client)
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
|
||||
+ if (nbd_drop(client->ioc, length) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
ret = nbd_negotiate_send_rep_err(client->ioc,
|
||||
@@ -554,7 +490,7 @@ static int nbd_negotiate_options(NBDClient *client)
|
||||
return nbd_negotiate_handle_export_name(client, length);
|
||||
|
||||
case NBD_OPT_STARTTLS:
|
||||
- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
|
||||
+ if (nbd_drop(client->ioc, length) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
if (client->tlscreds) {
|
||||
@@ -573,7 +509,7 @@ static int nbd_negotiate_options(NBDClient *client)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
|
||||
+ if (nbd_drop(client->ioc, length) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
ret = nbd_negotiate_send_rep_err(client->ioc,
|
||||
@@ -662,12 +598,12 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data)
|
||||
TRACE("TLS cannot be enabled with oldstyle protocol");
|
||||
goto fail;
|
||||
}
|
||||
- if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) < 0) {
|
||||
+ if (write_sync(client->ioc, buf, sizeof(buf)) < 0) {
|
||||
LOG("write failed");
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
- if (nbd_negotiate_write(client->ioc, buf, 18) < 0) {
|
||||
+ if (write_sync(client->ioc, buf, 18) < 0) {
|
||||
LOG("write failed");
|
||||
goto fail;
|
||||
}
|
||||
@@ -682,7 +618,7 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data)
|
||||
stq_be_p(buf + 18, client->exp->size);
|
||||
stw_be_p(buf + 26, client->exp->nbdflags | myflags);
|
||||
len = client->no_zeroes ? 10 : sizeof(buf) - 18;
|
||||
- if (nbd_negotiate_write(client->ioc, buf + 18, len) < 0) {
|
||||
+ if (write_sync(client->ioc, buf + 18, len) < 0) {
|
||||
LOG("write failed");
|
||||
goto fail;
|
||||
}
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,153 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Wed, 27 Sep 2017 17:57:19 +0200
|
||||
Subject: [PATCH] nbd-client: Fix regression when server sends garbage
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
Message-id: <20170927175725.20023-2-eblake@redhat.com>
|
||||
Patchwork-id: 76672
|
||||
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 1/7] nbd-client: Fix regression when server sends garbage
|
||||
Bugzilla: 1495474
|
||||
RH-Acked-by: Max Reitz <mreitz@redhat.com>
|
||||
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
|
||||
When we switched NBD to use coroutines for qemu 2.9 (in particular,
|
||||
commit a12a712a), we introduced a regression: if a server sends us
|
||||
garbage (such as a corrupted magic number), we quit the read loop
|
||||
but do not stop sending further queued commands, resulting in the
|
||||
client hanging when it never reads the response to those additional
|
||||
commands. In qemu 2.8, we properly detected that the server is no
|
||||
longer reliable, and cancelled all existing pending commands with
|
||||
EIO, then tore down the socket so that all further command attempts
|
||||
get EPIPE.
|
||||
|
||||
Restore the proper behavior of quitting (almost) all communication
|
||||
with a broken server: Once we know we are out of sync or otherwise
|
||||
can't trust the server, we must assume that any further incoming
|
||||
data is unreliable and therefore end all pending commands with EIO,
|
||||
and quit trying to send any further commands. As an exception, we
|
||||
still (try to) send NBD_CMD_DISC to let the server know we are going
|
||||
away (in part, because it is easier to do that than to further
|
||||
refactor nbd_teardown_connection, and in part because it is the
|
||||
only command where we do not have to wait for a reply).
|
||||
|
||||
Based on a patch by Vladimir Sementsov-Ogievskiy.
|
||||
|
||||
A malicious server can be created with the following hack,
|
||||
followed by setting NBD_SERVER_DEBUG to a non-zero value in the
|
||||
environment when running qemu-nbd:
|
||||
|
||||
| --- a/nbd/server.c
|
||||
| +++ b/nbd/server.c
|
||||
| @@ -919,6 +919,17 @@ static int nbd_send_reply(QIOChannel *ioc, NBDReply *reply, Error **errp)
|
||||
| stl_be_p(buf + 4, reply->error);
|
||||
| stq_be_p(buf + 8, reply->handle);
|
||||
|
|
||||
| + static int debug;
|
||||
| + static int count;
|
||||
| + if (!count++) {
|
||||
| + const char *str = getenv("NBD_SERVER_DEBUG");
|
||||
| + if (str) {
|
||||
| + debug = atoi(str);
|
||||
| + }
|
||||
| + }
|
||||
| + if (debug && !(count % debug)) {
|
||||
| + buf[0] = 0;
|
||||
| + }
|
||||
| return nbd_write(ioc, buf, sizeof(buf), errp);
|
||||
| }
|
||||
|
||||
Reported-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
Message-Id: <20170814213426.24681-1-eblake@redhat.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 72b6ffc76653214b69a94a7b1643ff80df134486)
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
block/nbd-client.c
|
||||
---
|
||||
block/nbd-client.c | 17 +++++++++++++----
|
||||
block/nbd-client.h | 1 +
|
||||
2 files changed, 14 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/block/nbd-client.c b/block/nbd-client.c
|
||||
index 282679b4f8..701b4ce2eb 100644
|
||||
--- a/block/nbd-client.c
|
||||
+++ b/block/nbd-client.c
|
||||
@@ -71,7 +71,7 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque)
|
||||
uint64_t i;
|
||||
int ret;
|
||||
|
||||
- for (;;) {
|
||||
+ while (!s->quit) {
|
||||
assert(s->reply.handle == 0);
|
||||
ret = nbd_receive_reply(s->ioc, &s->reply);
|
||||
if (ret <= 0) {
|
||||
@@ -102,6 +102,9 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque)
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
+ if (ret < 0) {
|
||||
+ s->quit = true;
|
||||
+ }
|
||||
nbd_recv_coroutines_enter_all(s);
|
||||
s->read_reply_co = NULL;
|
||||
}
|
||||
@@ -130,6 +133,10 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
assert(i < MAX_NBD_REQUESTS);
|
||||
request->handle = INDEX_TO_HANDLE(s, i);
|
||||
|
||||
+ if (s->quit) {
|
||||
+ qemu_co_mutex_unlock(&s->send_mutex);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
if (!s->ioc) {
|
||||
qemu_co_mutex_unlock(&s->send_mutex);
|
||||
return -EPIPE;
|
||||
@@ -138,7 +145,7 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
if (qiov) {
|
||||
qio_channel_set_cork(s->ioc, true);
|
||||
rc = nbd_send_request(s->ioc, request);
|
||||
- if (rc >= 0) {
|
||||
+ if (rc >= 0 && !s->quit) {
|
||||
ret = nbd_wr_syncv(s->ioc, qiov->iov, qiov->niov, request->len,
|
||||
false);
|
||||
if (ret != request->len) {
|
||||
@@ -149,6 +156,9 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
} else {
|
||||
rc = nbd_send_request(s->ioc, request);
|
||||
}
|
||||
+ if (rc < 0) {
|
||||
+ s->quit = true;
|
||||
+ }
|
||||
qemu_co_mutex_unlock(&s->send_mutex);
|
||||
return rc;
|
||||
}
|
||||
@@ -163,8 +173,7 @@ static void nbd_co_receive_reply(NBDClientSession *s,
|
||||
/* Wait until we're woken up by nbd_read_reply_entry. */
|
||||
qemu_coroutine_yield();
|
||||
*reply = s->reply;
|
||||
- if (reply->handle != request->handle ||
|
||||
- !s->ioc) {
|
||||
+ if (reply->handle != request->handle || !s->ioc || s->quit) {
|
||||
reply->error = EIO;
|
||||
} else {
|
||||
if (qiov && reply->error == 0) {
|
||||
diff --git a/block/nbd-client.h b/block/nbd-client.h
|
||||
index 891ba44a20..9774a8ebbb 100644
|
||||
--- a/block/nbd-client.h
|
||||
+++ b/block/nbd-client.h
|
||||
@@ -30,6 +30,7 @@ typedef struct NBDClientSession {
|
||||
|
||||
Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
|
||||
NBDReply reply;
|
||||
+ bool quit;
|
||||
} NBDClientSession;
|
||||
|
||||
NBDClientSession *nbd_get_client_session(BlockDriverState *bs);
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,55 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Wed, 27 Sep 2017 17:57:20 +0200
|
||||
Subject: [PATCH] fix build failure in nbd_read_reply_entry()
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
Message-id: <20170927175725.20023-3-eblake@redhat.com>
|
||||
Patchwork-id: 76668
|
||||
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 2/7] fix build failure in nbd_read_reply_entry()
|
||||
Bugzilla: 1495474
|
||||
RH-Acked-by: Max Reitz <mreitz@redhat.com>
|
||||
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
|
||||
From: Igor Mammedov <imammedo@redhat.com>
|
||||
|
||||
travis builds fail at HEAD at rc3 master with
|
||||
|
||||
block/nbd-client.c: In function ‘nbd_read_reply_entry’:
|
||||
block/nbd-client.c:110:8: error: ‘ret’ may be used uninitialized in this function [-Werror=uninitialized]
|
||||
|
||||
fix it by initializing 'ret' to 0
|
||||
|
||||
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit d0a180131c6655487b47ea72e7da0a909a479a3c)
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
block/nbd-client.c - context
|
||||
---
|
||||
block/nbd-client.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/block/nbd-client.c b/block/nbd-client.c
|
||||
index 701b4ce2eb..256dabeeef 100644
|
||||
--- a/block/nbd-client.c
|
||||
+++ b/block/nbd-client.c
|
||||
@@ -69,7 +69,7 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque)
|
||||
{
|
||||
NBDClientSession *s = opaque;
|
||||
uint64_t i;
|
||||
- int ret;
|
||||
+ int ret = 0;
|
||||
|
||||
while (!s->quit) {
|
||||
assert(s->reply.handle == 0);
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,184 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Wed, 27 Sep 2017 17:57:21 +0200
|
||||
Subject: [PATCH] nbd-client: avoid spurious qio_channel_yield() re-entry
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
Message-id: <20170927175725.20023-4-eblake@redhat.com>
|
||||
Patchwork-id: 76671
|
||||
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 3/7] nbd-client: avoid spurious qio_channel_yield() re-entry
|
||||
Bugzilla: 1495474
|
||||
RH-Acked-by: Max Reitz <mreitz@redhat.com>
|
||||
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
|
||||
The following scenario leads to an assertion failure in
|
||||
qio_channel_yield():
|
||||
|
||||
1. Request coroutine calls qio_channel_yield() successfully when sending
|
||||
would block on the socket. It is now yielded.
|
||||
2. nbd_read_reply_entry() calls nbd_recv_coroutines_enter_all() because
|
||||
nbd_receive_reply() failed.
|
||||
3. Request coroutine is entered and returns from qio_channel_yield().
|
||||
Note that the socket fd handler has not fired yet so
|
||||
ioc->write_coroutine is still set.
|
||||
4. Request coroutine attempts to send the request body with nbd_rwv()
|
||||
but the socket would still block. qio_channel_yield() is called
|
||||
again and assert(!ioc->write_coroutine) is hit.
|
||||
|
||||
The problem is that nbd_read_reply_entry() does not distinguish between
|
||||
request coroutines that are waiting to receive a reply and those that
|
||||
are not.
|
||||
|
||||
This patch adds a per-request bool receiving flag so
|
||||
nbd_read_reply_entry() can avoid spurious aio_wake() calls.
|
||||
|
||||
Reported-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Message-Id: <20170822125113.5025-1-stefanha@redhat.com>
|
||||
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||||
Tested-by: Eric Blake <eblake@redhat.com>
|
||||
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
(cherry picked from commit 40f4a21895b5a7eae4011593837069f63460d983)
|
||||
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
---
|
||||
block/nbd-client.c | 35 ++++++++++++++++++++++-------------
|
||||
block/nbd-client.h | 7 ++++++-
|
||||
2 files changed, 28 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/block/nbd-client.c b/block/nbd-client.c
|
||||
index 256dabeeef..f7bca3f996 100644
|
||||
--- a/block/nbd-client.c
|
||||
+++ b/block/nbd-client.c
|
||||
@@ -38,8 +38,10 @@ static void nbd_recv_coroutines_enter_all(NBDClientSession *s)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_NBD_REQUESTS; i++) {
|
||||
- if (s->recv_coroutine[i]) {
|
||||
- aio_co_wake(s->recv_coroutine[i]);
|
||||
+ NBDClientRequest *req = &s->requests[i];
|
||||
+
|
||||
+ if (req->coroutine && req->receiving) {
|
||||
+ aio_co_wake(req->coroutine);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,28 +85,28 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque)
|
||||
* one coroutine is called until the reply finishes.
|
||||
*/
|
||||
i = HANDLE_TO_INDEX(s, s->reply.handle);
|
||||
- if (i >= MAX_NBD_REQUESTS || !s->recv_coroutine[i]) {
|
||||
+ if (i >= MAX_NBD_REQUESTS ||
|
||||
+ !s->requests[i].coroutine ||
|
||||
+ !s->requests[i].receiving) {
|
||||
break;
|
||||
}
|
||||
|
||||
- /* We're woken up by the recv_coroutine itself. Note that there
|
||||
+ /* We're woken up again by the request itself. Note that there
|
||||
* is no race between yielding and reentering read_reply_co. This
|
||||
* is because:
|
||||
*
|
||||
- * - if recv_coroutine[i] runs on the same AioContext, it is only
|
||||
+ * - if the request runs on the same AioContext, it is only
|
||||
* entered after we yield
|
||||
*
|
||||
- * - if recv_coroutine[i] runs on a different AioContext, reentering
|
||||
+ * - if the request runs on a different AioContext, reentering
|
||||
* read_reply_co happens through a bottom half, which can only
|
||||
* run after we yield.
|
||||
*/
|
||||
- aio_co_wake(s->recv_coroutine[i]);
|
||||
+ aio_co_wake(s->requests[i].coroutine);
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
- if (ret < 0) {
|
||||
- s->quit = true;
|
||||
- }
|
||||
+ s->quit = true;
|
||||
nbd_recv_coroutines_enter_all(s);
|
||||
s->read_reply_co = NULL;
|
||||
}
|
||||
@@ -123,14 +125,17 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
s->in_flight++;
|
||||
|
||||
for (i = 0; i < MAX_NBD_REQUESTS; i++) {
|
||||
- if (s->recv_coroutine[i] == NULL) {
|
||||
- s->recv_coroutine[i] = qemu_coroutine_self();
|
||||
+ if (s->requests[i].coroutine == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert(qemu_in_coroutine());
|
||||
assert(i < MAX_NBD_REQUESTS);
|
||||
+
|
||||
+ s->requests[i].coroutine = qemu_coroutine_self();
|
||||
+ s->requests[i].receiving = false;
|
||||
+
|
||||
request->handle = INDEX_TO_HANDLE(s, i);
|
||||
|
||||
if (s->quit) {
|
||||
@@ -168,10 +173,13 @@ static void nbd_co_receive_reply(NBDClientSession *s,
|
||||
NBDReply *reply,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
+ int i = HANDLE_TO_INDEX(s, request->handle);
|
||||
int ret;
|
||||
|
||||
/* Wait until we're woken up by nbd_read_reply_entry. */
|
||||
+ s->requests[i].receiving = true;
|
||||
qemu_coroutine_yield();
|
||||
+ s->requests[i].receiving = false;
|
||||
*reply = s->reply;
|
||||
if (reply->handle != request->handle || !s->ioc || s->quit) {
|
||||
reply->error = EIO;
|
||||
@@ -181,6 +189,7 @@ static void nbd_co_receive_reply(NBDClientSession *s,
|
||||
true);
|
||||
if (ret != request->len) {
|
||||
reply->error = EIO;
|
||||
+ s->quit = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +204,7 @@ static void nbd_coroutine_end(BlockDriverState *bs,
|
||||
NBDClientSession *s = nbd_get_client_session(bs);
|
||||
int i = HANDLE_TO_INDEX(s, request->handle);
|
||||
|
||||
- s->recv_coroutine[i] = NULL;
|
||||
+ s->requests[i].coroutine = NULL;
|
||||
|
||||
/* Kick the read_reply_co to get the next reply. */
|
||||
if (s->read_reply_co) {
|
||||
diff --git a/block/nbd-client.h b/block/nbd-client.h
|
||||
index 9774a8ebbb..f97792ff49 100644
|
||||
--- a/block/nbd-client.h
|
||||
+++ b/block/nbd-client.h
|
||||
@@ -17,6 +17,11 @@
|
||||
|
||||
#define MAX_NBD_REQUESTS 16
|
||||
|
||||
+typedef struct {
|
||||
+ Coroutine *coroutine;
|
||||
+ bool receiving; /* waiting for read_reply_co? */
|
||||
+} NBDClientRequest;
|
||||
+
|
||||
typedef struct NBDClientSession {
|
||||
QIOChannelSocket *sioc; /* The master data channel */
|
||||
QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
|
||||
@@ -28,7 +33,7 @@ typedef struct NBDClientSession {
|
||||
Coroutine *read_reply_co;
|
||||
int in_flight;
|
||||
|
||||
- Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
|
||||
+ NBDClientRequest requests[MAX_NBD_REQUESTS];
|
||||
NBDReply reply;
|
||||
bool quit;
|
||||
} NBDClientSession;
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,160 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Wed, 27 Sep 2017 17:57:22 +0200
|
||||
Subject: [PATCH] nbd-client: avoid read_reply_co entry if send failed
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
Message-id: <20170927175725.20023-5-eblake@redhat.com>
|
||||
Patchwork-id: 76674
|
||||
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 4/7] nbd-client: avoid read_reply_co entry if send failed
|
||||
Bugzilla: 1495474
|
||||
RH-Acked-by: Max Reitz <mreitz@redhat.com>
|
||||
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
|
||||
The following segfault is encountered if the NBD server closes the UNIX
|
||||
domain socket immediately after negotiation:
|
||||
|
||||
Program terminated with signal SIGSEGV, Segmentation fault.
|
||||
#0 aio_co_schedule (ctx=0x0, co=0xd3c0ff2ef0) at util/async.c:441
|
||||
441 QSLIST_INSERT_HEAD_ATOMIC(&ctx->scheduled_coroutines,
|
||||
(gdb) bt
|
||||
#0 0x000000d3c01a50f8 in aio_co_schedule (ctx=0x0, co=0xd3c0ff2ef0) at util/async.c:441
|
||||
#1 0x000000d3c012fa90 in nbd_coroutine_end (bs=bs@entry=0xd3c0fec650, request=<optimized out>) at block/nbd-client.c:207
|
||||
#2 0x000000d3c012fb58 in nbd_client_co_preadv (bs=0xd3c0fec650, offset=0, bytes=<optimized out>, qiov=0x7ffc10a91b20, flags=0) at block/nbd-client.c:237
|
||||
#3 0x000000d3c0128e63 in bdrv_driver_preadv (bs=bs@entry=0xd3c0fec650, offset=offset@entry=0, bytes=bytes@entry=512, qiov=qiov@entry=0x7ffc10a91b20, flags=0) at block/io.c:836
|
||||
#4 0x000000d3c012c3e0 in bdrv_aligned_preadv (child=child@entry=0xd3c0ff51d0, req=req@entry=0x7f31885d6e90, offset=offset@entry=0, bytes=bytes@entry=512, align=align@entry=1, qiov=qiov@entry=0x7ffc10a91b20, f
|
||||
+lags=0) at block/io.c:1086
|
||||
#5 0x000000d3c012c6b8 in bdrv_co_preadv (child=0xd3c0ff51d0, offset=offset@entry=0, bytes=bytes@entry=512, qiov=qiov@entry=0x7ffc10a91b20, flags=flags@entry=0) at block/io.c:1182
|
||||
#6 0x000000d3c011cc17 in blk_co_preadv (blk=0xd3c0ff4f80, offset=0, bytes=512, qiov=0x7ffc10a91b20, flags=0) at block/block-backend.c:1032
|
||||
#7 0x000000d3c011ccec in blk_read_entry (opaque=0x7ffc10a91b40) at block/block-backend.c:1079
|
||||
#8 0x000000d3c01bbb96 in coroutine_trampoline (i0=<optimized out>, i1=<optimized out>) at util/coroutine-ucontext.c:79
|
||||
#9 0x00007f3196cb8600 in __start_context () at /lib64/libc.so.6
|
||||
|
||||
The problem is that nbd_client_init() uses
|
||||
nbd_client_attach_aio_context() -> aio_co_schedule(new_context,
|
||||
client->read_reply_co). Execution of read_reply_co is deferred to a BH
|
||||
which doesn't run until later.
|
||||
|
||||
In the mean time blk_co_preadv() can be called and nbd_coroutine_end()
|
||||
calls aio_wake() on read_reply_co. At this point in time
|
||||
read_reply_co's ctx isn't set because it has never been entered yet.
|
||||
|
||||
This patch simplifies the nbd_co_send_request() ->
|
||||
nbd_co_receive_reply() -> nbd_coroutine_end() lifecycle to just
|
||||
nbd_co_send_request() -> nbd_co_receive_reply(). The request is "ended"
|
||||
if an error occurs at any point. Callers no longer have to invoke
|
||||
nbd_coroutine_end().
|
||||
|
||||
This cleanup also eliminates the segfault because we don't call
|
||||
aio_co_schedule() to wake up s->read_reply_co if sending the request
|
||||
failed. It is only necessary to wake up s->read_reply_co if a reply was
|
||||
received.
|
||||
|
||||
Note this only happens with UNIX domain sockets on Linux. It doesn't
|
||||
seem possible to reproduce this with TCP sockets.
|
||||
|
||||
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Message-Id: <20170829122745.14309-2-stefanha@redhat.com>
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
(cherry picked from commit 3c2d5183f9fa4eac3d17d841e26da65a0181ae7b)
|
||||
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
---
|
||||
block/nbd-client.c | 25 +++++++++----------------
|
||||
1 file changed, 9 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/block/nbd-client.c b/block/nbd-client.c
|
||||
index f7bca3f996..434acf647f 100644
|
||||
--- a/block/nbd-client.c
|
||||
+++ b/block/nbd-client.c
|
||||
@@ -139,12 +139,12 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
request->handle = INDEX_TO_HANDLE(s, i);
|
||||
|
||||
if (s->quit) {
|
||||
- qemu_co_mutex_unlock(&s->send_mutex);
|
||||
- return -EIO;
|
||||
+ rc = -EIO;
|
||||
+ goto err;
|
||||
}
|
||||
if (!s->ioc) {
|
||||
- qemu_co_mutex_unlock(&s->send_mutex);
|
||||
- return -EPIPE;
|
||||
+ rc = -EPIPE;
|
||||
+ goto err;
|
||||
}
|
||||
|
||||
if (qiov) {
|
||||
@@ -161,8 +161,13 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
} else {
|
||||
rc = nbd_send_request(s->ioc, request);
|
||||
}
|
||||
+
|
||||
+err:
|
||||
if (rc < 0) {
|
||||
s->quit = true;
|
||||
+ s->requests[i].coroutine = NULL;
|
||||
+ s->in_flight--;
|
||||
+ qemu_co_queue_next(&s->free_sema);
|
||||
}
|
||||
qemu_co_mutex_unlock(&s->send_mutex);
|
||||
return rc;
|
||||
@@ -196,13 +201,6 @@ static void nbd_co_receive_reply(NBDClientSession *s,
|
||||
/* Tell the read handler to read another header. */
|
||||
s->reply.handle = 0;
|
||||
}
|
||||
-}
|
||||
-
|
||||
-static void nbd_coroutine_end(BlockDriverState *bs,
|
||||
- NBDRequest *request)
|
||||
-{
|
||||
- NBDClientSession *s = nbd_get_client_session(bs);
|
||||
- int i = HANDLE_TO_INDEX(s, request->handle);
|
||||
|
||||
s->requests[i].coroutine = NULL;
|
||||
|
||||
@@ -238,7 +236,6 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
} else {
|
||||
nbd_co_receive_reply(client, &request, &reply, qiov);
|
||||
}
|
||||
- nbd_coroutine_end(bs, &request);
|
||||
return -reply.error;
|
||||
}
|
||||
|
||||
@@ -267,7 +264,6 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
} else {
|
||||
nbd_co_receive_reply(client, &request, &reply, NULL);
|
||||
}
|
||||
- nbd_coroutine_end(bs, &request);
|
||||
return -reply.error;
|
||||
}
|
||||
|
||||
@@ -301,7 +297,6 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
||||
} else {
|
||||
nbd_co_receive_reply(client, &request, &reply, NULL);
|
||||
}
|
||||
- nbd_coroutine_end(bs, &request);
|
||||
return -reply.error;
|
||||
}
|
||||
|
||||
@@ -325,7 +320,6 @@ int nbd_client_co_flush(BlockDriverState *bs)
|
||||
} else {
|
||||
nbd_co_receive_reply(client, &request, &reply, NULL);
|
||||
}
|
||||
- nbd_coroutine_end(bs, &request);
|
||||
return -reply.error;
|
||||
}
|
||||
|
||||
@@ -350,7 +344,6 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
|
||||
} else {
|
||||
nbd_co_receive_reply(client, &request, &reply, NULL);
|
||||
}
|
||||
- nbd_coroutine_end(bs, &request);
|
||||
return -reply.error;
|
||||
|
||||
}
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,60 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Wed, 27 Sep 2017 17:57:23 +0200
|
||||
Subject: [PATCH] qemu-iotests: improve nbd-fault-injector.py startup protocol
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
Message-id: <20170927175725.20023-6-eblake@redhat.com>
|
||||
Patchwork-id: 76675
|
||||
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 5/7] qemu-iotests: improve nbd-fault-injector.py startup protocol
|
||||
Bugzilla: 1495474
|
||||
RH-Acked-by: Max Reitz <mreitz@redhat.com>
|
||||
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
|
||||
Currently 083 waits for the nbd-fault-injector.py server to start up by
|
||||
looping until netstat shows the TCP listen socket.
|
||||
|
||||
The startup protocol can be simplified by passing a 0 port number to
|
||||
nbd-fault-injector.py. The kernel will allocate a port in bind(2) and
|
||||
the final port number can be printed by nbd-fault-injector.py.
|
||||
|
||||
This should make it slightly nicer and less TCP-specific to wait for
|
||||
server startup. This patch changes nbd-fault-injector.py, the next one
|
||||
will rewrite server startup in 083.
|
||||
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Message-Id: <20170829122745.14309-3-stefanha@redhat.com>
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
(cherry picked from commit 6e592fc92234a58c7156c385840633c17dedd24f)
|
||||
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
---
|
||||
tests/qemu-iotests/nbd-fault-injector.py | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/tests/qemu-iotests/nbd-fault-injector.py b/tests/qemu-iotests/nbd-fault-injector.py
|
||||
index 6c07191a5a..1c10dcb51c 100755
|
||||
--- a/tests/qemu-iotests/nbd-fault-injector.py
|
||||
+++ b/tests/qemu-iotests/nbd-fault-injector.py
|
||||
@@ -235,11 +235,15 @@ def open_socket(path):
|
||||
sock = socket.socket()
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sock.bind((host, int(port)))
|
||||
+
|
||||
+ # If given port was 0 the final port number is now available
|
||||
+ path = '%s:%d' % sock.getsockname()
|
||||
else:
|
||||
sock = socket.socket(socket.AF_UNIX)
|
||||
sock.bind(path)
|
||||
sock.listen(0)
|
||||
print 'Listening on %s' % path
|
||||
+ sys.stdout.flush() # another process may be waiting, show message now
|
||||
return sock
|
||||
|
||||
def usage(args):
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,454 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Wed, 27 Sep 2017 17:57:24 +0200
|
||||
Subject: [PATCH] qemu-iotests: test NBD over UNIX domain sockets in 083
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
Message-id: <20170927175725.20023-7-eblake@redhat.com>
|
||||
Patchwork-id: 76670
|
||||
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 6/7] qemu-iotests: test NBD over UNIX domain sockets in 083
|
||||
Bugzilla: 1495474
|
||||
RH-Acked-by: Max Reitz <mreitz@redhat.com>
|
||||
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
|
||||
083 only tests TCP. Some failures might be specific to UNIX domain
|
||||
sockets.
|
||||
|
||||
A few adjustments are necessary:
|
||||
|
||||
1. Generating a port number and waiting for server startup is
|
||||
TCP-specific. Use the new nbd-fault-injector.py startup protocol to
|
||||
fetch the address. This is a little more elegant because we don't
|
||||
need netstat anymore.
|
||||
|
||||
2. The NBD filter does not work for the UNIX domain sockets URIs we
|
||||
generate and must be extended.
|
||||
|
||||
3. Run all tests twice: once for TCP and once for UNIX domain sockets.
|
||||
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Message-Id: <20170829122745.14309-4-stefanha@redhat.com>
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
(cherry picked from commit 02d2d860d25e439f0e88658c701668ab684568fb)
|
||||
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/083.out - error message improvements not backported
|
||||
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
---
|
||||
tests/qemu-iotests/083 | 136 +++++++++++++++++++++++--------------
|
||||
tests/qemu-iotests/083.out | 143 ++++++++++++++++++++++++++++++++++-----
|
||||
tests/qemu-iotests/common.filter | 4 +-
|
||||
3 files changed, 212 insertions(+), 71 deletions(-)
|
||||
|
||||
diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083
|
||||
index bff9360048..0306f112da 100755
|
||||
--- a/tests/qemu-iotests/083
|
||||
+++ b/tests/qemu-iotests/083
|
||||
@@ -27,6 +27,14 @@ echo "QA output created by $seq"
|
||||
here=`pwd`
|
||||
status=1 # failure is the default!
|
||||
|
||||
+_cleanup()
|
||||
+{
|
||||
+ rm -f nbd.sock
|
||||
+ rm -f nbd-fault-injector.out
|
||||
+ rm -f nbd-fault-injector.conf
|
||||
+}
|
||||
+trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
+
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
@@ -35,81 +43,105 @@ _supported_fmt generic
|
||||
_supported_proto nbd
|
||||
_supported_os Linux
|
||||
|
||||
-# Pick a TCP port based on our pid. This way multiple instances of this test
|
||||
-# can run in parallel without conflicting.
|
||||
-choose_tcp_port() {
|
||||
- echo $((($$ % 31744) + 1024)) # 1024 <= port < 32768
|
||||
-}
|
||||
-
|
||||
-wait_for_tcp_port() {
|
||||
- while ! (netstat --tcp --listening --numeric | \
|
||||
- grep "$1.*0\\.0\\.0\\.0:\\*.*LISTEN") >/dev/null 2>&1; do
|
||||
- sleep 0.1
|
||||
+check_disconnect() {
|
||||
+ local event export_name=foo extra_args nbd_addr nbd_url proto when
|
||||
+
|
||||
+ while true; do
|
||||
+ case $1 in
|
||||
+ --classic-negotiation)
|
||||
+ shift
|
||||
+ extra_args=--classic-negotiation
|
||||
+ export_name=
|
||||
+ ;;
|
||||
+ --tcp)
|
||||
+ shift
|
||||
+ proto=tcp
|
||||
+ ;;
|
||||
+ --unix)
|
||||
+ shift
|
||||
+ proto=unix
|
||||
+ ;;
|
||||
+ *)
|
||||
+ break
|
||||
+ ;;
|
||||
+ esac
|
||||
done
|
||||
-}
|
||||
|
||||
-check_disconnect() {
|
||||
event=$1
|
||||
when=$2
|
||||
- negotiation=$3
|
||||
echo "=== Check disconnect $when $event ==="
|
||||
echo
|
||||
|
||||
- port=$(choose_tcp_port)
|
||||
-
|
||||
cat > "$TEST_DIR/nbd-fault-injector.conf" <<EOF
|
||||
[inject-error]
|
||||
event=$event
|
||||
when=$when
|
||||
EOF
|
||||
|
||||
- if [ "$negotiation" = "--classic-negotiation" ]; then
|
||||
- extra_args=--classic-negotiation
|
||||
- nbd_url="nbd:127.0.0.1:$port"
|
||||
+ if [ "$proto" = "tcp" ]; then
|
||||
+ nbd_addr="127.0.0.1:0"
|
||||
else
|
||||
- nbd_url="nbd:127.0.0.1:$port:exportname=foo"
|
||||
+ nbd_addr="$TEST_DIR/nbd.sock"
|
||||
+ fi
|
||||
+
|
||||
+ rm -f "$TEST_DIR/nbd.sock"
|
||||
+
|
||||
+ $PYTHON nbd-fault-injector.py $extra_args "$nbd_addr" "$TEST_DIR/nbd-fault-injector.conf" >"$TEST_DIR/nbd-fault-injector.out" 2>&1 &
|
||||
+
|
||||
+ # Wait for server to be ready
|
||||
+ while ! grep -q 'Listening on ' "$TEST_DIR/nbd-fault-injector.out"; do
|
||||
+ sleep 0.1
|
||||
+ done
|
||||
+
|
||||
+ # Extract the final address (port number has now been assigned in tcp case)
|
||||
+ nbd_addr=$(sed 's/Listening on \(.*\)$/\1/' "$TEST_DIR/nbd-fault-injector.out")
|
||||
+
|
||||
+ if [ "$proto" = "tcp" ]; then
|
||||
+ nbd_url="nbd+tcp://$nbd_addr/$export_name"
|
||||
+ else
|
||||
+ nbd_url="nbd+unix:///$export_name?socket=$nbd_addr"
|
||||
fi
|
||||
|
||||
- $PYTHON nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" >/dev/null 2>&1 &
|
||||
- wait_for_tcp_port "127\\.0\\.0\\.1:$port"
|
||||
$QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | _filter_nbd
|
||||
|
||||
echo
|
||||
}
|
||||
|
||||
-for event in neg1 "export" neg2 request reply data; do
|
||||
- for when in before after; do
|
||||
- check_disconnect "$event" "$when"
|
||||
- done
|
||||
-
|
||||
- # Also inject short replies from the NBD server
|
||||
- case "$event" in
|
||||
- neg1)
|
||||
- for when in 8 16; do
|
||||
- check_disconnect "$event" "$when"
|
||||
- done
|
||||
- ;;
|
||||
- "export")
|
||||
- for when in 4 12 16; do
|
||||
- check_disconnect "$event" "$when"
|
||||
+for proto in tcp unix; do
|
||||
+ for event in neg1 "export" neg2 request reply data; do
|
||||
+ for when in before after; do
|
||||
+ check_disconnect "--$proto" "$event" "$when"
|
||||
done
|
||||
- ;;
|
||||
- neg2)
|
||||
- for when in 8 10; do
|
||||
- check_disconnect "$event" "$when"
|
||||
- done
|
||||
- ;;
|
||||
- reply)
|
||||
- for when in 4 8; do
|
||||
- check_disconnect "$event" "$when"
|
||||
- done
|
||||
- ;;
|
||||
- esac
|
||||
-done
|
||||
|
||||
-# Also check classic negotiation without export information
|
||||
-for when in before 8 16 24 28 after; do
|
||||
- check_disconnect "neg-classic" "$when" --classic-negotiation
|
||||
+ # Also inject short replies from the NBD server
|
||||
+ case "$event" in
|
||||
+ neg1)
|
||||
+ for when in 8 16; do
|
||||
+ check_disconnect "--$proto" "$event" "$when"
|
||||
+ done
|
||||
+ ;;
|
||||
+ "export")
|
||||
+ for when in 4 12 16; do
|
||||
+ check_disconnect "--$proto" "$event" "$when"
|
||||
+ done
|
||||
+ ;;
|
||||
+ neg2)
|
||||
+ for when in 8 10; do
|
||||
+ check_disconnect "--$proto" "$event" "$when"
|
||||
+ done
|
||||
+ ;;
|
||||
+ reply)
|
||||
+ for when in 4 8; do
|
||||
+ check_disconnect "--$proto" "$event" "$when"
|
||||
+ done
|
||||
+ ;;
|
||||
+ esac
|
||||
+ done
|
||||
+
|
||||
+ # Also check classic negotiation without export information
|
||||
+ for when in before 8 16 24 28 after; do
|
||||
+ check_disconnect "--$proto" --classic-negotiation "neg-classic" "$when"
|
||||
+ done
|
||||
done
|
||||
|
||||
# success, all done
|
||||
diff --git a/tests/qemu-iotests/083.out b/tests/qemu-iotests/083.out
|
||||
index 0c13888ba1..7419722cd7 100644
|
||||
--- a/tests/qemu-iotests/083.out
|
||||
+++ b/tests/qemu-iotests/083.out
|
||||
@@ -1,43 +1,43 @@
|
||||
QA output created by 083
|
||||
=== Check disconnect before neg1 ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/foo
|
||||
|
||||
=== Check disconnect after neg1 ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/foo
|
||||
|
||||
=== Check disconnect 8 neg1 ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/foo
|
||||
|
||||
=== Check disconnect 16 neg1 ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/foo
|
||||
|
||||
=== Check disconnect before export ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/foo
|
||||
|
||||
=== Check disconnect after export ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/foo
|
||||
|
||||
=== Check disconnect 4 export ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/foo
|
||||
|
||||
=== Check disconnect 12 export ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/foo
|
||||
|
||||
=== Check disconnect 16 export ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/foo
|
||||
|
||||
=== Check disconnect before neg2 ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/foo
|
||||
|
||||
=== Check disconnect after neg2 ===
|
||||
|
||||
@@ -45,11 +45,11 @@ read failed: Input/output error
|
||||
|
||||
=== Check disconnect 8 neg2 ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/foo
|
||||
|
||||
=== Check disconnect 10 neg2 ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/foo
|
||||
|
||||
=== Check disconnect before request ===
|
||||
|
||||
@@ -86,23 +86,132 @@ read 512/512 bytes at offset 0
|
||||
|
||||
=== Check disconnect before neg-classic ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/
|
||||
|
||||
=== Check disconnect 8 neg-classic ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/
|
||||
|
||||
=== Check disconnect 16 neg-classic ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/
|
||||
|
||||
=== Check disconnect 24 neg-classic ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/
|
||||
|
||||
=== Check disconnect 28 neg-classic ===
|
||||
|
||||
-can't open device nbd:127.0.0.1:PORT
|
||||
+can't open device nbd+tcp://127.0.0.1:PORT/
|
||||
+
|
||||
+=== Check disconnect after neg-classic ===
|
||||
+
|
||||
+read failed: Input/output error
|
||||
+
|
||||
+=== Check disconnect before neg1 ===
|
||||
+
|
||||
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect after neg1 ===
|
||||
+
|
||||
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect 8 neg1 ===
|
||||
+
|
||||
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect 16 neg1 ===
|
||||
+
|
||||
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect before export ===
|
||||
+
|
||||
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect after export ===
|
||||
+
|
||||
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect 4 export ===
|
||||
+
|
||||
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect 12 export ===
|
||||
+
|
||||
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect 16 export ===
|
||||
+
|
||||
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect before neg2 ===
|
||||
+
|
||||
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect after neg2 ===
|
||||
+
|
||||
+read failed: Input/output error
|
||||
+
|
||||
+=== Check disconnect 8 neg2 ===
|
||||
+
|
||||
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect 10 neg2 ===
|
||||
+
|
||||
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect before request ===
|
||||
+
|
||||
+read failed: Input/output error
|
||||
+
|
||||
+=== Check disconnect after request ===
|
||||
+
|
||||
+read failed: Input/output error
|
||||
+
|
||||
+=== Check disconnect before reply ===
|
||||
+
|
||||
+read failed: Input/output error
|
||||
+
|
||||
+=== Check disconnect after reply ===
|
||||
+
|
||||
+read failed: Input/output error
|
||||
+
|
||||
+=== Check disconnect 4 reply ===
|
||||
+
|
||||
+read failed: Input/output error
|
||||
+
|
||||
+=== Check disconnect 8 reply ===
|
||||
+
|
||||
+read failed: Input/output error
|
||||
+
|
||||
+=== Check disconnect before data ===
|
||||
+
|
||||
+read failed: Input/output error
|
||||
+
|
||||
+=== Check disconnect after data ===
|
||||
+
|
||||
+read 512/512 bytes at offset 0
|
||||
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
+
|
||||
+=== Check disconnect before neg-classic ===
|
||||
+
|
||||
+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect 8 neg-classic ===
|
||||
+
|
||||
+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect 16 neg-classic ===
|
||||
+
|
||||
+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect 24 neg-classic ===
|
||||
+
|
||||
+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
|
||||
+
|
||||
+=== Check disconnect 28 neg-classic ===
|
||||
+
|
||||
+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
|
||||
|
||||
=== Check disconnect after neg-classic ===
|
||||
|
||||
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
|
||||
index 104001358b..65ec315f25 100644
|
||||
--- a/tests/qemu-iotests/common.filter
|
||||
+++ b/tests/qemu-iotests/common.filter
|
||||
@@ -153,9 +153,9 @@ _filter_nbd()
|
||||
#
|
||||
# Filter out the TCP port number since this changes between runs.
|
||||
sed -e '/nbd\/.*\.c:/d' \
|
||||
- -e 's#nbd:\(//\)\?127\.0\.0\.1:[0-9]*#nbd:\1127.0.0.1:PORT#g' \
|
||||
+ -e 's#127\.0\.0\.1:[0-9]*#127.0.0.1:PORT#g' \
|
||||
-e "s#?socket=$TEST_DIR#?socket=TEST_DIR#g" \
|
||||
- -e 's#\(exportname=foo\|PORT\): Failed to .*$#\1#'
|
||||
+ -e 's#\(foo\|PORT/\?\|.sock\): Failed to .*$#\1#'
|
||||
}
|
||||
|
||||
# make sure this script returns success
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,45 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Wed, 27 Sep 2017 17:57:25 +0200
|
||||
Subject: [PATCH] block/nbd-client: nbd_co_send_request: fix return code
|
||||
|
||||
RH-Author: Eric Blake <eblake@redhat.com>
|
||||
Message-id: <20170927175725.20023-8-eblake@redhat.com>
|
||||
Patchwork-id: 76673
|
||||
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 7/7] block/nbd-client: nbd_co_send_request: fix return code
|
||||
Bugzilla: 1495474
|
||||
RH-Acked-by: Max Reitz <mreitz@redhat.com>
|
||||
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
|
||||
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||||
|
||||
It's incorrect to return success rc >= 0 if we skip qio_channel_writev_all()
|
||||
call due to s->quit.
|
||||
|
||||
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Message-Id: <20170920124507.18841-4-vsementsov@virtuozzo.com>
|
||||
Signed-off-by: Eric Blake <eblake@redhat.com>
|
||||
(cherry picked from commit a693437037328a95d815ad5aec37ac2f8e130e58)
|
||||
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
---
|
||||
block/nbd-client.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/block/nbd-client.c b/block/nbd-client.c
|
||||
index 434acf647f..76789c1829 100644
|
||||
--- a/block/nbd-client.c
|
||||
+++ b/block/nbd-client.c
|
||||
@@ -156,6 +156,8 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
if (ret != request->len) {
|
||||
rc = -EIO;
|
||||
}
|
||||
+ } else if (rc >= 0) {
|
||||
+ rc = -EIO;
|
||||
}
|
||||
qio_channel_set_cork(s->ioc, false);
|
||||
} else {
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,86 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Brijesh Singh <brijesh.singh@amd.com>
|
||||
Date: Tue, 15 Aug 2017 12:00:51 -0500
|
||||
Subject: [PATCH] target-i386/cpu: Add new EPYC CPU model
|
||||
|
||||
Add a new base CPU model called 'EPYC' to model processors from AMD EPYC
|
||||
family (which includes EPYC 76xx,75xx,74xx, 73xx and 72xx).
|
||||
|
||||
The following features bits have been added/removed compare to Opteron_G5
|
||||
|
||||
Added: monitor, movbe, rdrand, mmxext, ffxsr, rdtscp, cr8legacy, osvw,
|
||||
fsgsbase, bmi1, avx2, smep, bmi2, rdseed, adx, smap, clfshopt, sha
|
||||
xsaveopt, xsavec, xgetbv1, arat
|
||||
|
||||
Removed: xop, fma4, tbm
|
||||
|
||||
Cc: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Cc: Richard Henderson <rth@twiddle.net>
|
||||
Cc: Eduardo Habkost <ehabkost@redhat.com>
|
||||
Cc: Tom Lendacky <Thomas.Lendacky@amd.com>
|
||||
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
|
||||
Message-Id: <20170815170051.127257-1-brijesh.singh@amd.com>
|
||||
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
---
|
||||
target/i386/cpu.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 44 insertions(+)
|
||||
|
||||
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
|
||||
index e4a2d5a012..e977c6c616 100644
|
||||
--- a/target/i386/cpu.c
|
||||
+++ b/target/i386/cpu.c
|
||||
@@ -1923,6 +1923,50 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
.xlevel = 0x8000001A,
|
||||
.model_id = "AMD Opteron 63xx class CPU",
|
||||
},
|
||||
+ {
|
||||
+ .name = "EPYC",
|
||||
+ .level = 0xd,
|
||||
+ .vendor = CPUID_VENDOR_AMD,
|
||||
+ .family = 23,
|
||||
+ .model = 1,
|
||||
+ .stepping = 2,
|
||||
+ .features[FEAT_1_EDX] =
|
||||
+ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH |
|
||||
+ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE |
|
||||
+ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE |
|
||||
+ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE |
|
||||
+ CPUID_VME | CPUID_FP87,
|
||||
+ .features[FEAT_1_ECX] =
|
||||
+ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX |
|
||||
+ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT |
|
||||
+ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
|
||||
+ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 |
|
||||
+ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
|
||||
+ .features[FEAT_8000_0001_EDX] =
|
||||
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB |
|
||||
+ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX |
|
||||
+ CPUID_EXT2_SYSCALL,
|
||||
+ .features[FEAT_8000_0001_ECX] =
|
||||
+ CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH |
|
||||
+ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM |
|
||||
+ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
|
||||
+ .features[FEAT_7_0_EBX] =
|
||||
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 |
|
||||
+ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED |
|
||||
+ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT |
|
||||
+ CPUID_7_0_EBX_SHA_NI,
|
||||
+ /* Missing: XSAVES (not supported by some Linux versions,
|
||||
+ * including v4.1 to v4.12).
|
||||
+ * KVM doesn't yet expose any XSAVES state save component.
|
||||
+ */
|
||||
+ .features[FEAT_XSAVE] =
|
||||
+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
|
||||
+ CPUID_XSAVE_XGETBV1,
|
||||
+ .features[FEAT_6_EAX] =
|
||||
+ CPUID_6_EAX_ARAT,
|
||||
+ .xlevel = 0x8000000A,
|
||||
+ .model_id = "AMD EPYC Processor",
|
||||
+ },
|
||||
};
|
||||
|
||||
typedef struct PropValue {
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,78 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eduardo Habkost <ehabkost@redhat.com>
|
||||
Date: Tue, 9 Jan 2018 13:45:18 -0200
|
||||
Subject: [PATCH] i386: Add EPYC-IBPB CPU model
|
||||
|
||||
EPYC-IBPB is a copy of the EPYC CPU model with
|
||||
just CPUID_8000_0008_EBX_IBPB added.
|
||||
|
||||
Cc: Jiri Denemark <jdenemar@redhat.com>
|
||||
Cc: Tom Lendacky <thomas.lendacky@amd.com>
|
||||
Cc: Brijesh Singh <brijesh.singh@amd.com>
|
||||
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
Message-Id: <20180109154519.25634-7-ehabkost@redhat.com>
|
||||
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
||||
---
|
||||
target/i386/cpu.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 46 insertions(+)
|
||||
|
||||
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
|
||||
index e977c6c616..95e6a1f122 100644
|
||||
--- a/target/i386/cpu.c
|
||||
+++ b/target/i386/cpu.c
|
||||
@@ -1967,6 +1967,52 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
.xlevel = 0x8000000A,
|
||||
.model_id = "AMD EPYC Processor",
|
||||
},
|
||||
+ {
|
||||
+ .name = "EPYC-IBPB",
|
||||
+ .level = 0xd,
|
||||
+ .vendor = CPUID_VENDOR_AMD,
|
||||
+ .family = 23,
|
||||
+ .model = 1,
|
||||
+ .stepping = 2,
|
||||
+ .features[FEAT_1_EDX] =
|
||||
+ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH |
|
||||
+ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE |
|
||||
+ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE |
|
||||
+ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE |
|
||||
+ CPUID_VME | CPUID_FP87,
|
||||
+ .features[FEAT_1_ECX] =
|
||||
+ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX |
|
||||
+ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT |
|
||||
+ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
|
||||
+ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 |
|
||||
+ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
|
||||
+ .features[FEAT_8000_0001_EDX] =
|
||||
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB |
|
||||
+ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX |
|
||||
+ CPUID_EXT2_SYSCALL,
|
||||
+ .features[FEAT_8000_0001_ECX] =
|
||||
+ CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH |
|
||||
+ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM |
|
||||
+ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
|
||||
+ .features[FEAT_8000_0008_EBX] =
|
||||
+ CPUID_8000_0008_EBX_IBPB,
|
||||
+ .features[FEAT_7_0_EBX] =
|
||||
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 |
|
||||
+ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED |
|
||||
+ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT |
|
||||
+ CPUID_7_0_EBX_SHA_NI,
|
||||
+ /* Missing: XSAVES (not supported by some Linux versions,
|
||||
+ * including v4.1 to v4.12).
|
||||
+ * KVM doesn't yet expose any XSAVES state save component.
|
||||
+ */
|
||||
+ .features[FEAT_XSAVE] =
|
||||
+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
|
||||
+ CPUID_XSAVE_XGETBV1,
|
||||
+ .features[FEAT_6_EAX] =
|
||||
+ CPUID_6_EAX_ARAT,
|
||||
+ .xlevel = 0x8000000A,
|
||||
+ .model_id = "AMD EPYC Processor (with IBPB)",
|
||||
+ },
|
||||
};
|
||||
|
||||
typedef struct PropValue {
|
||||
--
|
||||
2.11.0
|
||||
|
39
debian/patches/pve/0001-block-file-change-locking-default-to-off.patch
vendored
Normal file
39
debian/patches/pve/0001-block-file-change-locking-default-to-off.patch
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
Date: Wed, 29 Nov 2017 11:11:46 +0100
|
||||
Subject: [PATCH] block/file: change locking default to off
|
||||
|
||||
'auto' only checks whether the system generally supports OFD
|
||||
locks but not whether the storage the file resides on
|
||||
supports any locking, causing issues with NFS.
|
||||
|
||||
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
---
|
||||
block/file-posix.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/block/file-posix.c b/block/file-posix.c
|
||||
index 36ee89e940..4bff572d07 100644
|
||||
--- a/block/file-posix.c
|
||||
+++ b/block/file-posix.c
|
||||
@@ -405,7 +405,7 @@ static QemuOptsList raw_runtime_opts = {
|
||||
{
|
||||
.name = "locking",
|
||||
.type = QEMU_OPT_STRING,
|
||||
- .help = "file locking mode (on/off/auto, default: auto)",
|
||||
+ .help = "file locking mode (on/off/auto, default: off)",
|
||||
},
|
||||
{
|
||||
.name = "pr-manager",
|
||||
@@ -481,7 +481,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
s->use_lock = false;
|
||||
break;
|
||||
case ON_OFF_AUTO_AUTO:
|
||||
- s->use_lock = qemu_has_ofd_lock();
|
||||
+ s->use_lock = false;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,48 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 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] 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 b645208e42..92912409e1 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.11.0
|
||||
|
@ -8,10 +8,10 @@ Subject: [PATCH] Adjust network script path to /etc/kvm/
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/include/net/net.h b/include/net/net.h
|
||||
index 99b28d5b38..40c39f00e6 100644
|
||||
index 1c55a93588..13ecb9cc8c 100644
|
||||
--- a/include/net/net.h
|
||||
+++ b/include/net/net.h
|
||||
@@ -214,8 +214,9 @@ void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp);
|
||||
@@ -220,8 +220,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);
|
||||
|
||||
|
@ -8,12 +8,12 @@ Subject: [PATCH] qemu-img: return success on info without snapshots
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/qemu-img.c b/qemu-img.c
|
||||
index e4a2686f56..c7804d63ee 100644
|
||||
index 68b375f998..f8a39dd195 100644
|
||||
--- a/qemu-img.c
|
||||
+++ b/qemu-img.c
|
||||
@@ -2596,7 +2596,8 @@ static int img_info(int argc, char **argv)
|
||||
|
||||
list = collect_image_info_list(image_opts, filename, fmt, chain);
|
||||
@@ -2594,7 +2594,8 @@ static int img_info(int argc, char **argv)
|
||||
list = collect_image_info_list(image_opts, filename, fmt, chain,
|
||||
force_share);
|
||||
if (!list) {
|
||||
- return 1;
|
||||
+ // return success if snapshot does not exists
|
||||
|
22
debian/patches/pve/0004-use-kvm-by-default.patch
vendored
22
debian/patches/pve/0004-use-kvm-by-default.patch
vendored
@ -4,24 +4,24 @@ Date: Wed, 9 Dec 2015 14:27:05 +0100
|
||||
Subject: [PATCH] use kvm by default
|
||||
|
||||
---
|
||||
accel.c | 4 ++--
|
||||
accel/accel.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/accel.c b/accel.c
|
||||
index 664bb88422..ddb23a3f1d 100644
|
||||
--- a/accel.c
|
||||
+++ b/accel.c
|
||||
@@ -87,8 +87,8 @@ void configure_accelerator(MachineState *ms)
|
||||
diff --git a/accel/accel.c b/accel/accel.c
|
||||
index 8ae40e1e13..df21981026 100644
|
||||
--- a/accel/accel.c
|
||||
+++ b/accel/accel.c
|
||||
@@ -79,8 +79,8 @@ void configure_accelerator(MachineState *ms)
|
||||
|
||||
p = qemu_opt_get(qemu_get_machine_opts(), "accel");
|
||||
if (p == NULL) {
|
||||
accel = qemu_opt_get(qemu_get_machine_opts(), "accel");
|
||||
if (accel == NULL) {
|
||||
- /* Use the default "accelerator", tcg */
|
||||
- p = "tcg";
|
||||
- accel = "tcg";
|
||||
+ /* Use the default "accelerator", kvm */
|
||||
+ p = "kvm";
|
||||
+ accel = "kvm";
|
||||
}
|
||||
|
||||
while (!accel_initialised && *p != '\0') {
|
||||
p = accel;
|
||||
--
|
||||
2.11.0
|
||||
|
||||
|
@ -8,14 +8,14 @@ command.
|
||||
---
|
||||
hmp.c | 30 +++++++++++++++++++++++++++++-
|
||||
hw/virtio/virtio-balloon.c | 33 +++++++++++++++++++++++++++++++--
|
||||
qapi-schema.json | 23 +++++++++++++++++++++--
|
||||
3 files changed, 81 insertions(+), 5 deletions(-)
|
||||
qapi-schema.json | 22 +++++++++++++++++++++-
|
||||
3 files changed, 81 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/hmp.c b/hmp.c
|
||||
index edb8970461..904542d026 100644
|
||||
index 35a7041824..4e1d571003 100644
|
||||
--- a/hmp.c
|
||||
+++ b/hmp.c
|
||||
@@ -723,7 +723,35 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict)
|
||||
@@ -789,7 +789,35 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict)
|
||||
return;
|
||||
}
|
||||
|
||||
@ -53,10 +53,10 @@ index edb8970461..904542d026 100644
|
||||
qapi_free_BalloonInfo(info);
|
||||
}
|
||||
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
|
||||
index a705e0ec55..158e13e795 100644
|
||||
index 37cde38982..1feaf77223 100644
|
||||
--- a/hw/virtio/virtio-balloon.c
|
||||
+++ b/hw/virtio/virtio-balloon.c
|
||||
@@ -379,8 +379,37 @@ static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f,
|
||||
@@ -380,8 +380,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;
|
||||
@ -97,14 +97,13 @@ index a705e0ec55..158e13e795 100644
|
||||
|
||||
static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
|
||||
diff --git a/qapi-schema.json b/qapi-schema.json
|
||||
index 250e4dc49b..f38b85bf6a 100644
|
||||
index 18457954a8..ebc22fe5a6 100644
|
||||
--- a/qapi-schema.json
|
||||
+++ b/qapi-schema.json
|
||||
@@ -1900,10 +1900,29 @@
|
||||
@@ -623,10 +623,30 @@
|
||||
#
|
||||
# @actual: the number of bytes the balloon currently contains
|
||||
#
|
||||
-# Since: 0.14.0
|
||||
+# @last_update: time when stats got updated from guest
|
||||
+#
|
||||
+# @mem_swapped_in: number of pages swapped in within the guest
|
||||
@ -112,7 +111,7 @@ index 250e4dc49b..f38b85bf6a 100644
|
||||
+# @mem_swapped_out: number of pages swapped out within the guest
|
||||
+#
|
||||
+# @major_page_faults: number of major page faults within the guest
|
||||
#
|
||||
+#
|
||||
+# @minor_page_faults: number of minor page faults within the guest
|
||||
+#
|
||||
+# @free_mem: amount of memory (in bytes) free in the guest
|
||||
@ -120,8 +119,9 @@ index 250e4dc49b..f38b85bf6a 100644
|
||||
+# @total_mem: amount of memory (in bytes) visible to the guest
|
||||
+#
|
||||
+# @max_mem: amount of memory (in bytes) assigned to the guest
|
||||
+#
|
||||
+# Since: 0.14.0
|
||||
+#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
##
|
||||
-{ 'struct': 'BalloonInfo', 'data': {'actual': 'int' } }
|
||||
+{ 'struct': 'BalloonInfo',
|
||||
|
@ -4,25 +4,25 @@ Date: Wed, 9 Dec 2015 14:30:21 +0100
|
||||
Subject: [PATCH] set the CPU model to kvm64/32 instead of qemu64/32
|
||||
|
||||
---
|
||||
hw/i386/pc.c | 4 ++--
|
||||
target/i386/cpu.h | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
|
||||
index 610050eb4f..e96901435a 100644
|
||||
--- a/hw/i386/pc.c
|
||||
+++ b/hw/i386/pc.c
|
||||
@@ -1151,9 +1151,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
|
||||
}
|
||||
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
|
||||
index f3d0ebb673..660e42977b 100644
|
||||
--- a/target/i386/cpu.h
|
||||
+++ b/target/i386/cpu.h
|
||||
@@ -1521,9 +1521,9 @@ uint64_t cpu_get_tsc(CPUX86State *env);
|
||||
#define X86_CPU_TYPE_NAME(name) (name X86_CPU_TYPE_SUFFIX)
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
-#define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("qemu64")
|
||||
+#define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("kvm64")
|
||||
#else
|
||||
-#define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("qemu32")
|
||||
+#define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("kvm32")
|
||||
#endif
|
||||
|
||||
#define cpu_signal_handler cpu_x86_signal_handler
|
||||
--
|
||||
2.11.0
|
||||
|
||||
|
@ -10,10 +10,10 @@ provide '*is-current' in MachineInfo struct
|
||||
2 files changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/qapi-schema.json b/qapi-schema.json
|
||||
index f38b85bf6a..51e150c6c1 100644
|
||||
index ebc22fe5a6..8f436ba1f3 100644
|
||||
--- a/qapi-schema.json
|
||||
+++ b/qapi-schema.json
|
||||
@@ -4242,6 +4242,8 @@
|
||||
@@ -1914,6 +1914,8 @@
|
||||
#
|
||||
# @is-default: whether the machine is default
|
||||
#
|
||||
@ -22,7 +22,7 @@ index f38b85bf6a..51e150c6c1 100644
|
||||
# @cpu-max: maximum number of CPUs supported by the machine type
|
||||
# (since 1.5.0)
|
||||
#
|
||||
@@ -4251,7 +4253,7 @@
|
||||
@@ -1923,7 +1925,7 @@
|
||||
##
|
||||
{ 'struct': 'MachineInfo',
|
||||
'data': { 'name': 'str', '*alias': 'str',
|
||||
@ -32,10 +32,10 @@ index f38b85bf6a..51e150c6c1 100644
|
||||
|
||||
##
|
||||
diff --git a/vl.c b/vl.c
|
||||
index b719cc432e..46de1b9087 100644
|
||||
index 1ad1c04637..2e0fe15978 100644
|
||||
--- a/vl.c
|
||||
+++ b/vl.c
|
||||
@@ -1518,6 +1518,11 @@ MachineInfoList *qmp_query_machines(Error **errp)
|
||||
@@ -1604,6 +1604,11 @@ MachineInfoList *qmp_query_machines(Error **errp)
|
||||
info->cpu_max = !mc->max_cpus ? 1 : mc->max_cpus;
|
||||
info->hotpluggable_cpus = mc->has_hotpluggable_cpus;
|
||||
|
||||
|
@ -5,15 +5,15 @@ Subject: [PATCH] qapi: modify spice query
|
||||
|
||||
Provide the last ticket in the SpiceInfo struct optionally.
|
||||
---
|
||||
qapi-schema.json | 3 +++
|
||||
ui/spice-core.c | 5 +++++
|
||||
qapi/ui.json | 3 +++
|
||||
ui/spice-core.c | 5 +++++
|
||||
2 files changed, 8 insertions(+)
|
||||
|
||||
diff --git a/qapi-schema.json b/qapi-schema.json
|
||||
index 51e150c6c1..1b14ff2476 100644
|
||||
--- a/qapi-schema.json
|
||||
+++ b/qapi-schema.json
|
||||
@@ -1841,11 +1841,14 @@
|
||||
diff --git a/qapi/ui.json b/qapi/ui.json
|
||||
index 07b468f625..78c906ddcf 100644
|
||||
--- a/qapi/ui.json
|
||||
+++ b/qapi/ui.json
|
||||
@@ -199,11 +199,14 @@
|
||||
#
|
||||
# @channels: a list of @SpiceChannel for each active spice channel
|
||||
#
|
||||
@ -29,10 +29,10 @@ index 51e150c6c1..1b14ff2476 100644
|
||||
|
||||
##
|
||||
diff --git a/ui/spice-core.c b/ui/spice-core.c
|
||||
index 804abc5c0f..4a417310d3 100644
|
||||
index ea04dc69b5..05f5958b14 100644
|
||||
--- a/ui/spice-core.c
|
||||
+++ b/ui/spice-core.c
|
||||
@@ -552,6 +552,11 @@ SpiceInfo *qmp_query_spice(Error **errp)
|
||||
@@ -551,6 +551,11 @@ SpiceInfo *qmp_query_spice(Error **errp)
|
||||
micro = SPICE_SERVER_VERSION & 0xff;
|
||||
info->compiled_version = g_strdup_printf("%d.%d.%d", major, minor, micro);
|
||||
|
||||
|
@ -8,10 +8,10 @@ Subject: [PATCH] ui/spice: default to pve certs unless otherwise specified
|
||||
1 file changed, 9 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/ui/spice-core.c b/ui/spice-core.c
|
||||
index 4a417310d3..af1dc8c653 100644
|
||||
index 05f5958b14..6e1a46d1e5 100644
|
||||
--- a/ui/spice-core.c
|
||||
+++ b/ui/spice-core.c
|
||||
@@ -685,32 +685,35 @@ void qemu_spice_init(void)
|
||||
@@ -684,32 +684,35 @@ void qemu_spice_init(void)
|
||||
|
||||
if (tls_port) {
|
||||
x509_dir = qemu_opt_get(opts, "x509-dir");
|
||||
|
@ -4,37 +4,45 @@ Date: Wed, 9 Dec 2015 16:04:32 +0100
|
||||
Subject: [PATCH] internal snapshot async
|
||||
|
||||
---
|
||||
Makefile.objs | 1 +
|
||||
hmp-commands-info.hx | 13 ++
|
||||
hmp-commands.hx | 32 +++
|
||||
hmp.c | 57 ++++++
|
||||
hmp.h | 5 +
|
||||
include/sysemu/sysemu.h | 5 +-
|
||||
migration/savevm.c | 12 +-
|
||||
qapi-schema.json | 68 +++++++
|
||||
qemu-options.hx | 13 ++
|
||||
savevm-async.c | 523 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
vl.c | 8 +
|
||||
11 files changed, 730 insertions(+), 7 deletions(-)
|
||||
Makefile.objs | 2 +-
|
||||
hmp-commands-info.hx | 13 ++
|
||||
hmp-commands.hx | 32 +++
|
||||
hmp.c | 57 +++++
|
||||
hmp.h | 5 +
|
||||
include/migration/snapshot.h | 1 +
|
||||
qapi-schema.json | 32 +++
|
||||
qapi/migration.json | 34 +++
|
||||
qemu-options.hx | 13 ++
|
||||
savevm-async.c | 524 +++++++++++++++++++++++++++++++++++++++++++
|
||||
vl.c | 10 +
|
||||
11 files changed, 722 insertions(+), 1 deletion(-)
|
||||
create mode 100644 savevm-async.c
|
||||
|
||||
diff --git a/Makefile.objs b/Makefile.objs
|
||||
index 6167e7b17d..fbfbbb7f70 100644
|
||||
index 285c6f3c15..686247b556 100644
|
||||
--- a/Makefile.objs
|
||||
+++ b/Makefile.objs
|
||||
@@ -50,6 +50,7 @@ common-obj-$(CONFIG_LINUX) += fsdev/
|
||||
@@ -41,6 +41,7 @@ io-obj-y = io/
|
||||
ifeq ($(CONFIG_SOFTMMU),y)
|
||||
common-obj-y = blockdev.o blockdev-nbd.o block/
|
||||
common-obj-y += bootdevice.o iothread.o
|
||||
+common-obj-y += savevm-async.o
|
||||
common-obj-y += net/
|
||||
common-obj-y += qdev-monitor.o device-hotplug.o
|
||||
common-obj-$(CONFIG_WIN32) += os-win32.o
|
||||
@@ -49,7 +50,6 @@ common-obj-$(CONFIG_POSIX) += os-posix.o
|
||||
common-obj-$(CONFIG_LINUX) += fsdev/
|
||||
|
||||
common-obj-y += migration/
|
||||
common-obj-y += page_cache.o #aio.o
|
||||
+common-obj-y += savevm-async.o
|
||||
|
||||
common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
|
||||
-
|
||||
common-obj-y += audio/
|
||||
common-obj-y += hw/
|
||||
|
||||
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
|
||||
index a53f105c52..5fc57a2210 100644
|
||||
index 54c3e5eac6..3bf69a193c 100644
|
||||
--- a/hmp-commands-info.hx
|
||||
+++ b/hmp-commands-info.hx
|
||||
@@ -560,6 +560,19 @@ Show current migration xbzrle cache size.
|
||||
@@ -566,6 +566,19 @@ Show current migration xbzrle cache size.
|
||||
ETEXI
|
||||
|
||||
{
|
||||
@ -55,10 +63,10 @@ index a53f105c52..5fc57a2210 100644
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
diff --git a/hmp-commands.hx b/hmp-commands.hx
|
||||
index 88192817b2..58940a762b 100644
|
||||
index 4afd57cf5f..b35bc6ab6c 100644
|
||||
--- a/hmp-commands.hx
|
||||
+++ b/hmp-commands.hx
|
||||
@@ -1777,3 +1777,35 @@ ETEXI
|
||||
@@ -1873,3 +1873,35 @@ ETEXI
|
||||
STEXI
|
||||
@end table
|
||||
ETEXI
|
||||
@ -95,11 +103,11 @@ index 88192817b2..58940a762b 100644
|
||||
+ .cmd = hmp_savevm_end,
|
||||
+ },
|
||||
diff --git a/hmp.c b/hmp.c
|
||||
index 904542d026..f725d061e6 100644
|
||||
index 4e1d571003..b9ade681f0 100644
|
||||
--- a/hmp.c
|
||||
+++ b/hmp.c
|
||||
@@ -2207,6 +2207,63 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
|
||||
qapi_free_MemoryDeviceInfoList(info_list);
|
||||
@@ -2486,6 +2486,63 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
|
||||
hmp_handle_error(mon, &err);
|
||||
}
|
||||
|
||||
+void hmp_savevm_start(Monitor *mon, const QDict *qdict)
|
||||
@ -163,7 +171,7 @@ index 904542d026..f725d061e6 100644
|
||||
{
|
||||
IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
|
||||
diff --git a/hmp.h b/hmp.h
|
||||
index 799fd371fa..0497afbf65 100644
|
||||
index a6f56b1f29..45ada581b6 100644
|
||||
--- a/hmp.h
|
||||
+++ b/hmp.h
|
||||
@@ -26,6 +26,7 @@ void hmp_info_status(Monitor *mon, const QDict *qdict);
|
||||
@ -174,7 +182,7 @@ index 799fd371fa..0497afbf65 100644
|
||||
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);
|
||||
@@ -92,6 +93,10 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict);
|
||||
@@ -97,6 +98,10 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict);
|
||||
void hmp_netdev_del(Monitor *mon, const QDict *qdict);
|
||||
void hmp_getfd(Monitor *mon, const QDict *qdict);
|
||||
void hmp_closefd(Monitor *mon, const QDict *qdict);
|
||||
@ -185,97 +193,65 @@ index 799fd371fa..0497afbf65 100644
|
||||
void hmp_sendkey(Monitor *mon, const QDict *qdict);
|
||||
void hmp_screendump(Monitor *mon, const QDict *qdict);
|
||||
void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
|
||||
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
|
||||
index 576c7ce640..74623de16c 100644
|
||||
--- a/include/sysemu/sysemu.h
|
||||
+++ b/include/sysemu/sysemu.h
|
||||
@@ -78,6 +78,7 @@ void qemu_remove_machine_init_done_notifier(Notifier *notify);
|
||||
void hmp_savevm(Monitor *mon, const QDict *qdict);
|
||||
int save_vmstate(Monitor *mon, const char *name);
|
||||
int load_vmstate(const char *name);
|
||||
+int load_state_from_blockdev(const char *filename);
|
||||
void hmp_delvm(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_snapshots(Monitor *mon, const QDict *qdict);
|
||||
diff --git a/include/migration/snapshot.h b/include/migration/snapshot.h
|
||||
index c85b6ec75b..4411b7121d 100644
|
||||
--- a/include/migration/snapshot.h
|
||||
+++ b/include/migration/snapshot.h
|
||||
@@ -17,5 +17,6 @@
|
||||
|
||||
@@ -105,13 +106,13 @@ enum qemu_vm_cmd {
|
||||
#define MAX_VM_CMD_PACKAGED_SIZE (1ul << 24)
|
||||
int save_snapshot(const char *name, Error **errp);
|
||||
int load_snapshot(const char *name, Error **errp);
|
||||
+int load_snapshot_from_blockdev(const char *filename, Error **errp);
|
||||
|
||||
bool qemu_savevm_state_blocked(Error **errp);
|
||||
-void qemu_savevm_state_begin(QEMUFile *f,
|
||||
+int qemu_savevm_state_begin(QEMUFile *f,
|
||||
const MigrationParams *params);
|
||||
void qemu_savevm_state_header(QEMUFile *f);
|
||||
int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy);
|
||||
void qemu_savevm_state_cleanup(void);
|
||||
void qemu_savevm_state_complete_postcopy(QEMUFile *f);
|
||||
-void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only);
|
||||
+int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only);
|
||||
void qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size,
|
||||
uint64_t *res_non_postcopiable,
|
||||
uint64_t *res_postcopiable);
|
||||
diff --git a/migration/savevm.c b/migration/savevm.c
|
||||
index 3b19a4a274..feb0dc6834 100644
|
||||
--- a/migration/savevm.c
|
||||
+++ b/migration/savevm.c
|
||||
@@ -970,11 +970,11 @@ void qemu_savevm_state_header(QEMUFile *f)
|
||||
|
||||
}
|
||||
|
||||
-void qemu_savevm_state_begin(QEMUFile *f,
|
||||
+int qemu_savevm_state_begin(QEMUFile *f,
|
||||
const MigrationParams *params)
|
||||
{
|
||||
SaveStateEntry *se;
|
||||
- int ret;
|
||||
+ int ret = 0;
|
||||
|
||||
trace_savevm_state_begin();
|
||||
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
|
||||
@@ -1002,6 +1002,7 @@ void qemu_savevm_state_begin(QEMUFile *f,
|
||||
break;
|
||||
}
|
||||
}
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1105,7 +1106,7 @@ void qemu_savevm_state_complete_postcopy(QEMUFile *f)
|
||||
qemu_fflush(f);
|
||||
}
|
||||
|
||||
-void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
|
||||
+int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
|
||||
{
|
||||
QJSON *vmdesc;
|
||||
int vmdesc_len;
|
||||
@@ -1139,12 +1140,12 @@ void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
|
||||
save_section_footer(f, se);
|
||||
if (ret < 0) {
|
||||
qemu_file_set_error(f, ret);
|
||||
- return;
|
||||
+ return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (iterable_only) {
|
||||
- return;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
vmdesc = qjson_new();
|
||||
@@ -1191,6 +1192,7 @@ void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
|
||||
qjson_destroy(vmdesc);
|
||||
|
||||
qemu_fflush(f);
|
||||
+ return qemu_file_get_error(f);
|
||||
}
|
||||
|
||||
/* Give an estimate of the amount left to be transferred,
|
||||
#endif
|
||||
diff --git a/qapi-schema.json b/qapi-schema.json
|
||||
index 1b14ff2476..361700d37c 100644
|
||||
index 8f436ba1f3..348b527681 100644
|
||||
--- a/qapi-schema.json
|
||||
+++ b/qapi-schema.json
|
||||
@@ -723,6 +723,40 @@
|
||||
@@ -2439,6 +2439,38 @@
|
||||
{ 'command': 'query-target', 'returns': 'TargetInfo' }
|
||||
|
||||
##
|
||||
+# @savevm-start:
|
||||
+#
|
||||
+# Prepare for snapshot and halt VM. Save VM state to statefile.
|
||||
+#
|
||||
+##
|
||||
+{ 'command': 'savevm-start', 'data': { '*statefile': 'str' } }
|
||||
+
|
||||
+##
|
||||
+# @snapshot-drive:
|
||||
+#
|
||||
+# Create an internal drive snapshot.
|
||||
+#
|
||||
+##
|
||||
+{ 'command': 'snapshot-drive', 'data': { 'device': 'str', 'name': 'str' } }
|
||||
+
|
||||
+##
|
||||
+# @delete-drive-snapshot:
|
||||
+#
|
||||
+# Delete a drive snapshot.
|
||||
+#
|
||||
+##
|
||||
+{ 'command': 'delete-drive-snapshot', 'data': { 'device': 'str', 'name': 'str' } }
|
||||
+
|
||||
+##
|
||||
+# @savevm-end:
|
||||
+#
|
||||
+# Resume VM after a snapshot.
|
||||
+#
|
||||
+##
|
||||
+{ 'command': 'savevm-end' }
|
||||
+
|
||||
+##
|
||||
# @AcpiTableOptions:
|
||||
#
|
||||
# Specify an ACPI table on the command line to load.
|
||||
diff --git a/qapi/migration.json b/qapi/migration.json
|
||||
index 03f57c9616..9ae55b81a2 100644
|
||||
--- a/qapi/migration.json
|
||||
+++ b/qapi/migration.json
|
||||
@@ -170,6 +170,40 @@
|
||||
'*error-desc': 'str'} }
|
||||
|
||||
##
|
||||
@ -316,55 +292,11 @@ index 1b14ff2476..361700d37c 100644
|
||||
# @query-migrate:
|
||||
#
|
||||
# Returns information about current migration process. If migration
|
||||
@@ -4735,9 +4769,43 @@
|
||||
#
|
||||
# Since: 1.2.0
|
||||
##
|
||||
+
|
||||
{ 'command': 'query-target', 'returns': 'TargetInfo' }
|
||||
|
||||
##
|
||||
+# @savevm-start:
|
||||
+#
|
||||
+# Prepare for snapshot and halt VM. Save VM state to statefile.
|
||||
+#
|
||||
+##
|
||||
+{ 'command': 'savevm-start', 'data': { '*statefile': 'str' } }
|
||||
+
|
||||
+##
|
||||
+# @snapshot-drive:
|
||||
+#
|
||||
+# Create an internal drive snapshot.
|
||||
+#
|
||||
+##
|
||||
+{ 'command': 'snapshot-drive', 'data': { 'device': 'str', 'name': 'str' } }
|
||||
+
|
||||
+##
|
||||
+# @delete-drive-snapshot:
|
||||
+#
|
||||
+# Delete a drive snapshot.
|
||||
+#
|
||||
+##
|
||||
+{ 'command': 'delete-drive-snapshot', 'data': { 'device': 'str', 'name': 'str' } }
|
||||
+
|
||||
+##
|
||||
+# @savevm-end:
|
||||
+#
|
||||
+# Resume VM after a snapshot.
|
||||
+#
|
||||
+##
|
||||
+{ 'command': 'savevm-end' }
|
||||
+
|
||||
+
|
||||
+##
|
||||
# @QKeyCode:
|
||||
#
|
||||
# An enumeration of key name.
|
||||
diff --git a/qemu-options.hx b/qemu-options.hx
|
||||
index 48dfffd86a..cbcb27da9a 100644
|
||||
index 57f2c6a75f..7c054af8f9 100644
|
||||
--- a/qemu-options.hx
|
||||
+++ b/qemu-options.hx
|
||||
@@ -3396,6 +3396,19 @@ STEXI
|
||||
@@ -3698,6 +3698,19 @@ STEXI
|
||||
Start right away with a saved state (@code{loadvm} in monitor)
|
||||
ETEXI
|
||||
|
||||
@ -386,28 +318,23 @@ index 48dfffd86a..cbcb27da9a 100644
|
||||
"-daemonize daemonize QEMU after initializing\n", QEMU_ARCH_ALL)
|
||||
diff --git a/savevm-async.c b/savevm-async.c
|
||||
new file mode 100644
|
||||
index 0000000000..5fcb56d373
|
||||
index 0000000000..897134ab5a
|
||||
--- /dev/null
|
||||
+++ b/savevm-async.c
|
||||
@@ -0,0 +1,523 @@
|
||||
@@ -0,0 +1,524 @@
|
||||
+#include "qemu/osdep.h"
|
||||
+#include "qemu-common.h"
|
||||
+#include "migration/migration.h"
|
||||
+#include "migration/savevm.h"
|
||||
+#include "migration/snapshot.h"
|
||||
+#include "migration/global_state.h"
|
||||
+#include "migration/ram.h"
|
||||
+#include "migration/qemu-file.h"
|
||||
+#include "qapi/qmp/qerror.h"
|
||||
+#include "qemu/error-report.h"
|
||||
+#include "sysemu/sysemu.h"
|
||||
+#include "qmp-commands.h"
|
||||
+#include "qemu-options.h"
|
||||
+#include "migration/qemu-file.h"
|
||||
+#include "qom/qom-qobject.h"
|
||||
+#include "migration/migration.h"
|
||||
+#include "block/snapshot.h"
|
||||
+#include "block/qapi.h"
|
||||
+#include "block/block.h"
|
||||
+#include "qemu/timer.h"
|
||||
+#include "sysemu/block-backend.h"
|
||||
+#include "qapi/qmp/qstring.h"
|
||||
+#include "qemu/rcu.h"
|
||||
+#include "qemu/thread.h"
|
||||
+#include "qemu/cutils.h"
|
||||
+
|
||||
+/* #define DEBUG_SAVEVM_STATE */
|
||||
@ -498,7 +425,7 @@ index 0000000000..5fcb56d373
|
||||
+ * note: bdrv_read() need whole blocks, so we round up
|
||||
+ */
|
||||
+ size_t size = (snap_state.bs_pos + BDRV_SECTOR_SIZE) & BDRV_SECTOR_MASK;
|
||||
+ blk_truncate(snap_state.target, size, NULL);
|
||||
+ blk_truncate(snap_state.target, size, PREALLOC_MODE_OFF, NULL);
|
||||
+ blk_op_unblock_all(snap_state.target, snap_state.blocker);
|
||||
+ error_free(snap_state.blocker);
|
||||
+ snap_state.blocker = NULL;
|
||||
@ -578,20 +505,17 @@ index 0000000000..5fcb56d373
|
||||
+{
|
||||
+ int ret;
|
||||
+ int64_t maxlen;
|
||||
+ MigrationParams params = {
|
||||
+ .blk = 0,
|
||||
+ .shared = 0
|
||||
+ };
|
||||
+
|
||||
+ snap_state.state = SAVE_STATE_ACTIVE;
|
||||
+
|
||||
+ qemu_mutex_unlock_iothread();
|
||||
+ qemu_savevm_state_header(snap_state.file);
|
||||
+ ret = qemu_savevm_state_begin(snap_state.file, ¶ms);
|
||||
+ qemu_savevm_state_setup(snap_state.file);
|
||||
+ ret = qemu_file_get_error(snap_state.file);
|
||||
+ qemu_mutex_lock_iothread();
|
||||
+
|
||||
+ if (ret < 0) {
|
||||
+ save_snapshot_error("qemu_savevm_state_begin failed");
|
||||
+ save_snapshot_error("qemu_savevm_state_setup failed");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
@ -613,7 +537,16 @@ index 0000000000..5fcb56d373
|
||||
+ if (store_and_stop())
|
||||
+ break;
|
||||
+ DPRINTF("savevm inerate finished\n");
|
||||
+ qemu_savevm_state_complete_precopy(snap_state.file, false);
|
||||
+ /* upstream made the return value here inconsistent
|
||||
+ * (-1 instead of 'ret' in one case and 0 after flush which can
|
||||
+ * still set a file error...)
|
||||
+ */
|
||||
+ (void)qemu_savevm_state_complete_precopy(snap_state.file, false, false);
|
||||
+ ret = qemu_file_get_error(snap_state.file);
|
||||
+ if (ret < 0) {
|
||||
+ save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
|
||||
+ break;
|
||||
+ }
|
||||
+ DPRINTF("save complete\n");
|
||||
+ save_snapshot_completed();
|
||||
+ break;
|
||||
@ -867,7 +800,7 @@ index 0000000000..5fcb56d373
|
||||
+ .get_buffer = loadstate_get_buffer,
|
||||
+};
|
||||
+
|
||||
+int load_state_from_blockdev(const char *filename)
|
||||
+int load_snapshot_from_blockdev(const char *filename, Error **errp)
|
||||
+{
|
||||
+ BlockBackend *be;
|
||||
+ Error *local_err = NULL;
|
||||
@ -879,7 +812,7 @@ index 0000000000..5fcb56d373
|
||||
+ be = blk_new_open(filename, NULL, NULL, 0, &local_err);
|
||||
+
|
||||
+ if (!be) {
|
||||
+ error_report("Could not open VM state file");
|
||||
+ error_setg(errp, "Could not open VM state file");
|
||||
+ goto the_end;
|
||||
+ }
|
||||
+
|
||||
@ -889,17 +822,17 @@ index 0000000000..5fcb56d373
|
||||
+ /* restore the VM state */
|
||||
+ f = qemu_fopen_ops(be, &loadstate_file_ops);
|
||||
+ if (!f) {
|
||||
+ error_report("Could not open VM state file");
|
||||
+ error_setg(errp, "Could not open VM state file");
|
||||
+ goto the_end;
|
||||
+ }
|
||||
+
|
||||
+ qemu_system_reset(VMRESET_SILENT);
|
||||
+ qemu_system_reset(SHUTDOWN_CAUSE_NONE);
|
||||
+ ret = qemu_loadvm_state(f);
|
||||
+
|
||||
+ qemu_fclose(f);
|
||||
+ migration_incoming_state_destroy();
|
||||
+ if (ret < 0) {
|
||||
+ error_report("Error %d while loading VM state", ret);
|
||||
+ error_setg_errno(errp, -ret, "Error while loading VM state");
|
||||
+ goto the_end;
|
||||
+ }
|
||||
+
|
||||
@ -914,10 +847,10 @@ index 0000000000..5fcb56d373
|
||||
+ return ret;
|
||||
+}
|
||||
diff --git a/vl.c b/vl.c
|
||||
index 46de1b9087..2132a77129 100644
|
||||
index 2e0fe15978..1bfbe95b22 100644
|
||||
--- a/vl.c
|
||||
+++ b/vl.c
|
||||
@@ -2960,6 +2960,7 @@ int main(int argc, char **argv, char **envp)
|
||||
@@ -3109,6 +3109,7 @@ int main(int argc, char **argv, char **envp)
|
||||
int optind;
|
||||
const char *optarg;
|
||||
const char *loadvm = NULL;
|
||||
@ -925,7 +858,7 @@ index 46de1b9087..2132a77129 100644
|
||||
MachineClass *machine_class;
|
||||
const char *cpu_model;
|
||||
const char *vga_model = NULL;
|
||||
@@ -3635,6 +3636,9 @@ int main(int argc, char **argv, char **envp)
|
||||
@@ -3785,6 +3786,9 @@ int main(int argc, char **argv, char **envp)
|
||||
case QEMU_OPTION_loadvm:
|
||||
loadvm = optarg;
|
||||
break;
|
||||
@ -935,12 +868,14 @@ index 46de1b9087..2132a77129 100644
|
||||
case QEMU_OPTION_full_screen:
|
||||
full_screen = 1;
|
||||
break;
|
||||
@@ -4693,6 +4697,10 @@ int main(int argc, char **argv, char **envp)
|
||||
if (load_vmstate(loadvm) < 0) {
|
||||
@@ -4891,6 +4895,12 @@ int main(int argc, char **argv, char **envp)
|
||||
error_report_err(local_err);
|
||||
autostart = 0;
|
||||
}
|
||||
+ } else if (loadstate) {
|
||||
+ if (load_state_from_blockdev(loadstate) < 0) {
|
||||
+ Error *local_err = NULL;
|
||||
+ if (load_snapshot_from_blockdev(loadstate, &local_err) < 0) {
|
||||
+ error_report_err(local_err);
|
||||
+ autostart = 0;
|
||||
+ }
|
||||
}
|
||||
|
@ -4,14 +4,14 @@ Date: Tue, 8 Nov 2016 11:13:06 +0100
|
||||
Subject: [PATCH] convert savevm-async to threads
|
||||
|
||||
---
|
||||
savevm-async.c | 144 +++++++++++++++++++++++++++++++++++----------------------
|
||||
1 file changed, 88 insertions(+), 56 deletions(-)
|
||||
savevm-async.c | 143 +++++++++++++++++++++++++++++++++++----------------------
|
||||
1 file changed, 87 insertions(+), 56 deletions(-)
|
||||
|
||||
diff --git a/savevm-async.c b/savevm-async.c
|
||||
index 5fcb56d373..97d51d3edd 100644
|
||||
index 897134ab5a..96523c88ae 100644
|
||||
--- a/savevm-async.c
|
||||
+++ b/savevm-async.c
|
||||
@@ -48,6 +48,8 @@ static struct SnapshotState {
|
||||
@@ -43,6 +43,8 @@ static struct SnapshotState {
|
||||
int saved_vm_running;
|
||||
QEMUFile *file;
|
||||
int64_t total_time;
|
||||
@ -20,7 +20,7 @@ index 5fcb56d373..97d51d3edd 100644
|
||||
} snap_state;
|
||||
|
||||
SaveVMInfo *qmp_query_savevm(Error **errp)
|
||||
@@ -135,19 +137,6 @@ static void save_snapshot_error(const char *fmt, ...)
|
||||
@@ -130,19 +132,6 @@ static void save_snapshot_error(const char *fmt, ...)
|
||||
g_free (msg);
|
||||
|
||||
snap_state.state = SAVE_STATE_ERROR;
|
||||
@ -40,7 +40,7 @@ index 5fcb56d373..97d51d3edd 100644
|
||||
}
|
||||
|
||||
static int block_state_close(void *opaque)
|
||||
@@ -156,51 +145,90 @@ static int block_state_close(void *opaque)
|
||||
@@ -151,48 +140,86 @@ static int block_state_close(void *opaque)
|
||||
return blk_flush(snap_state.target);
|
||||
}
|
||||
|
||||
@ -125,29 +125,25 @@ index 5fcb56d373..97d51d3edd 100644
|
||||
{
|
||||
int ret;
|
||||
int64_t maxlen;
|
||||
+
|
||||
MigrationParams params = {
|
||||
.blk = 0,
|
||||
.shared = 0
|
||||
};
|
||||
|
||||
- snap_state.state = SAVE_STATE_ACTIVE;
|
||||
+ rcu_register_thread();
|
||||
|
||||
- qemu_mutex_unlock_iothread();
|
||||
qemu_savevm_state_header(snap_state.file);
|
||||
ret = qemu_savevm_state_begin(snap_state.file, ¶ms);
|
||||
qemu_savevm_state_setup(snap_state.file);
|
||||
ret = qemu_file_get_error(snap_state.file);
|
||||
- qemu_mutex_lock_iothread();
|
||||
|
||||
if (ret < 0) {
|
||||
save_snapshot_error("qemu_savevm_state_begin failed");
|
||||
save_snapshot_error("qemu_savevm_state_setup failed");
|
||||
- return;
|
||||
+ rcu_unregister_thread();
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
while (snap_state.state == SAVE_STATE_ACTIVE) {
|
||||
@@ -209,41 +237,43 @@ static void process_savevm_co(void *opaque)
|
||||
@@ -201,17 +228,30 @@ static void process_savevm_co(void *opaque)
|
||||
qemu_savevm_state_pending(snap_state.file, 0, &pend_nonpost, &pend_post);
|
||||
pending_size = pend_post + pend_nonpost;
|
||||
|
||||
@ -185,7 +181,12 @@ index 5fcb56d373..97d51d3edd 100644
|
||||
+ break;
|
||||
+ }
|
||||
DPRINTF("savevm inerate finished\n");
|
||||
qemu_savevm_state_complete_precopy(snap_state.file, false);
|
||||
/* upstream made the return value here inconsistent
|
||||
* (-1 instead of 'ret' in one case and 0 after flush which can
|
||||
@@ -223,28 +263,17 @@ static void process_savevm_co(void *opaque)
|
||||
save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
|
||||
break;
|
||||
}
|
||||
+ qemu_savevm_state_cleanup();
|
||||
DPRINTF("save complete\n");
|
||||
- save_snapshot_completed();
|
||||
@ -216,7 +217,7 @@ index 5fcb56d373..97d51d3edd 100644
|
||||
}
|
||||
|
||||
static const QEMUFileOps block_file_ops = {
|
||||
@@ -306,8 +336,10 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
|
||||
@@ -307,8 +336,10 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
|
||||
error_setg(&snap_state.blocker, "block device is in use by savevm");
|
||||
blk_op_block_all(snap_state.target, snap_state.blocker);
|
||||
|
||||
|
@ -4,15 +4,15 @@ Date: Wed, 9 Dec 2015 16:34:41 +0100
|
||||
Subject: [PATCH] qmp: add get_link_status
|
||||
|
||||
---
|
||||
net/net.c | 27 +++++++++++++++++++++++++++
|
||||
qapi-schema.json | 16 ++++++++++++++++
|
||||
2 files changed, 43 insertions(+)
|
||||
net/net.c | 27 +++++++++++++++++++++++++++
|
||||
qapi/net.json | 15 +++++++++++++++
|
||||
2 files changed, 42 insertions(+)
|
||||
|
||||
diff --git a/net/net.c b/net/net.c
|
||||
index 0ac3b9e80c..7410c1e5f3 100644
|
||||
index 39ef546708..3681aa2173 100644
|
||||
--- a/net/net.c
|
||||
+++ b/net/net.c
|
||||
@@ -1373,6 +1373,33 @@ void hmp_info_network(Monitor *mon, const QDict *qdict)
|
||||
@@ -1399,6 +1399,33 @@ void hmp_info_network(Monitor *mon, const QDict *qdict)
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,19 +46,11 @@ index 0ac3b9e80c..7410c1e5f3 100644
|
||||
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 361700d37c..5e82933ca1 100644
|
||||
--- a/qapi-schema.json
|
||||
+++ b/qapi-schema.json
|
||||
@@ -56,6 +56,7 @@
|
||||
{ 'pragma': {
|
||||
# Commands allowed to return a non-dictionary:
|
||||
'returns-whitelist': [
|
||||
+ 'get_link_status',
|
||||
'human-monitor-command',
|
||||
'qom-get',
|
||||
'query-migrate-cache-size',
|
||||
@@ -2537,6 +2538,21 @@
|
||||
diff --git a/qapi/net.json b/qapi/net.json
|
||||
index 4beff5d582..73334c8f3c 100644
|
||||
--- a/qapi/net.json
|
||||
+++ b/qapi/net.json
|
||||
@@ -35,6 +35,21 @@
|
||||
{ 'command': 'set_link', 'data': {'name': 'str', 'up': 'bool'} }
|
||||
|
||||
##
|
||||
@ -77,9 +69,9 @@ index 361700d37c..5e82933ca1 100644
|
||||
+{ 'command': 'get_link_status', 'data': {'name': 'str'}, 'returns': 'int'}
|
||||
+
|
||||
+##
|
||||
# @balloon:
|
||||
# @netdev_add:
|
||||
#
|
||||
# Request the balloon driver to change its balloon size.
|
||||
# Add a network backend.
|
||||
--
|
||||
2.11.0
|
||||
|
||||
|
@ -9,10 +9,10 @@ Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
|
||||
index e96901435a..f049bbca9a 100644
|
||||
index 186545d2a4..603a7ce6bf 100644
|
||||
--- a/hw/i386/pc.c
|
||||
+++ b/hw/i386/pc.c
|
||||
@@ -2123,7 +2123,7 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms)
|
||||
@@ -2135,7 +2135,7 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms)
|
||||
if (tcg_enabled() || qtest_enabled()) {
|
||||
smm_available = true;
|
||||
} else if (kvm_enabled()) {
|
||||
|
@ -10,10 +10,10 @@ the version string, see PVE::QemuServer::kvm_user_version()
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/vl.c b/vl.c
|
||||
index 2132a77129..5d888cd179 100644
|
||||
index 1bfbe95b22..75fde82180 100644
|
||||
--- a/vl.c
|
||||
+++ b/vl.c
|
||||
@@ -1909,7 +1909,7 @@ static void main_loop(void)
|
||||
@@ -2006,7 +2006,7 @@ static void main_loop(void)
|
||||
|
||||
static void version(void)
|
||||
{
|
||||
|
@ -8,10 +8,10 @@ Subject: [PATCH] vnc: altgr emulation
|
||||
1 file changed, 25 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ui/vnc.c b/ui/vnc.c
|
||||
index b0314441c4..f30687884b 100644
|
||||
index 06abe7360e..03f8f61b2e 100644
|
||||
--- a/ui/vnc.c
|
||||
+++ b/ui/vnc.c
|
||||
@@ -1631,6 +1631,10 @@ static void kbd_leds(void *opaque, int ledstate)
|
||||
@@ -1775,6 +1775,10 @@ static void kbd_leds(void *opaque, int ledstate)
|
||||
|
||||
static void do_key_event(VncState *vs, int down, int keycode, int sym)
|
||||
{
|
||||
@ -22,7 +22,7 @@ index b0314441c4..f30687884b 100644
|
||||
/* QEMU console switch */
|
||||
switch(keycode) {
|
||||
case 0x2a: /* Left Shift */
|
||||
@@ -1711,8 +1715,27 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
|
||||
@@ -1855,8 +1859,27 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
|
||||
}
|
||||
|
||||
if (qemu_console_is_graphic(NULL)) {
|
||||
@ -50,7 +50,7 @@ index b0314441c4..f30687884b 100644
|
||||
} else {
|
||||
bool numlock = vs->modifiers_state[0x45];
|
||||
bool control = (vs->modifiers_state[0x1d] ||
|
||||
@@ -1852,7 +1875,8 @@ static void key_event(VncState *vs, int down, uint32_t sym)
|
||||
@@ -1996,7 +2019,8 @@ static void key_event(VncState *vs, int down, uint32_t sym)
|
||||
lsym = lsym - 'A' + 'a';
|
||||
}
|
||||
|
||||
|
@ -8,10 +8,10 @@ Subject: [PATCH] vnc: make x509 imply tls again
|
||||
1 file changed, 2 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/ui/vnc.c b/ui/vnc.c
|
||||
index f30687884b..a345bf0d78 100644
|
||||
index 03f8f61b2e..4494cb1dd4 100644
|
||||
--- a/ui/vnc.c
|
||||
+++ b/ui/vnc.c
|
||||
@@ -3881,9 +3881,8 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
@@ -4034,9 +4034,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);
|
||||
|
@ -4,21 +4,22 @@ Date: Mon, 11 Jan 2016 10:40:31 +0100
|
||||
Subject: [PATCH] vnc: PVE VNC authentication
|
||||
|
||||
---
|
||||
crypto/tlscreds.c | 47 +++++++++++
|
||||
crypto/tlscreds.c | 47 ++++++++++++
|
||||
crypto/tlscredspriv.h | 2 +
|
||||
crypto/tlscredsx509.c | 13 +--
|
||||
crypto/tlscredsx509.c | 13 ++--
|
||||
crypto/tlssession.c | 1 +
|
||||
include/crypto/tlscreds.h | 1 +
|
||||
include/ui/console.h | 1 +
|
||||
qapi-schema.json | 1 +
|
||||
qemu-options.hx | 3 +
|
||||
ui/vnc-auth-vencrypt.c | 197 ++++++++++++++++++++++++++++++++++++++--------
|
||||
ui/vnc.c | 140 +++++++++++++++++++++++++++++++-
|
||||
ui/vnc-auth-vencrypt.c | 182 ++++++++++++++++++++++++++++++++++++++--------
|
||||
ui/vnc.c | 140 ++++++++++++++++++++++++++++++++++-
|
||||
ui/vnc.h | 4 +
|
||||
vl.c | 9 +++
|
||||
11 files changed, 377 insertions(+), 41 deletions(-)
|
||||
12 files changed, 364 insertions(+), 40 deletions(-)
|
||||
|
||||
diff --git a/crypto/tlscreds.c b/crypto/tlscreds.c
|
||||
index a8965531b6..e9ae13ce47 100644
|
||||
index 3cd41035bb..e982da3451 100644
|
||||
--- a/crypto/tlscreds.c
|
||||
+++ b/crypto/tlscreds.c
|
||||
@@ -158,6 +158,33 @@ qcrypto_tls_creds_prop_get_verify(Object *obj,
|
||||
@ -75,7 +76,7 @@ index a8965531b6..e9ae13ce47 100644
|
||||
+ NULL);
|
||||
+ object_property_add_enum(obj, "endpoint",
|
||||
+ "QCryptoTLSCredsEndpoint",
|
||||
+ QCryptoTLSCredsEndpoint_lookup,
|
||||
+ &QCryptoTLSCredsEndpoint_lookup,
|
||||
+ qcrypto_tls_creds_prop_get_endpoint,
|
||||
+ qcrypto_tls_creds_prop_set_endpoint,
|
||||
+ NULL);
|
||||
@ -168,10 +169,10 @@ index ad47d88be7..f86d379f26 100644
|
||||
|
||||
|
||||
diff --git a/include/ui/console.h b/include/ui/console.h
|
||||
index d759338816..69f010e1db 100644
|
||||
index 580dfc57ee..383e5c88bd 100644
|
||||
--- a/include/ui/console.h
|
||||
+++ b/include/ui/console.h
|
||||
@@ -462,6 +462,7 @@ static inline void cocoa_display_init(DisplayState *ds, int full_screen)
|
||||
@@ -466,6 +466,7 @@ static inline void cocoa_display_init(DisplayState *ds, int full_screen)
|
||||
#endif
|
||||
|
||||
/* vnc.c */
|
||||
@ -179,11 +180,23 @@ index d759338816..69f010e1db 100644
|
||||
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/qapi-schema.json b/qapi-schema.json
|
||||
index 348b527681..d2155cb00f 100644
|
||||
--- a/qapi-schema.json
|
||||
+++ b/qapi-schema.json
|
||||
@@ -56,6 +56,7 @@
|
||||
{ 'pragma': {
|
||||
# Commands allowed to return a non-dictionary:
|
||||
'returns-whitelist': [
|
||||
+ 'get_link_status',
|
||||
'human-monitor-command',
|
||||
'qom-get',
|
||||
'query-migrate-cache-size',
|
||||
diff --git a/qemu-options.hx b/qemu-options.hx
|
||||
index cbcb27da9a..0b1957c034 100644
|
||||
index 7c054af8f9..07129d55bc 100644
|
||||
--- a/qemu-options.hx
|
||||
+++ b/qemu-options.hx
|
||||
@@ -513,6 +513,9 @@ STEXI
|
||||
@@ -583,6 +583,9 @@ STEXI
|
||||
@table @option
|
||||
ETEXI
|
||||
|
||||
@ -194,13 +207,13 @@ index cbcb27da9a..0b1957c034 100644
|
||||
"-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 ffaab57550..594ca737a9 100644
|
||||
index 7833631275..c42acd3714 100644
|
||||
--- a/ui/vnc-auth-vencrypt.c
|
||||
+++ b/ui/vnc-auth-vencrypt.c
|
||||
@@ -28,6 +28,108 @@
|
||||
#include "vnc.h"
|
||||
@@ -29,6 +29,108 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "trace.h"
|
||||
+#include "io/channel-socket.h"
|
||||
+
|
||||
+static int protocol_client_auth_plain(VncState *vs, uint8_t *data, size_t len)
|
||||
@ -228,7 +241,7 @@ index ffaab57550..594ca737a9 100644
|
||||
+
|
||||
+ VNC_DEBUG("AUTH PLAIN username: %s pw: %s\n", username, passwd);
|
||||
+
|
||||
+ if (pve_auth_verify(clientip->u.inet.data->host, username, passwd) == 0) {
|
||||
+ if (pve_auth_verify(clientip->u.inet.host, username, passwd) == 0) {
|
||||
+ vnc_write_u32(vs, 0); /* Accept auth completion */
|
||||
+ start_client_init(vs);
|
||||
+ qapi_free_SocketAddress(clientip);
|
||||
@ -323,21 +336,20 @@ index ffaab57550..594ca737a9 100644
|
||||
+
|
||||
case VNC_AUTH_VENCRYPT_TLSVNC:
|
||||
case VNC_AUTH_VENCRYPT_X509VNC:
|
||||
VNC_DEBUG("Start TLS auth VNC\n");
|
||||
@@ -88,45 +201,64 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len
|
||||
{
|
||||
start_auth_vnc(vs);
|
||||
@@ -90,45 +203,51 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len
|
||||
int auth = read_u32(data, 0);
|
||||
|
||||
trace_vnc_auth_vencrypt_subauth(vs, auth);
|
||||
- if (auth != vs->subauth) {
|
||||
+ if (auth != vs->subauth && auth != VNC_AUTH_VENCRYPT_PLAIN) {
|
||||
VNC_DEBUG("Rejecting auth %d\n", auth);
|
||||
trace_vnc_auth_fail(vs, vs->auth, "Unsupported sub-auth version", "");
|
||||
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);
|
||||
-
|
||||
@ -352,7 +364,6 @@ index ffaab57550..594ca737a9 100644
|
||||
+ {
|
||||
+ 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);
|
||||
|
||||
@ -362,7 +373,8 @@ index ffaab57550..594ca737a9 100644
|
||||
- vs->vd->tlsaclname,
|
||||
- &err);
|
||||
- if (!tls) {
|
||||
- VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
|
||||
- trace_vnc_auth_fail(vs, vs->auth, "TLS setup failed",
|
||||
- error_get_pretty(err));
|
||||
- error_free(err);
|
||||
- vnc_client_error(vs);
|
||||
- return 0;
|
||||
@ -371,46 +383,34 @@ index ffaab57550..594ca737a9 100644
|
||||
+ g_source_remove(vs->ioc_tag);
|
||||
+ vs->ioc_tag = 0;
|
||||
+ }
|
||||
|
||||
- qio_channel_set_name(QIO_CHANNEL(tls), "vnc-server-tls");
|
||||
- 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));
|
||||
+ trace_vnc_auth_fail(vs, vs->auth, "TLS setup failed",
|
||||
+ 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_set_name(QIO_CHANNEL(tls), "vnc-server-tls");
|
||||
- object_unref(OBJECT(vs->ioc));
|
||||
- vs->ioc = QIO_CHANNEL(tls);
|
||||
- trace_vnc_client_io_wrap(vs, vs->ioc, "tls");
|
||||
- vs->tls = qio_channel_tls_get_session(tls);
|
||||
+ qio_channel_set_name(QIO_CHANNEL(tls), "vnc-server-tls");
|
||||
+ object_unref(OBJECT(vs->ioc));
|
||||
+ vs->ioc = QIO_CHANNEL(tls);
|
||||
+ trace_vnc_client_io_wrap(vs, vs->ioc, "tls");
|
||||
+ vs->tls = qio_channel_tls_get_session(tls);
|
||||
|
||||
- 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,
|
||||
@ -419,12 +419,9 @@ index ffaab57550..594ca737a9 100644
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -140,10 +272,11 @@ static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len
|
||||
vnc_flush(vs);
|
||||
@@ -144,8 +263,9 @@ static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len
|
||||
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 */
|
||||
@ -434,10 +431,10 @@ index ffaab57550..594ca737a9 100644
|
||||
vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
|
||||
}
|
||||
diff --git a/ui/vnc.c b/ui/vnc.c
|
||||
index a345bf0d78..42db7e386b 100644
|
||||
index 4494cb1dd4..1589cbe1b3 100644
|
||||
--- a/ui/vnc.c
|
||||
+++ b/ui/vnc.c
|
||||
@@ -56,6 +56,125 @@ static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
|
||||
@@ -55,6 +55,125 @@ static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
|
||||
#include "vnc_keysym.h"
|
||||
#include "crypto/cipher.h"
|
||||
|
||||
@ -563,7 +560,7 @@ index a345bf0d78..42db7e386b 100644
|
||||
static QTAILQ_HEAD(, VncDisplay) vnc_displays =
|
||||
QTAILQ_HEAD_INITIALIZER(vnc_displays);
|
||||
|
||||
@@ -3356,10 +3475,16 @@ vnc_display_setup_auth(int *auth,
|
||||
@@ -3507,10 +3626,16 @@ vnc_display_setup_auth(int *auth,
|
||||
if (password) {
|
||||
if (is_x509) {
|
||||
VNC_DEBUG("Initializing VNC server with x509 password auth\n");
|
||||
@ -582,7 +579,7 @@ index a345bf0d78..42db7e386b 100644
|
||||
}
|
||||
|
||||
} else if (sasl) {
|
||||
@@ -3393,6 +3518,7 @@ vnc_display_create_creds(bool x509,
|
||||
@@ -3544,6 +3669,7 @@ vnc_display_create_creds(bool x509,
|
||||
bool x509verify,
|
||||
const char *dir,
|
||||
const char *id,
|
||||
@ -590,7 +587,7 @@ index a345bf0d78..42db7e386b 100644
|
||||
Error **errp)
|
||||
{
|
||||
gchar *credsid = g_strdup_printf("tlsvnc%s", id);
|
||||
@@ -3408,6 +3534,7 @@ vnc_display_create_creds(bool x509,
|
||||
@@ -3559,6 +3685,7 @@ vnc_display_create_creds(bool x509,
|
||||
"endpoint", "server",
|
||||
"dir", dir,
|
||||
"verify-peer", x509verify ? "yes" : "no",
|
||||
@ -598,7 +595,7 @@ index a345bf0d78..42db7e386b 100644
|
||||
NULL);
|
||||
} else {
|
||||
creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_ANON,
|
||||
@@ -3415,6 +3542,7 @@ vnc_display_create_creds(bool x509,
|
||||
@@ -3566,6 +3693,7 @@ vnc_display_create_creds(bool x509,
|
||||
credsid,
|
||||
&err,
|
||||
"endpoint", "server",
|
||||
@ -606,7 +603,7 @@ index a345bf0d78..42db7e386b 100644
|
||||
NULL);
|
||||
}
|
||||
|
||||
@@ -3879,12 +4007,17 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
@@ -4032,12 +4160,17 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
}
|
||||
} else {
|
||||
const char *path;
|
||||
@ -625,7 +622,7 @@ index a345bf0d78..42db7e386b 100644
|
||||
} else {
|
||||
path = qemu_opt_get(opts, "x509verify");
|
||||
if (path) {
|
||||
@@ -3896,6 +4029,7 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
@@ -4049,6 +4182,7 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
x509verify,
|
||||
path,
|
||||
vd->id,
|
||||
@ -634,10 +631,10 @@ index a345bf0d78..42db7e386b 100644
|
||||
if (!vd->tlscreds) {
|
||||
goto fail;
|
||||
diff --git a/ui/vnc.h b/ui/vnc.h
|
||||
index 694cf32ca9..78d622ab84 100644
|
||||
index bbda0540a7..8cc6367ed3 100644
|
||||
--- a/ui/vnc.h
|
||||
+++ b/ui/vnc.h
|
||||
@@ -284,6 +284,8 @@ struct VncState
|
||||
@@ -290,6 +290,8 @@ struct VncState
|
||||
int auth;
|
||||
int subauth; /* Used by VeNCrypt */
|
||||
char challenge[VNC_AUTH_CHALLENGE_SIZE];
|
||||
@ -646,7 +643,7 @@ index 694cf32ca9..78d622ab84 100644
|
||||
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);
|
||||
@@ -595,4 +597,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);
|
||||
|
||||
@ -654,10 +651,10 @@ index 694cf32ca9..78d622ab84 100644
|
||||
+
|
||||
#endif /* QEMU_VNC_H */
|
||||
diff --git a/vl.c b/vl.c
|
||||
index 5d888cd179..1000a4a259 100644
|
||||
index 75fde82180..255d989009 100644
|
||||
--- a/vl.c
|
||||
+++ b/vl.c
|
||||
@@ -2947,6 +2947,7 @@ static int qemu_read_default_config_file(void)
|
||||
@@ -3096,6 +3096,7 @@ static void register_global_properties(MachineState *ms)
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
int i;
|
||||
@ -665,7 +662,7 @@ index 5d888cd179..1000a4a259 100644
|
||||
int snapshot, linux_boot;
|
||||
const char *initrd_filename;
|
||||
const char *kernel_filename, *kernel_cmdline;
|
||||
@@ -3778,6 +3779,14 @@ int main(int argc, char **argv, char **envp)
|
||||
@@ -3922,6 +3923,14 @@ int main(int argc, char **argv, char **envp)
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
@ -10,10 +10,10 @@ Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/block/rbd.c b/block/rbd.c
|
||||
index 2354ffcc64..b7700648ff 100644
|
||||
index a76a5e8755..a33738a254 100644
|
||||
--- a/block/rbd.c
|
||||
+++ b/block/rbd.c
|
||||
@@ -623,6 +623,10 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
@@ -642,6 +642,10 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
rados_conf_set(s->cluster, "rbd_cache", "true");
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 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] migrate: 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 feb0dc6834..d2615f4620 100644
|
||||
--- a/migration/savevm.c
|
||||
+++ b/migration/savevm.c
|
||||
@@ -1111,7 +1111,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.11.0
|
||||
|
@ -9,7 +9,7 @@ Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
|
||||
1 file changed, 11 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/savevm-async.c b/savevm-async.c
|
||||
index 97d51d3edd..ece193a065 100644
|
||||
index 96523c88ae..06dcd29fc7 100644
|
||||
--- a/savevm-async.c
|
||||
+++ b/savevm-async.c
|
||||
@@ -377,6 +377,7 @@ void qmp_snapshot_drive(const char *device, const char *name, Error **errp)
|
@ -11,7 +11,7 @@ Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
|
||||
1 file changed, 10 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/savevm-async.c b/savevm-async.c
|
||||
index ece193a065..716dd2d7a1 100644
|
||||
index 06dcd29fc7..e6f86ef865 100644
|
||||
--- a/savevm-async.c
|
||||
+++ b/savevm-async.c
|
||||
@@ -459,6 +459,7 @@ void qmp_delete_drive_snapshot(const char *device, const char *name,
|
@ -8,10 +8,10 @@ Subject: [PATCH] glusterfs: no default logfile if daemonized
|
||||
1 file changed, 11 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/block/gluster.c b/block/gluster.c
|
||||
index cf29b5f9a4..bc44c50db0 100644
|
||||
index 0f4265a3a4..8fab26481c 100644
|
||||
--- a/block/gluster.c
|
||||
+++ b/block/gluster.c
|
||||
@@ -33,7 +33,7 @@
|
||||
@@ -32,7 +32,7 @@
|
||||
#define GLUSTER_DEBUG_DEFAULT 4
|
||||
#define GLUSTER_DEBUG_MAX 9
|
||||
#define GLUSTER_OPT_LOGFILE "logfile"
|
||||
@ -20,15 +20,15 @@ index cf29b5f9a4..bc44c50db0 100644
|
||||
|
||||
#define GERR_INDEX_HINT "hint: check in 'server' array index '%d'\n"
|
||||
|
||||
@@ -398,6 +398,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
|
||||
@@ -396,6 +396,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
|
||||
int old_errno;
|
||||
SocketAddressFlatList *server;
|
||||
SocketAddressList *server;
|
||||
unsigned long long port;
|
||||
+ const char *logfile;
|
||||
|
||||
glfs = glfs_find_preopened(gconf->volume);
|
||||
if (glfs) {
|
||||
@@ -440,9 +441,15 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
|
||||
@@ -438,9 +439,15 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
|
||||
}
|
||||
}
|
||||
|
@ -14,10 +14,10 @@ sense.
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/block/gluster.c b/block/gluster.c
|
||||
index bc44c50db0..4fdf68f1fc 100644
|
||||
index 8fab26481c..24296a39b3 100644
|
||||
--- a/block/gluster.c
|
||||
+++ b/block/gluster.c
|
||||
@@ -42,6 +42,7 @@ typedef struct GlusterAIOCB {
|
||||
@@ -41,6 +41,7 @@ typedef struct GlusterAIOCB {
|
||||
int ret;
|
||||
Coroutine *coroutine;
|
||||
AioContext *aio_context;
|
||||
@ -25,7 +25,7 @@ index bc44c50db0..4fdf68f1fc 100644
|
||||
} GlusterAIOCB;
|
||||
|
||||
typedef struct BDRVGlusterState {
|
||||
@@ -713,8 +714,10 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
|
||||
@@ -709,8 +710,10 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
|
||||
acb->ret = 0; /* Success */
|
||||
} else if (ret < 0) {
|
||||
acb->ret = -errno; /* Read/Write failed */
|
||||
@ -37,7 +37,7 @@ index bc44c50db0..4fdf68f1fc 100644
|
||||
}
|
||||
|
||||
aio_co_schedule(acb->aio_context, acb->coroutine);
|
||||
@@ -962,6 +965,7 @@ static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
@@ -958,6 +961,7 @@ static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
acb.ret = 0;
|
||||
acb.coroutine = qemu_coroutine_self();
|
||||
acb.aio_context = bdrv_get_aio_context(bs);
|
||||
@ -45,7 +45,7 @@ index bc44c50db0..4fdf68f1fc 100644
|
||||
|
||||
ret = glfs_zerofill_async(s->fd, offset, size, gluster_finish_aiocb, &acb);
|
||||
if (ret < 0) {
|
||||
@@ -1084,9 +1088,11 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
|
||||
@@ -1083,9 +1087,11 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
|
||||
acb.aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
if (write) {
|
||||
@ -57,7 +57,7 @@ index bc44c50db0..4fdf68f1fc 100644
|
||||
ret = glfs_preadv_async(s->fd, qiov->iov, qiov->niov, offset, 0,
|
||||
gluster_finish_aiocb, &acb);
|
||||
}
|
||||
@@ -1150,6 +1156,7 @@ static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
|
||||
@@ -1158,6 +1164,7 @@ static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
|
||||
acb.ret = 0;
|
||||
acb.coroutine = qemu_coroutine_self();
|
||||
acb.aio_context = bdrv_get_aio_context(bs);
|
||||
@ -65,7 +65,7 @@ index bc44c50db0..4fdf68f1fc 100644
|
||||
|
||||
ret = glfs_fsync_async(s->fd, gluster_finish_aiocb, &acb);
|
||||
if (ret < 0) {
|
||||
@@ -1196,6 +1203,7 @@ static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs,
|
||||
@@ -1204,6 +1211,7 @@ static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs,
|
||||
acb.ret = 0;
|
||||
acb.coroutine = qemu_coroutine_self();
|
||||
acb.aio_context = bdrv_get_aio_context(bs);
|
@ -5,15 +5,15 @@ Subject: [PATCH] block: add the zeroinit block driver filter
|
||||
|
||||
---
|
||||
block/Makefile.objs | 1 +
|
||||
block/zeroinit.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 221 insertions(+)
|
||||
block/zeroinit.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 203 insertions(+)
|
||||
create mode 100644 block/zeroinit.c
|
||||
|
||||
diff --git a/block/Makefile.objs b/block/Makefile.objs
|
||||
index de96f8ee80..8cdac08db5 100644
|
||||
index 6eaf78a046..823e60cda6 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
|
||||
@@ -4,6 +4,7 @@ block-obj-y += qed.o qed-l2-cache.o qed-table.o qed-cluster.o
|
||||
block-obj-y += qed-check.o
|
||||
block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
|
||||
block-obj-y += quorum.o
|
||||
@ -23,10 +23,10 @@ index de96f8ee80..8cdac08db5 100644
|
||||
block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
|
||||
diff --git a/block/zeroinit.c b/block/zeroinit.c
|
||||
new file mode 100644
|
||||
index 0000000000..305185512e
|
||||
index 0000000000..37f588f75c
|
||||
--- /dev/null
|
||||
+++ b/block/zeroinit.c
|
||||
@@ -0,0 +1,220 @@
|
||||
@@ -0,0 +1,202 @@
|
||||
+/*
|
||||
+ * Filter to fake a zero-initialized block device.
|
||||
+ *
|
||||
@ -134,12 +134,10 @@ index 0000000000..305185512e
|
||||
+ 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)
|
||||
+static int coroutine_fn zeroinit_co_preadv(BlockDriverState *bs,
|
||||
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
+{
|
||||
+ return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors,
|
||||
+ cb, opaque);
|
||||
+ return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
|
||||
+}
|
||||
+
|
||||
+static int coroutine_fn zeroinit_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
||||
@ -151,23 +149,14 @@ index 0000000000..305185512e
|
||||
+ 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)
|
||||
+static int coroutine_fn zeroinit_co_pwritev(BlockDriverState *bs,
|
||||
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
+{
|
||||
+ BDRVZeroinitState *s = bs->opaque;
|
||||
+ int64_t extents = (sector_num << BDRV_SECTOR_BITS) + ((nb_sectors + 1) << BDRV_SECTOR_BITS);
|
||||
+ int64_t extents = offset + bytes;
|
||||
+ 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);
|
||||
+ return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
|
||||
+}
|
||||
+
|
||||
+static bool zeroinit_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
@ -187,23 +176,16 @@ index 0000000000..305185512e
|
||||
+ 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 int coroutine_fn zeroinit_co_pdiscard(BlockDriverState *bs,
|
||||
+ int64_t offset, int count)
|
||||
+{
|
||||
+ return bdrv_co_pdiscard(bs->file->bs, offset, count);
|
||||
+}
|
||||
+
|
||||
+static int zeroinit_truncate(BlockDriverState *bs, int64_t offset)
|
||||
+static int zeroinit_truncate(BlockDriverState *bs, int64_t offset,
|
||||
+ PreallocMode prealloc, Error **errp)
|
||||
+{
|
||||
+ return bdrv_truncate(bs->file, offset, NULL);
|
||||
+ return bdrv_truncate(bs->file, offset, prealloc, errp);
|
||||
+}
|
||||
+
|
||||
+static int zeroinit_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
@ -224,16 +206,16 @@ index 0000000000..305185512e
|
||||
+ .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,
|
||||
+ .bdrv_co_pwritev = zeroinit_co_pwritev,
|
||||
+ .bdrv_co_preadv = zeroinit_co_preadv,
|
||||
+ .bdrv_co_flush = zeroinit_co_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_co_get_block_status = bdrv_co_get_block_status_from_file,
|
||||
+
|
||||
+ .bdrv_co_pdiscard = zeroinit_co_pdiscard,
|
||||
+
|
@ -31,30 +31,30 @@ override the output file's size.
|
||||
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
---
|
||||
qemu-img-cmds.hx | 4 +-
|
||||
qemu-img.c | 176 +++++++++++++++++++++++++++++++++++--------------------
|
||||
2 files changed, 115 insertions(+), 65 deletions(-)
|
||||
qemu-img.c | 192 ++++++++++++++++++++++++++++++++++---------------------
|
||||
2 files changed, 122 insertions(+), 74 deletions(-)
|
||||
|
||||
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
|
||||
index 8ac78222af..16bee83987 100644
|
||||
index 2fe31893cf..52042f2773 100644
|
||||
--- a/qemu-img-cmds.hx
|
||||
+++ b/qemu-img-cmds.hx
|
||||
@@ -46,9 +46,9 @@ STEXI
|
||||
@@ -53,9 +53,9 @@ STEXI
|
||||
ETEXI
|
||||
|
||||
DEF("dd", img_dd,
|
||||
- "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] if=input of=output")
|
||||
+ "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] [osize=output_size] [if=input] [of=output]")
|
||||
- "dd [--image-opts] [-U] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] if=input of=output")
|
||||
+ "dd [--image-opts] [-U] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] [osize=output_size] if=input of=output")
|
||||
STEXI
|
||||
-@item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] if=@var{input} of=@var{output}
|
||||
+@item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] [osize=output_size] [if=@var{input}] [of=@var{output}]
|
||||
-@item dd [--image-opts] [-U] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] if=@var{input} of=@var{output}
|
||||
+@item dd [--image-opts] [-U] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] [osize=output_size] if=@var{input} of=@var{output}
|
||||
ETEXI
|
||||
|
||||
DEF("info", img_info,
|
||||
diff --git a/qemu-img.c b/qemu-img.c
|
||||
index c7804d63ee..ee7816e727 100644
|
||||
index f8a39dd195..876a3623a7 100644
|
||||
--- a/qemu-img.c
|
||||
+++ b/qemu-img.c
|
||||
@@ -4026,10 +4026,12 @@ out:
|
||||
@@ -4088,10 +4088,12 @@ out:
|
||||
#define C_IF 04
|
||||
#define C_OF 010
|
||||
#define C_SKIP 020
|
||||
@ -67,7 +67,7 @@ index c7804d63ee..ee7816e727 100644
|
||||
};
|
||||
|
||||
struct DdIo {
|
||||
@@ -4108,6 +4110,20 @@ static int img_dd_skip(const char *arg,
|
||||
@@ -4170,6 +4172,20 @@ static int img_dd_skip(const char *arg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ index c7804d63ee..ee7816e727 100644
|
||||
static int img_dd(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -4147,6 +4163,7 @@ static int img_dd(int argc, char **argv)
|
||||
@@ -4210,6 +4226,7 @@ static int img_dd(int argc, char **argv)
|
||||
{ "if", img_dd_if, C_IF },
|
||||
{ "of", img_dd_of, C_OF },
|
||||
{ "skip", img_dd_skip, C_SKIP },
|
||||
@ -96,7 +96,7 @@ index c7804d63ee..ee7816e727 100644
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
const struct option long_options[] = {
|
||||
@@ -4214,84 +4231,106 @@ static int img_dd(int argc, char **argv)
|
||||
@@ -4288,8 +4305,13 @@ static int img_dd(int argc, char **argv)
|
||||
arg = NULL;
|
||||
}
|
||||
|
||||
@ -104,42 +104,25 @@ index c7804d63ee..ee7816e727 100644
|
||||
- error_report("Must specify both input and output files");
|
||||
+ if (!(dd.flags & C_IF) && (!fmt || strcmp(fmt, "raw") != 0)) {
|
||||
+ error_report("Input format must be raw when readin from stdin");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
- blk1 = img_open(image_opts, in.filename, fmt, 0, false, false);
|
||||
-
|
||||
- if (!blk1) {
|
||||
+ ret = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (!(dd.flags & C_OF) && strcmp(out_fmt, "raw") != 0) {
|
||||
+ error_report("Output format must be raw when writing to stdout");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
+ if (dd.flags & C_IF) {
|
||||
+ blk1 = img_open(image_opts, in.filename, fmt, 0, false, false);
|
||||
@@ -4301,85 +4323,101 @@ static int img_dd(int argc, char **argv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
- drv = bdrv_find_format(out_fmt);
|
||||
- if (!drv) {
|
||||
- error_report("Unknown file format");
|
||||
- ret = -1;
|
||||
- goto out;
|
||||
- }
|
||||
- proto_drv = bdrv_find_protocol(out.filename, true, &local_err);
|
||||
-
|
||||
- if (!proto_drv) {
|
||||
- error_report_err(local_err);
|
||||
- ret = -1;
|
||||
- goto out;
|
||||
- }
|
||||
- if (!drv->create_opts) {
|
||||
- error_report("Format driver '%s' does not support image creation",
|
||||
- drv->format_name);
|
||||
- ret = -1;
|
||||
- goto out;
|
||||
- }
|
||||
- if (!proto_drv->create_opts) {
|
||||
- error_report("Protocol driver '%s' does not support image creation",
|
||||
- proto_drv->format_name);
|
||||
- blk1 = img_open(image_opts, in.filename, fmt, 0, false, false,
|
||||
- force_share);
|
||||
+ if (dd.flags & C_IF) {
|
||||
+ blk1 = img_open(image_opts, in.filename, fmt, 0, false, false,
|
||||
+ force_share);
|
||||
|
||||
- if (!blk1) {
|
||||
- ret = -1;
|
||||
- goto out;
|
||||
+ if (!blk1) {
|
||||
@ -147,14 +130,10 @@ index c7804d63ee..ee7816e727 100644
|
||||
+ goto out;
|
||||
+ }
|
||||
}
|
||||
- create_opts = qemu_opts_append(create_opts, drv->create_opts);
|
||||
- create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
|
||||
-
|
||||
- opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
|
||||
|
||||
- size = blk_getlength(blk1);
|
||||
- if (size < 0) {
|
||||
- error_report("Failed to get size for '%s'", in.filename);
|
||||
- drv = bdrv_find_format(out_fmt);
|
||||
- if (!drv) {
|
||||
- error_report("Unknown file format");
|
||||
+ if (dd.flags & C_OSIZE) {
|
||||
+ size = dd.osize;
|
||||
+ } else if (dd.flags & C_IF) {
|
||||
@ -171,30 +150,32 @@ index c7804d63ee..ee7816e727 100644
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
- proto_drv = bdrv_find_protocol(out.filename, true, &local_err);
|
||||
|
||||
- if (dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
|
||||
+ if (!(dd.flags & C_OSIZE) && dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
|
||||
dd.count * in.bsz < size) {
|
||||
size = dd.count * in.bsz;
|
||||
}
|
||||
|
||||
- /* Overflow means the specified offset is beyond input image's size */
|
||||
- if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
|
||||
- size < in.bsz * in.offset)) {
|
||||
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort);
|
||||
- } else {
|
||||
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
|
||||
- size - in.bsz * in.offset, &error_abort);
|
||||
- }
|
||||
|
||||
- ret = bdrv_create(drv, out.filename, opts, &local_err);
|
||||
- if (ret < 0) {
|
||||
- error_reportf_err(local_err,
|
||||
- "%s: error while creating output image: ",
|
||||
- out.filename);
|
||||
- if (!proto_drv) {
|
||||
- error_report_err(local_err);
|
||||
- ret = -1;
|
||||
- goto out;
|
||||
- }
|
||||
- if (!drv->create_opts) {
|
||||
- error_report("Format driver '%s' does not support image creation",
|
||||
- drv->format_name);
|
||||
- ret = -1;
|
||||
- goto out;
|
||||
- }
|
||||
- if (!proto_drv->create_opts) {
|
||||
- error_report("Protocol driver '%s' does not support image creation",
|
||||
- proto_drv->format_name);
|
||||
- ret = -1;
|
||||
- goto out;
|
||||
+ if (!(dd.flags & C_OSIZE) && dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
|
||||
+ dd.count * in.bsz < size) {
|
||||
+ size = dd.count * in.bsz;
|
||||
}
|
||||
- create_opts = qemu_opts_append(create_opts, drv->create_opts);
|
||||
- create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
|
||||
|
||||
- opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
|
||||
+ if (dd.flags & C_OF) {
|
||||
+ drv = bdrv_find_format(out_fmt);
|
||||
+ if (!drv) {
|
||||
@ -203,7 +184,13 @@ index c7804d63ee..ee7816e727 100644
|
||||
+ goto out;
|
||||
+ }
|
||||
+ proto_drv = bdrv_find_protocol(out.filename, true, &local_err);
|
||||
+
|
||||
|
||||
- size = blk_getlength(blk1);
|
||||
- if (size < 0) {
|
||||
- error_report("Failed to get size for '%s'", in.filename);
|
||||
- ret = -1;
|
||||
- goto out;
|
||||
- }
|
||||
+ if (!proto_drv) {
|
||||
+ error_report_err(local_err);
|
||||
+ ret = -1;
|
||||
@ -224,24 +211,39 @@ index c7804d63ee..ee7816e727 100644
|
||||
+ create_opts = qemu_opts_append(create_opts, drv->create_opts);
|
||||
+ create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
|
||||
|
||||
- blk2 = img_open(image_opts, out.filename, out_fmt, BDRV_O_RDWR,
|
||||
- false, false);
|
||||
- if (dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
|
||||
- dd.count * in.bsz < size) {
|
||||
- size = dd.count * in.bsz;
|
||||
- }
|
||||
+ opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
|
||||
|
||||
- if (!blk2) {
|
||||
- ret = -1;
|
||||
- goto out;
|
||||
- /* Overflow means the specified offset is beyond input image's size */
|
||||
- if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
|
||||
- size < in.bsz * in.offset)) {
|
||||
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort);
|
||||
- } else {
|
||||
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
|
||||
- size - in.bsz * in.offset, &error_abort);
|
||||
- }
|
||||
+ /* Overflow means the specified offset is beyond input image's size */
|
||||
+ if (dd.flags & C_OSIZE) {
|
||||
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size, &error_abort);
|
||||
+ } else if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
|
||||
+ size < in.bsz * in.offset)) {
|
||||
+ size < in.bsz * in.offset)) {
|
||||
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort);
|
||||
+ } else {
|
||||
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
|
||||
+ size - in.bsz * in.offset, &error_abort);
|
||||
+ }
|
||||
+
|
||||
|
||||
- ret = bdrv_create(drv, out.filename, opts, &local_err);
|
||||
- if (ret < 0) {
|
||||
- error_reportf_err(local_err,
|
||||
- "%s: error while creating output image: ",
|
||||
- out.filename);
|
||||
- ret = -1;
|
||||
- goto out;
|
||||
- }
|
||||
+ ret = bdrv_create(drv, out.filename, opts, &local_err);
|
||||
+ if (ret < 0) {
|
||||
+ error_reportf_err(local_err,
|
||||
@ -250,10 +252,25 @@ index c7804d63ee..ee7816e727 100644
|
||||
+ ret = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ blk2 = img_open(image_opts, out.filename, out_fmt, BDRV_O_RDWR,
|
||||
+ false, false);
|
||||
+
|
||||
|
||||
- /* TODO, we can't honour --image-opts for the target,
|
||||
- * since it needs to be given in a format compatible
|
||||
- * with the bdrv_create() call above which does not
|
||||
- * support image-opts style.
|
||||
- */
|
||||
- blk2 = img_open_file(out.filename, NULL, out_fmt, BDRV_O_RDWR,
|
||||
- false, false, false);
|
||||
+ /* TODO, we can't honour --image-opts for the target,
|
||||
+ * since it needs to be given in a format compatible
|
||||
+ * with the bdrv_create() call above which does not
|
||||
+ * support image-opts style.
|
||||
+ */
|
||||
+ blk2 = img_open_file(out.filename, NULL, out_fmt, BDRV_O_RDWR,
|
||||
+ false, false, false);
|
||||
|
||||
- if (!blk2) {
|
||||
- ret = -1;
|
||||
- goto out;
|
||||
+ if (!blk2) {
|
||||
+ ret = -1;
|
||||
+ goto out;
|
||||
@ -261,14 +278,14 @@ index c7804d63ee..ee7816e727 100644
|
||||
}
|
||||
|
||||
if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
|
||||
@@ -4309,11 +4348,18 @@ static int img_dd(int argc, char **argv)
|
||||
@@ -4397,11 +4435,17 @@ static int img_dd(int argc, char **argv)
|
||||
|
||||
for (out_pos = 0; in_pos < size; block_count++) {
|
||||
int in_ret, out_ret;
|
||||
+ size_t in_bsz = in_pos + in.bsz > size ? size - in_pos : in.bsz;
|
||||
|
||||
-
|
||||
- if (in_pos + in.bsz > size) {
|
||||
- in_ret = blk_pread(blk1, in_pos, in.buf, size - in_pos);
|
||||
+ size_t in_bsz = in_pos + in.bsz > size ? size - in_pos : in.bsz;
|
||||
+ if (blk1) {
|
||||
+ in_ret = blk_pread(blk1, in_pos, in.buf, in_bsz);
|
||||
} else {
|
||||
@ -283,7 +300,7 @@ index c7804d63ee..ee7816e727 100644
|
||||
}
|
||||
if (in_ret < 0) {
|
||||
error_report("error while reading from input image file: %s",
|
||||
@@ -4323,9 +4369,13 @@ static int img_dd(int argc, char **argv)
|
||||
@@ -4411,9 +4455,13 @@ static int img_dd(int argc, char **argv)
|
||||
}
|
||||
in_pos += in_ret;
|
||||
|
@ -16,10 +16,10 @@ having been started at the same point in time.
|
||||
5 files changed, 7 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/block/backup.c b/block/backup.c
|
||||
index a4fb2884f9..1ede70c061 100644
|
||||
index 99e6bcc748..8c2967a8cb 100644
|
||||
--- a/block/backup.c
|
||||
+++ b/block/backup.c
|
||||
@@ -558,6 +558,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
@@ -539,6 +539,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
BlockdevOnError on_target_error,
|
||||
int creation_flags,
|
||||
BlockCompletionFunc *cb, void *opaque,
|
||||
@ -27,7 +27,7 @@ index a4fb2884f9..1ede70c061 100644
|
||||
BlockJobTxn *txn, Error **errp)
|
||||
{
|
||||
int64_t len;
|
||||
@@ -682,6 +683,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
@@ -663,6 +664,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
|
||||
&error_abort);
|
||||
job->common.len = len;
|
||||
@ -36,10 +36,10 @@ index a4fb2884f9..1ede70c061 100644
|
||||
|
||||
return &job->common;
|
||||
diff --git a/block/replication.c b/block/replication.c
|
||||
index bf3c395eb4..1c41d9e6bf 100644
|
||||
index e41e293d2b..1b08b242eb 100644
|
||||
--- a/block/replication.c
|
||||
+++ b/block/replication.c
|
||||
@@ -531,7 +531,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
||||
@@ -561,7 +561,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
||||
0, MIRROR_SYNC_MODE_NONE, NULL, false,
|
||||
BLOCKDEV_ON_ERROR_REPORT,
|
||||
BLOCKDEV_ON_ERROR_REPORT, BLOCK_JOB_INTERNAL,
|
||||
@ -49,10 +49,10 @@ index bf3c395eb4..1c41d9e6bf 100644
|
||||
error_propagate(errp, local_err);
|
||||
backup_job_cleanup(bs);
|
||||
diff --git a/blockdev.c b/blockdev.c
|
||||
index e8a9a65167..9b6cfafd33 100644
|
||||
index 56a6b24a0b..a9ed9034b5 100644
|
||||
--- a/blockdev.c
|
||||
+++ b/blockdev.c
|
||||
@@ -3262,7 +3262,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
|
||||
@@ -3293,7 +3293,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
|
||||
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
|
||||
backup->sync, bmap, backup->compress,
|
||||
backup->on_source_error, backup->on_target_error,
|
||||
@ -61,7 +61,7 @@ index e8a9a65167..9b6cfafd33 100644
|
||||
bdrv_unref(target_bs);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
@@ -3341,7 +3341,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
|
||||
@@ -3372,7 +3372,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
|
||||
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
|
||||
backup->sync, NULL, backup->compress,
|
||||
backup->on_source_error, backup->on_target_error,
|
||||
@ -71,10 +71,10 @@ index e8a9a65167..9b6cfafd33 100644
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
diff --git a/blockjob.c b/blockjob.c
|
||||
index 6e489327ff..764d41863e 100644
|
||||
index 715c2c2680..c1b6b6a810 100644
|
||||
--- a/blockjob.c
|
||||
+++ b/blockjob.c
|
||||
@@ -289,7 +289,7 @@ void block_job_start(BlockJob *job)
|
||||
@@ -322,7 +322,7 @@ void block_job_start(BlockJob *job)
|
||||
job->co = qemu_coroutine_create(block_job_co_entry, job);
|
||||
job->pause_count--;
|
||||
job->busy = true;
|
||||
@ -84,10 +84,10 @@ index 6e489327ff..764d41863e 100644
|
||||
}
|
||||
|
||||
diff --git a/include/block/block_int.h b/include/block/block_int.h
|
||||
index 89d7b458e7..19b84b027f 100644
|
||||
index a5482775ec..1dbbdafd31 100644
|
||||
--- a/include/block/block_int.h
|
||||
+++ b/include/block/block_int.h
|
||||
@@ -879,6 +879,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
@@ -985,6 +985,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
BlockdevOnError on_target_error,
|
||||
int creation_flags,
|
||||
BlockCompletionFunc *cb, void *opaque,
|
@ -6,23 +6,23 @@ Subject: [PATCH] backup: introduce vma archive format
|
||||
---
|
||||
MAINTAINERS | 6 +
|
||||
block/Makefile.objs | 3 +
|
||||
block/vma.c | 424 +++++++++++++++++++++++++++++++++++++++++++
|
||||
blockdev.c | 498 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
configure | 30 ++++
|
||||
block/vma.c | 424 ++++++++++++++++++++++++++++++++++++++++
|
||||
blockdev.c | 536 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
blockjob.c | 3 +-
|
||||
configure | 30 +++
|
||||
hmp-commands-info.hx | 13 ++
|
||||
hmp-commands.hx | 31 ++++
|
||||
hmp.c | 63 +++++++
|
||||
hmp-commands.hx | 31 +++
|
||||
hmp.c | 63 ++++++
|
||||
hmp.h | 3 +
|
||||
qapi-schema.json | 91 ++++++++++
|
||||
qapi/block-core.json | 20 ++-
|
||||
11 files changed, 1180 insertions(+), 2 deletions(-)
|
||||
qapi/block-core.json | 109 ++++++++++-
|
||||
11 files changed, 1219 insertions(+), 2 deletions(-)
|
||||
create mode 100644 block/vma.c
|
||||
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index 430efb0ab7..6a7d338aad 100644
|
||||
index 0255113470..581d80d144 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -1811,6 +1811,12 @@ L: qemu-block@nongnu.org
|
||||
@@ -1950,6 +1950,12 @@ L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/vvfat.c
|
||||
|
||||
@ -36,18 +36,18 @@ index 430efb0ab7..6a7d338aad 100644
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
diff --git a/block/Makefile.objs b/block/Makefile.objs
|
||||
index 8cdac08db5..6df5567dd3 100644
|
||||
index 823e60cda6..d74140e413 100644
|
||||
--- a/block/Makefile.objs
|
||||
+++ b/block/Makefile.objs
|
||||
@@ -21,6 +21,7 @@ block-obj-$(CONFIG_CURL) += curl.o
|
||||
block-obj-$(CONFIG_RBD) += rbd.o
|
||||
@@ -22,6 +22,7 @@ block-obj-$(CONFIG_RBD) += rbd.o
|
||||
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
|
||||
block-obj-$(CONFIG_VXHS) += vxhs.o
|
||||
block-obj-$(CONFIG_LIBSSH2) += ssh.o
|
||||
+block-obj-$(CONFIG_VMA) += vma.o
|
||||
block-obj-y += accounting.o dirty-bitmap.o
|
||||
block-obj-y += write-threshold.o
|
||||
block-obj-y += backup.o
|
||||
@@ -45,3 +46,5 @@ block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
|
||||
@@ -48,3 +49,5 @@ block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
|
||||
dmg-bz2.o-libs := $(BZIP2_LIBS)
|
||||
qcow.o-libs := -lz
|
||||
linux-aio.o-libs := -laio
|
||||
@ -484,7 +484,7 @@ index 0000000000..7151514f94
|
||||
+
|
||||
+block_init(bdrv_vma_init);
|
||||
diff --git a/blockdev.c b/blockdev.c
|
||||
index 9b6cfafd33..534c00f5da 100644
|
||||
index a9ed9034b5..3ffd064c48 100644
|
||||
--- a/blockdev.c
|
||||
+++ b/blockdev.c
|
||||
@@ -31,10 +31,12 @@
|
||||
@ -500,7 +500,7 @@ index 9b6cfafd33..534c00f5da 100644
|
||||
#include "block/throttle-groups.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "qemu/error-report.h"
|
||||
@@ -2932,6 +2934,502 @@ out:
|
||||
@@ -2963,6 +2965,540 @@ out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
@ -521,6 +521,8 @@ index 9b6cfafd33..534c00f5da 100644
|
||||
+ size_t total;
|
||||
+ size_t transferred;
|
||||
+ size_t zero_bytes;
|
||||
+ QemuMutex backup_mutex;
|
||||
+ bool backup_mutex_initialized;
|
||||
+} backup_state;
|
||||
+
|
||||
+typedef struct PVEBackupDevInfo {
|
||||
@ -536,6 +538,13 @@ index 9b6cfafd33..534c00f5da 100644
|
||||
+
|
||||
+static void pvebackup_cleanup(void)
|
||||
+{
|
||||
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||
+ // Avoid race between block jobs and backup-cancel command:
|
||||
+ if (!backup_state.vmaw) {
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ backup_state.end_time = time(NULL);
|
||||
+
|
||||
+ if (backup_state.vmaobj) {
|
||||
@ -543,20 +552,15 @@ index 9b6cfafd33..534c00f5da 100644
|
||||
+ backup_state.vmaobj = 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;
|
||||
+ }
|
||||
+ g_list_free(backup_state.di_list);
|
||||
+ backup_state.di_list = NULL;
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
+}
|
||||
+
|
||||
+static void pvebackup_complete_cb(void *opaque, int ret)
|
||||
+{
|
||||
+ // This always runs in the main loop
|
||||
+
|
||||
+ PVEBackupDevInfo *di = opaque;
|
||||
+
|
||||
+ di->completed = true;
|
||||
@ -574,6 +578,12 @@ index 9b6cfafd33..534c00f5da 100644
|
||||
+ backup_state.vmaobj = NULL;
|
||||
+ }
|
||||
+
|
||||
+ // remove self from job queue
|
||||
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||
+ backup_state.di_list = g_list_remove(backup_state.di_list, di);
|
||||
+ g_free(di);
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
+
|
||||
+ if (!backup_state.cancel) {
|
||||
+ pvebackup_run_next_job();
|
||||
+ }
|
||||
@ -582,6 +592,12 @@ index 9b6cfafd33..534c00f5da 100644
|
||||
+static void pvebackup_cancel(void *opaque)
|
||||
+{
|
||||
+ backup_state.cancel = true;
|
||||
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||
+ // Avoid race between block jobs and backup-cancel command:
|
||||
+ if (!backup_state.vmaw) {
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!backup_state.error) {
|
||||
+ error_setg(&backup_state.error, "backup cancelled");
|
||||
@ -604,18 +620,24 @@ index 9b6cfafd33..534c00f5da 100644
|
||||
+ if (!di->completed && di->bs) {
|
||||
+ BlockJob *job = di->bs->job;
|
||||
+ if (job) {
|
||||
+ AioContext *aio_context = blk_get_aio_context(job->blk);
|
||||
+ aio_context_acquire(aio_context);
|
||||
+ if (!di->completed) {
|
||||
+ block_job_cancel_sync(job);
|
||||
+ block_job_cancel(job);
|
||||
+ }
|
||||
+ aio_context_release(aio_context);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
+ pvebackup_cleanup();
|
||||
+}
|
||||
+
|
||||
+void qmp_backup_cancel(Error **errp)
|
||||
+{
|
||||
+ if (!backup_state.backup_mutex_initialized)
|
||||
+ return;
|
||||
+ Coroutine *co = qemu_coroutine_create(pvebackup_cancel, NULL);
|
||||
+ qemu_coroutine_enter(co);
|
||||
+
|
||||
@ -633,53 +655,61 @@ index 9b6cfafd33..534c00f5da 100644
|
||||
+ const char *backup_dir,
|
||||
+ 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);
|
||||
+ 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) {
|
||||
+ vma_object_add_config_file(vmaobj, basename, cdata, clen, errp);
|
||||
+ } 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;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ char *basename = g_path_get_basename(file);
|
||||
+
|
||||
+ if (format == BACKUP_FORMAT_VMA) {
|
||||
+ vma_object_add_config_file(vmaobj, basename, cdata, clen, errp);
|
||||
+ } 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;
|
||||
+ g_free(basename);
|
||||
+ g_free(cdata);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void block_job_resume(BlockJob *job);
|
||||
+static void pvebackup_run_next_job(void)
|
||||
+{
|
||||
+ bool cancel = backup_state.error || backup_state.cancel;
|
||||
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||
+
|
||||
+ GList *next = g_list_nth(backup_state.di_list, backup_state.next_job);
|
||||
+ while (next) {
|
||||
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)next->data;
|
||||
+ backup_state.next_job++;
|
||||
+ if (!di->completed && di->bs && di->bs->job) {
|
||||
+ BlockJob *job = di->bs->job;
|
||||
+ if (cancel) {
|
||||
+ block_job_cancel(job);
|
||||
+ AioContext *aio_context = blk_get_aio_context(job->blk);
|
||||
+ aio_context_acquire(aio_context);
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
+ if (backup_state.error || backup_state.cancel) {
|
||||
+ block_job_cancel_sync(job);
|
||||
+ } else {
|
||||
+ block_job_resume(job);
|
||||
+ }
|
||||
+ aio_context_release(aio_context);
|
||||
+ return;
|
||||
+ }
|
||||
+ next = g_list_next(next);
|
||||
+ }
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
+
|
||||
+ // no more jobs, run the cleanup
|
||||
+ pvebackup_cleanup();
|
||||
+}
|
||||
+
|
||||
@ -701,6 +731,11 @@ index 9b6cfafd33..534c00f5da 100644
|
||||
+ UuidInfo *uuid_info;
|
||||
+ BlockJob *job;
|
||||
+
|
||||
+ if (!backup_state.backup_mutex_initialized) {
|
||||
+ qemu_mutex_init(&backup_state.backup_mutex);
|
||||
+ backup_state.backup_mutex_initialized = true;
|
||||
+ }
|
||||
+
|
||||
+ if (backup_state.di_list || backup_state.vmaobj) {
|
||||
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
|
||||
+ "previous backup not finished");
|
||||
@ -831,7 +866,7 @@ index 9b6cfafd33..534c00f5da 100644
|
||||
+
|
||||
+ int flags = BDRV_O_RDWR;
|
||||
+ bdrv_img_create(di->targetfile, "raw", NULL, NULL, NULL,
|
||||
+ di->size, flags, &local_err, false);
|
||||
+ di->size, flags, false, &local_err);
|
||||
+ if (local_err) {
|
||||
+ error_propagate(errp, local_err);
|
||||
+ goto err;
|
||||
@ -844,22 +879,22 @@ index 9b6cfafd33..534c00f5da 100644
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format");
|
||||
+ goto err;
|
||||
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format");
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ /* add configuration file to archive */
|
||||
+ if (has_config_file) {
|
||||
+ if(config_to_vma(config_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
|
||||
+ goto err;
|
||||
+ }
|
||||
+ if(config_to_vma(config_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
|
||||
+ goto err;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* add firewall file to archive */
|
||||
+ if (has_firewall_file) {
|
||||
+ if(config_to_vma(firewall_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
|
||||
+ goto err;
|
||||
+ }
|
||||
+ if(config_to_vma(firewall_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
|
||||
+ goto err;
|
||||
+ }
|
||||
+ }
|
||||
+ /* initialize global backup_state now */
|
||||
+
|
||||
@ -883,6 +918,7 @@ index 9b6cfafd33..534c00f5da 100644
|
||||
+ memcpy(&backup_state.uuid, &uuid, sizeof(uuid));
|
||||
+ qemu_uuid_unparse(&uuid, backup_state.uuid_str);
|
||||
+
|
||||
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||
+ backup_state.di_list = di_list;
|
||||
+ backup_state.next_job = 0;
|
||||
+
|
||||
@ -912,6 +948,8 @@ index 9b6cfafd33..534c00f5da 100644
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
+
|
||||
+ if (!backup_state.error) {
|
||||
+ pvebackup_run_next_job(); // run one job
|
||||
+ }
|
||||
@ -1003,21 +1041,35 @@ index 9b6cfafd33..534c00f5da 100644
|
||||
void qmp_block_stream(bool has_job_id, const char *job_id, const char *device,
|
||||
bool has_base, const char *base,
|
||||
bool has_base_node, const char *base_node,
|
||||
diff --git a/blockjob.c b/blockjob.c
|
||||
index c1b6b6a810..2de9f8f4dd 100644
|
||||
--- a/blockjob.c
|
||||
+++ b/blockjob.c
|
||||
@@ -149,7 +149,8 @@ static void block_job_pause(BlockJob *job)
|
||||
job->pause_count++;
|
||||
}
|
||||
|
||||
-static void block_job_resume(BlockJob *job)
|
||||
+void block_job_resume(BlockJob *job);
|
||||
+void block_job_resume(BlockJob *job)
|
||||
{
|
||||
assert(job->pause_count > 0);
|
||||
job->pause_count--;
|
||||
diff --git a/configure b/configure
|
||||
index be4d326ae0..841f7a8fae 100755
|
||||
index 0c6e7572db..3a28a0a092 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -320,6 +320,7 @@ numa=""
|
||||
tcmalloc="no"
|
||||
@@ -422,6 +422,7 @@ tcmalloc="no"
|
||||
jemalloc="no"
|
||||
replication="yes"
|
||||
vxhs=""
|
||||
+vma=""
|
||||
|
||||
supported_cpu="no"
|
||||
supported_os="no"
|
||||
@@ -1183,6 +1184,10 @@ for opt do
|
||||
@@ -1313,6 +1314,10 @@ for opt do
|
||||
;;
|
||||
--enable-replication) replication="yes"
|
||||
--disable-git-update) git_update=no
|
||||
;;
|
||||
+ --disable-vma) vma="no"
|
||||
+ ;;
|
||||
@ -1026,15 +1078,15 @@ index be4d326ae0..841f7a8fae 100755
|
||||
*)
|
||||
echo "ERROR: unknown option $opt"
|
||||
echo "Try '$0 --help' for more information"
|
||||
@@ -1427,6 +1432,7 @@ disabled with --disable-FEATURE, default is enabled if available:
|
||||
xfsctl xfsctl support
|
||||
qom-cast-debug cast debugging support
|
||||
tools build qemu-io, qemu-nbd and qemu-image tools
|
||||
@@ -1561,6 +1566,7 @@ disabled with --disable-FEATURE, default is enabled if available:
|
||||
crypto-afalg Linux AF_ALG crypto backend driver
|
||||
vhost-user vhost-user support
|
||||
capstone capstone disassembler support
|
||||
+ vma VMA archive backend
|
||||
|
||||
NOTE: The object files are built at the place where configure is launched
|
||||
EOF
|
||||
@@ -3705,6 +3711,23 @@ EOF
|
||||
@@ -3890,6 +3896,23 @@ EOF
|
||||
fi
|
||||
|
||||
##########################################
|
||||
@ -1058,16 +1110,16 @@ index be4d326ae0..841f7a8fae 100755
|
||||
# signalfd probe
|
||||
signalfd="no"
|
||||
cat > $TMPC << EOF
|
||||
@@ -5146,6 +5169,7 @@ echo "tcmalloc support $tcmalloc"
|
||||
echo "jemalloc support $jemalloc"
|
||||
echo "avx2 optimization $avx2_opt"
|
||||
@@ -5555,6 +5578,7 @@ echo "avx2 optimization $avx2_opt"
|
||||
echo "replication support $replication"
|
||||
echo "VxHS block device $vxhs"
|
||||
echo "capstone $capstone"
|
||||
+echo "VMA support $vma"
|
||||
|
||||
if test "$sdl_too_old" = "yes"; then
|
||||
echo "-> Your SDL version is too old - please upgrade to have SDL support"
|
||||
@@ -5703,6 +5727,12 @@ if test "$libssh2" = "yes" ; then
|
||||
echo "LIBSSH2_LIBS=$libssh2_libs" >> $config_host_mak
|
||||
@@ -5998,6 +6022,12 @@ if test "$libusb" = "yes" ; then
|
||||
echo "LIBUSB_LIBS=$libusb_libs" >> $config_host_mak
|
||||
fi
|
||||
|
||||
+if test "$vma" = "yes" ; then
|
||||
@ -1076,14 +1128,14 @@ index be4d326ae0..841f7a8fae 100755
|
||||
+ echo "VMA_LIBS=$vma_libs" >> $config_host_mak
|
||||
+fi
|
||||
+
|
||||
# USB host support
|
||||
if test "$libusb" = "yes"; then
|
||||
echo "HOST_USB=libusb legacy" >> $config_host_mak
|
||||
if test "$usb_redir" = "yes" ; then
|
||||
echo "CONFIG_USB_REDIR=y" >> $config_host_mak
|
||||
echo "USB_REDIR_CFLAGS=$usb_redir_cflags" >> $config_host_mak
|
||||
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
|
||||
index 5fc57a2210..3b5a0f95e4 100644
|
||||
index 3bf69a193c..7beeb29e99 100644
|
||||
--- a/hmp-commands-info.hx
|
||||
+++ b/hmp-commands-info.hx
|
||||
@@ -487,6 +487,19 @@ STEXI
|
||||
@@ -493,6 +493,19 @@ STEXI
|
||||
Show CPU statistics.
|
||||
ETEXI
|
||||
|
||||
@ -1104,7 +1156,7 @@ index 5fc57a2210..3b5a0f95e4 100644
|
||||
{
|
||||
.name = "usernet",
|
||||
diff --git a/hmp-commands.hx b/hmp-commands.hx
|
||||
index 58940a762b..a2867b56f2 100644
|
||||
index b35bc6ab6c..9e50947845 100644
|
||||
--- a/hmp-commands.hx
|
||||
+++ b/hmp-commands.hx
|
||||
@@ -87,6 +87,37 @@ STEXI
|
||||
@ -1146,10 +1198,10 @@ index 58940a762b..a2867b56f2 100644
|
||||
.name = "block_job_set_speed",
|
||||
.args_type = "device:B,speed:o",
|
||||
diff --git a/hmp.c b/hmp.c
|
||||
index f725d061e6..12f1f46125 100644
|
||||
index b9ade681f0..241c2543ec 100644
|
||||
--- a/hmp.c
|
||||
+++ b/hmp.c
|
||||
@@ -151,6 +151,44 @@ void hmp_info_mice(Monitor *mon, const QDict *qdict)
|
||||
@@ -156,6 +156,44 @@ void hmp_info_mice(Monitor *mon, const QDict *qdict)
|
||||
qapi_free_MouseInfoList(mice_list);
|
||||
}
|
||||
|
||||
@ -1194,7 +1246,7 @@ index f725d061e6..12f1f46125 100644
|
||||
void hmp_info_migrate(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
MigrationInfo *info;
|
||||
@@ -1613,6 +1651,31 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict)
|
||||
@@ -1848,6 +1886,31 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict)
|
||||
hmp_handle_error(mon, &error);
|
||||
}
|
||||
|
||||
@ -1227,7 +1279,7 @@ index f725d061e6..12f1f46125 100644
|
||||
{
|
||||
Error *error = NULL;
|
||||
diff --git a/hmp.h b/hmp.h
|
||||
index 0497afbf65..8c1b4846b3 100644
|
||||
index 45ada581b6..635b9b4218 100644
|
||||
--- a/hmp.h
|
||||
+++ b/hmp.h
|
||||
@@ -31,6 +31,7 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict);
|
||||
@ -1238,7 +1290,7 @@ index 0497afbf65..8c1b4846b3 100644
|
||||
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);
|
||||
@@ -80,6 +81,8 @@ void hmp_eject(Monitor *mon, const QDict *qdict);
|
||||
@@ -85,6 +86,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);
|
||||
@ -1247,12 +1299,12 @@ index 0497afbf65..8c1b4846b3 100644
|
||||
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/qapi-schema.json b/qapi-schema.json
|
||||
index 5e82933ca1..b20020a054 100644
|
||||
--- a/qapi-schema.json
|
||||
+++ b/qapi-schema.json
|
||||
@@ -571,6 +571,97 @@
|
||||
{ 'command': 'query-events', 'returns': ['EventInfo'] }
|
||||
diff --git a/qapi/block-core.json b/qapi/block-core.json
|
||||
index dd763dcf87..461fca9a3d 100644
|
||||
--- a/qapi/block-core.json
|
||||
+++ b/qapi/block-core.json
|
||||
@@ -615,6 +615,97 @@
|
||||
|
||||
|
||||
##
|
||||
+# @BackupStatus:
|
||||
@ -1346,24 +1398,20 @@ index 5e82933ca1..b20020a054 100644
|
||||
+{ 'command': 'backup-cancel' }
|
||||
+
|
||||
+##
|
||||
# @MigrationStats:
|
||||
# @BlockDeviceTimedStats:
|
||||
#
|
||||
# Detailed migration status.
|
||||
diff --git a/qapi/block-core.json b/qapi/block-core.json
|
||||
index 7ce90ec940..b0ffd3de4d 100644
|
||||
--- a/qapi/block-core.json
|
||||
+++ b/qapi/block-core.json
|
||||
@@ -2118,7 +2118,7 @@
|
||||
# Statistics of a block device during a given interval of time.
|
||||
@@ -2239,7 +2330,7 @@
|
||||
'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
|
||||
'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
|
||||
'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
|
||||
- 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] }
|
||||
+ 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vma-drive' ] }
|
||||
- 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
|
||||
+ 'throttle', 'vdi', 'vhdx', 'vma-drive', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsFile:
|
||||
@@ -2895,6 +2895,21 @@
|
||||
'data': { '*offset': 'int', '*size': 'int' } }
|
||||
@@ -3116,6 +3207,21 @@
|
||||
'*tls-creds': 'str' } }
|
||||
|
||||
##
|
||||
+# @BlockdevOptionsVMADrive:
|
||||
@ -1381,19 +1429,17 @@ index 7ce90ec940..b0ffd3de4d 100644
|
||||
+ 'size': 'int' } }
|
||||
+
|
||||
+##
|
||||
# @BlockdevOptions:
|
||||
# @BlockdevOptionsThrottle:
|
||||
#
|
||||
# Options for creating a block device. Many options are available for all
|
||||
@@ -2956,7 +2971,8 @@
|
||||
# Driver specific block device options for the throttle driver
|
||||
@@ -3196,6 +3302,7 @@
|
||||
'throttle': 'BlockdevOptionsThrottle',
|
||||
'vdi': 'BlockdevOptionsGenericFormat',
|
||||
'vhdx': 'BlockdevOptionsGenericFormat',
|
||||
+ 'vma-drive': 'BlockdevOptionsVMADrive',
|
||||
'vmdk': 'BlockdevOptionsGenericCOWFormat',
|
||||
'vpc': 'BlockdevOptionsGenericFormat',
|
||||
- 'vvfat': 'BlockdevOptionsVVFAT'
|
||||
+ 'vvfat': 'BlockdevOptionsVVFAT',
|
||||
+ 'vma-drive': 'BlockdevOptionsVMADrive'
|
||||
} }
|
||||
|
||||
##
|
||||
'vvfat': 'BlockdevOptionsVVFAT',
|
||||
--
|
||||
2.11.0
|
||||
|
@ -6,35 +6,35 @@ Subject: [PATCH] adding old vma files
|
||||
---
|
||||
Makefile | 3 +-
|
||||
Makefile.objs | 1 +
|
||||
block/backup.c | 132 ++++---
|
||||
block/backup.c | 130 ++++---
|
||||
block/replication.c | 1 +
|
||||
blockdev.c | 249 +++++++++-----
|
||||
blockjob.c | 11 +-
|
||||
blockdev.c | 207 +++++++----
|
||||
blockjob.c | 3 +-
|
||||
include/block/block_int.h | 4 +
|
||||
vma-reader.c | 857 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
vma-writer.c | 771 +++++++++++++++++++++++++++++++++++++++++
|
||||
vma.c | 757 ++++++++++++++++++++++++++++++++++++++++
|
||||
vma.h | 149 ++++++++
|
||||
11 files changed, 2802 insertions(+), 133 deletions(-)
|
||||
vma.c | 756 ++++++++++++++++++++++++++++++++++++++++
|
||||
vma.h | 150 ++++++++
|
||||
11 files changed, 2760 insertions(+), 123 deletions(-)
|
||||
create mode 100644 vma-reader.c
|
||||
create mode 100644 vma-writer.c
|
||||
create mode 100644 vma.c
|
||||
create mode 100644 vma.h
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index 6c359b2f86..edbc8b50f0 100644
|
||||
index ab0354c153..ad28227b6c 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -284,7 +284,7 @@ ifneq ($(wildcard config-host.mak),)
|
||||
@@ -340,7 +340,7 @@ dummy := $(call unnest-vars,, \
|
||||
|
||||
include $(SRC_PATH)/tests/Makefile.include
|
||||
endif
|
||||
|
||||
-all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules
|
||||
+all: $(DOCS) $(TOOLS) vma$(EXESUF) $(HELPERS-y) recurse-all modules
|
||||
|
||||
qemu-version.h: FORCE
|
||||
$(call quiet-command, \
|
||||
@@ -377,6 +377,7 @@ qemu-img.o: qemu-img-cmds.h
|
||||
@@ -439,6 +439,7 @@ qemu-img.o: qemu-img-cmds.h
|
||||
qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
@ -43,11 +43,11 @@ index 6c359b2f86..edbc8b50f0 100644
|
||||
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
|
||||
|
||||
diff --git a/Makefile.objs b/Makefile.objs
|
||||
index fbfbbb7f70..f5f8dbab3b 100644
|
||||
index 686247b556..34e62547d8 100644
|
||||
--- a/Makefile.objs
|
||||
+++ b/Makefile.objs
|
||||
@@ -14,6 +14,7 @@ block-obj-y += block.o blockjob.o
|
||||
block-obj-y += block/
|
||||
block-obj-y += block/ scsi/
|
||||
block-obj-y += qemu-io-cmds.o
|
||||
block-obj-$(CONFIG_REPLICATION) += replication.o
|
||||
+block-obj-y += vma-writer.o
|
||||
@ -55,7 +55,7 @@ index fbfbbb7f70..f5f8dbab3b 100644
|
||||
block-obj-m = block/
|
||||
|
||||
diff --git a/block/backup.c b/block/backup.c
|
||||
index 1ede70c061..7c5febc434 100644
|
||||
index 8c2967a8cb..0870acdae7 100644
|
||||
--- a/block/backup.c
|
||||
+++ b/block/backup.c
|
||||
@@ -36,6 +36,7 @@ typedef struct BackupBlockJob {
|
||||
@ -66,47 +66,48 @@ index 1ede70c061..7c5febc434 100644
|
||||
BlockdevOnError on_source_error;
|
||||
BlockdevOnError on_target_error;
|
||||
CoRwlock flush_rwlock;
|
||||
@@ -145,13 +146,24 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
|
||||
@@ -135,13 +136,24 @@ 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,
|
||||
- ret = blk_co_pwrite_zeroes(job->target, start,
|
||||
- bounce_qiov.size, BDRV_REQ_MAY_UNMAP);
|
||||
+ if (job->dump_cb) {
|
||||
+ ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, NULL);
|
||||
+ ret = job->dump_cb(job->common.opaque, job->target, start, bounce_qiov.size, NULL);
|
||||
+ }
|
||||
+ if (job->target) {
|
||||
+ ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size,
|
||||
+ ret = blk_co_pwrite_zeroes(job->target, start,
|
||||
+ bounce_qiov.size, BDRV_REQ_MAY_UNMAP);
|
||||
+ }
|
||||
} else {
|
||||
- ret = blk_co_pwritev(job->target, start * job->cluster_size,
|
||||
- ret = blk_co_pwritev(job->target, start,
|
||||
- bounce_qiov.size, &bounce_qiov,
|
||||
- job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0);
|
||||
+ if (job->dump_cb) {
|
||||
+ ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, bounce_buffer);
|
||||
+ ret = job->dump_cb(job->common.opaque, job->target, start, bounce_qiov.size, bounce_buffer);
|
||||
+ }
|
||||
+ if (job->target) {
|
||||
+ ret = blk_co_pwritev(job->target, start * job->cluster_size,
|
||||
+ ret = blk_co_pwritev(job->target, start,
|
||||
+ bounce_qiov.size, &bounce_qiov,
|
||||
+ job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0);
|
||||
+ }
|
||||
}
|
||||
if (ret < 0) {
|
||||
trace_backup_do_cow_write_fail(job, start, ret);
|
||||
@@ -246,6 +258,9 @@ static void backup_abort(BlockJob *job)
|
||||
@@ -234,7 +246,9 @@ static void backup_abort(BlockJob *job)
|
||||
static void backup_clean(BlockJob *job)
|
||||
{
|
||||
BackupBlockJob *s = container_of(job, BackupBlockJob, common);
|
||||
- assert(s->target);
|
||||
+ if (!s->target) {
|
||||
+ return;
|
||||
+ }
|
||||
assert(s->target);
|
||||
blk_unref(s->target);
|
||||
s->target = NULL;
|
||||
@@ -255,7 +270,9 @@ static void backup_attached_aio_context(BlockJob *job, AioContext *aio_context)
|
||||
}
|
||||
@@ -243,7 +257,9 @@ static void backup_attached_aio_context(BlockJob *job, AioContext *aio_context)
|
||||
{
|
||||
BackupBlockJob *s = container_of(job, BackupBlockJob, common);
|
||||
|
||||
@ -117,7 +118,7 @@ index 1ede70c061..7c5febc434 100644
|
||||
}
|
||||
|
||||
void backup_do_checkpoint(BlockJob *job, Error **errp)
|
||||
@@ -330,9 +347,11 @@ static BlockErrorAction backup_error_action(BackupBlockJob *job,
|
||||
@@ -315,9 +331,11 @@ static BlockErrorAction backup_error_action(BackupBlockJob *job,
|
||||
if (read) {
|
||||
return block_job_error_action(&job->common, job->on_source_error,
|
||||
true, error);
|
||||
@ -130,7 +131,7 @@ index 1ede70c061..7c5febc434 100644
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,6 +576,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
@@ -538,6 +556,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
int creation_flags,
|
||||
@ -138,7 +139,7 @@ index 1ede70c061..7c5febc434 100644
|
||||
BlockCompletionFunc *cb, void *opaque,
|
||||
int pause_count,
|
||||
BlockJobTxn *txn, Error **errp)
|
||||
@@ -567,7 +587,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
@@ -548,7 +567,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
int ret;
|
||||
|
||||
assert(bs);
|
||||
@ -147,7 +148,7 @@ index 1ede70c061..7c5febc434 100644
|
||||
|
||||
if (bs == target) {
|
||||
error_setg(errp, "Source and target cannot be the same");
|
||||
@@ -580,13 +600,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
@@ -561,13 +580,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -163,7 +164,7 @@ index 1ede70c061..7c5febc434 100644
|
||||
error_setg(errp, "Compression is not supported for this drive %s",
|
||||
bdrv_get_device_name(target));
|
||||
return NULL;
|
||||
@@ -596,7 +616,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
@@ -577,7 +596,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -172,7 +173,7 @@ index 1ede70c061..7c5febc434 100644
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -636,15 +656,18 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
@@ -617,15 +636,18 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -198,7 +199,7 @@ index 1ede70c061..7c5febc434 100644
|
||||
job->on_source_error = on_source_error;
|
||||
job->on_target_error = on_target_error;
|
||||
job->sync_mode = sync_mode;
|
||||
@@ -652,38 +675,55 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
@@ -633,36 +655,52 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
sync_bitmap : NULL;
|
||||
job->compress = compress;
|
||||
|
||||
@ -208,12 +209,12 @@ index 1ede70c061..7c5febc434 100644
|
||||
- ret = bdrv_get_info(target, &bdi);
|
||||
- if (ret == -ENOTSUP && !target->backing) {
|
||||
- /* Cluster size is not defined */
|
||||
- error_report("WARNING: The target block device doesn't provide "
|
||||
- "information about the block size and it doesn't have a "
|
||||
- "backing file. The default block size of %u bytes is "
|
||||
- "used. If the actual block size of the target exceeds "
|
||||
- "this default, the backup may be unusable",
|
||||
- BACKUP_CLUSTER_SIZE_DEFAULT);
|
||||
- warn_report("The target block device doesn't provide "
|
||||
- "information about the block size and it doesn't have a "
|
||||
- "backing file. The default block size of %u bytes is "
|
||||
- "used. If the actual block size of the target exceeds "
|
||||
- "this default, the backup may be unusable",
|
||||
- BACKUP_CLUSTER_SIZE_DEFAULT);
|
||||
- job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
|
||||
- } else if (ret < 0 && !target->backing) {
|
||||
- error_setg_errno(errp, -ret,
|
||||
@ -232,12 +233,12 @@ index 1ede70c061..7c5febc434 100644
|
||||
+ ret = bdrv_get_info(target, &bdi);
|
||||
+ if (ret == -ENOTSUP && !target->backing) {
|
||||
+ /* Cluster size is not defined */
|
||||
+ error_report("WARNING: The target block device doesn't provide "
|
||||
+ "information about the block size and it doesn't have a "
|
||||
+ "backing file. The default block size of %u bytes is "
|
||||
+ "used. If the actual block size of the target exceeds "
|
||||
+ "this default, the backup may be unusable",
|
||||
+ BACKUP_CLUSTER_SIZE_DEFAULT);
|
||||
+ warn_report("The target block device doesn't provide "
|
||||
+ "information about the block size and it doesn't have a "
|
||||
+ "backing file. The default block size of %u bytes is "
|
||||
+ "used. If the actual block size of the target exceeds "
|
||||
+ "this default, the backup may be unusable",
|
||||
+ BACKUP_CLUSTER_SIZE_DEFAULT);
|
||||
+ job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
|
||||
+ } else if (ret < 0 && !target->backing) {
|
||||
+ error_setg_errno(errp, -ret,
|
||||
@ -274,19 +275,15 @@ index 1ede70c061..7c5febc434 100644
|
||||
+ /* Required permissions are already taken with target's blk_new() */
|
||||
+ block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
|
||||
+ &error_abort);
|
||||
+ } else {
|
||||
+ job->common.pause_count = pause_count;
|
||||
+ }
|
||||
job->common.len = len;
|
||||
- job->common.pause_count = pause_count;
|
||||
job->common.pause_count = pause_count;
|
||||
block_job_txn_add_job(txn, &job->common);
|
||||
|
||||
return &job->common;
|
||||
diff --git a/block/replication.c b/block/replication.c
|
||||
index 1c41d9e6bf..60c6524417 100644
|
||||
index 1b08b242eb..3d101ce6e6 100644
|
||||
--- a/block/replication.c
|
||||
+++ b/block/replication.c
|
||||
@@ -531,6 +531,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
||||
@@ -561,6 +561,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
||||
0, MIRROR_SYNC_MODE_NONE, NULL, false,
|
||||
BLOCKDEV_ON_ERROR_REPORT,
|
||||
BLOCKDEV_ON_ERROR_REPORT, BLOCK_JOB_INTERNAL,
|
||||
@ -295,7 +292,7 @@ index 1c41d9e6bf..60c6524417 100644
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
diff --git a/blockdev.c b/blockdev.c
|
||||
index 534c00f5da..19a82e8774 100644
|
||||
index 3ffd064c48..4b6091afc6 100644
|
||||
--- a/blockdev.c
|
||||
+++ b/blockdev.c
|
||||
@@ -31,7 +31,6 @@
|
||||
@ -314,37 +311,7 @@ index 534c00f5da..19a82e8774 100644
|
||||
|
||||
static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
|
||||
QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states);
|
||||
@@ -2934,20 +2934,44 @@ out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
+void block_job_event_cancelled(BlockJob *job);
|
||||
+void block_job_event_completed(BlockJob *job, const char *msg);
|
||||
+static void block_job_cb(void *opaque, int ret)
|
||||
+{
|
||||
+ /* Note that this function may be executed from another AioContext besides
|
||||
+ * the QEMU main loop. If you need to access anything that assumes the
|
||||
+ * QEMU global mutex, use a BH or introduce a mutex.
|
||||
+ */
|
||||
+
|
||||
+ BlockDriverState *bs = opaque;
|
||||
+ const char *msg = NULL;
|
||||
+
|
||||
+ assert(bs->job);
|
||||
+
|
||||
+ if (ret < 0) {
|
||||
+ msg = strerror(-ret);
|
||||
+ }
|
||||
+
|
||||
+ if (block_job_is_cancelled(bs->job)) {
|
||||
+ block_job_event_cancelled(bs->job);
|
||||
+ } else {
|
||||
+ block_job_event_completed(bs->job, msg);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/* PVE backup related function */
|
||||
|
||||
@@ -2970,15 +2970,14 @@ out:
|
||||
static struct PVEBackupState {
|
||||
Error *error;
|
||||
bool cancel;
|
||||
@ -362,45 +329,37 @@ index 534c00f5da..19a82e8774 100644
|
||||
size_t total;
|
||||
size_t transferred;
|
||||
size_t zero_bytes;
|
||||
@@ -2957,6 +2981,7 @@ typedef struct PVEBackupDevInfo {
|
||||
BlockDriverState *bs;
|
||||
size_t size;
|
||||
uint8_t dev_id;
|
||||
+ //bool started;
|
||||
bool completed;
|
||||
char targetfile[PATH_MAX];
|
||||
BlockDriverState *target;
|
||||
@@ -2964,13 +2989,79 @@ typedef struct PVEBackupDevInfo {
|
||||
@@ -2997,6 +2996,71 @@ typedef struct 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)
|
||||
+ uint64_t start, uint64_t bytes,
|
||||
+ const void *pbuf)
|
||||
+{
|
||||
+ const uint64_t size = bytes;
|
||||
+ const unsigned char *buf = pbuf;
|
||||
+ PVEBackupDevInfo *di = opaque;
|
||||
+
|
||||
+ int size = n_sectors * BDRV_SECTOR_SIZE;
|
||||
+ if (backup_state.cancel) {
|
||||
+ return size; // return success
|
||||
+ }
|
||||
+
|
||||
+ if (sector_num & 0x7f) {
|
||||
+ uint64_t cluster_num = start / VMA_CLUSTER_SIZE;
|
||||
+ if ((cluster_num * VMA_CLUSTER_SIZE) != start) {
|
||||
+ if (!backup_state.error) {
|
||||
+ error_setg(&backup_state.error,
|
||||
+ "got unaligned write inside backup dump "
|
||||
+ "callback (sector %ld)", sector_num);
|
||||
+ "callback (sector %ld)", start);
|
||||
+ }
|
||||
+ return -1; // not aligned to cluster size
|
||||
+ }
|
||||
+
|
||||
+ int64_t cluster_num = sector_num >> 7;
|
||||
+
|
||||
+ int ret = -1;
|
||||
+
|
||||
+ if (backup_state.vmaw) {
|
||||
+ size_t zero_bytes = 0;
|
||||
+ int64_t remaining = n_sectors * BDRV_SECTOR_SIZE;
|
||||
+ uint64_t remaining = size;
|
||||
+ while (remaining > 0) {
|
||||
+ ret = vma_writer_write(backup_state.vmaw, di->dev_id, cluster_num,
|
||||
+ buf, &zero_bytes);
|
||||
@ -420,10 +379,11 @@ index 534c00f5da..19a82e8774 100644
|
||||
+ backup_state.zero_bytes += zero_bytes;
|
||||
+ if (remaining >= VMA_CLUSTER_SIZE) {
|
||||
+ backup_state.transferred += VMA_CLUSTER_SIZE;
|
||||
+ remaining -= VMA_CLUSTER_SIZE;
|
||||
+ } else {
|
||||
+ backup_state.transferred += remaining;
|
||||
+ remaining = 0;
|
||||
+ }
|
||||
+ remaining -= VMA_CLUSTER_SIZE;
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
@ -440,6 +400,9 @@ index 534c00f5da..19a82e8774 100644
|
||||
+
|
||||
static void pvebackup_cleanup(void)
|
||||
{
|
||||
qemu_mutex_lock(&backup_state.backup_mutex);
|
||||
@@ -3008,9 +3072,11 @@ static void pvebackup_cleanup(void)
|
||||
|
||||
backup_state.end_time = time(NULL);
|
||||
|
||||
- if (backup_state.vmaobj) {
|
||||
@ -452,9 +415,9 @@ index 534c00f5da..19a82e8774 100644
|
||||
+ backup_state.vmaw = NULL;
|
||||
}
|
||||
|
||||
if (backup_state.di_list) {
|
||||
@@ -2985,6 +3076,13 @@ static void pvebackup_cleanup(void)
|
||||
}
|
||||
g_list_free(backup_state.di_list);
|
||||
@@ -3018,6 +3084,13 @@ static void pvebackup_cleanup(void)
|
||||
qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
}
|
||||
|
||||
+static void coroutine_fn backup_close_vma_stream(void *opaque)
|
||||
@ -466,13 +429,8 @@ index 534c00f5da..19a82e8774 100644
|
||||
+
|
||||
static void pvebackup_complete_cb(void *opaque, int ret)
|
||||
{
|
||||
PVEBackupDevInfo *di = opaque;
|
||||
@@ -2996,14 +3094,18 @@ static void pvebackup_complete_cb(void *opaque, int ret)
|
||||
ret, strerror(-ret));
|
||||
}
|
||||
|
||||
+ BlockDriverState *bs = di->bs;
|
||||
+
|
||||
// This always runs in the main loop
|
||||
@@ -3034,9 +3107,9 @@ static void pvebackup_complete_cb(void *opaque, int ret)
|
||||
di->bs = NULL;
|
||||
di->target = NULL;
|
||||
|
||||
@ -484,12 +442,8 @@ index 534c00f5da..19a82e8774 100644
|
||||
+ qemu_coroutine_enter(co);
|
||||
}
|
||||
|
||||
+ block_job_cb(bs, ret);
|
||||
+
|
||||
if (!backup_state.cancel) {
|
||||
pvebackup_run_next_job();
|
||||
}
|
||||
@@ -3017,14 +3119,9 @@ static void pvebackup_cancel(void *opaque)
|
||||
// remove self from job queue
|
||||
@@ -3064,14 +3137,9 @@ static void pvebackup_cancel(void *opaque)
|
||||
error_setg(&backup_state.error, "backup cancelled");
|
||||
}
|
||||
|
||||
@ -506,7 +460,7 @@ index 534c00f5da..19a82e8774 100644
|
||||
}
|
||||
|
||||
GList *l = backup_state.di_list;
|
||||
@@ -3049,19 +3146,15 @@ void qmp_backup_cancel(Error **errp)
|
||||
@@ -3102,18 +3170,14 @@ void qmp_backup_cancel(Error **errp)
|
||||
Coroutine *co = qemu_coroutine_create(pvebackup_cancel, NULL);
|
||||
qemu_coroutine_enter(co);
|
||||
|
||||
@ -524,44 +478,33 @@ index 534c00f5da..19a82e8774 100644
|
||||
static int config_to_vma(const char *file, BackupFormat format,
|
||||
- Object *vmaobj,
|
||||
- const char *backup_dir,
|
||||
- Error **errp)
|
||||
+ const char *backup_dir, VmaWriter *vmaw,
|
||||
+ Error **errp)
|
||||
+ const char *backup_dir, VmaWriter *vmaw,
|
||||
Error **errp)
|
||||
{
|
||||
char *cdata = NULL;
|
||||
gsize clen = 0;
|
||||
@@ -3074,12 +3167,17 @@ static int config_to_vma(const char *file, BackupFormat format,
|
||||
char *basename = g_path_get_basename(file);
|
||||
char *cdata = NULL;
|
||||
@@ -3127,7 +3191,12 @@ static int config_to_vma(const char *file, BackupFormat format,
|
||||
char *basename = g_path_get_basename(file);
|
||||
|
||||
if (format == BACKUP_FORMAT_VMA) {
|
||||
- vma_object_add_config_file(vmaobj, basename, cdata, clen, errp);
|
||||
+ 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);
|
||||
+ error_setg(errp, "unable to write config file '%s'", config_path);
|
||||
g_free(cdata);
|
||||
g_free(basename);
|
||||
return 1;
|
||||
@@ -3089,34 +3187,37 @@ static int config_to_vma(const char *file, BackupFormat format,
|
||||
g_free(basename);
|
||||
g_free(cdata);
|
||||
|
||||
- return 0;
|
||||
+ return 0;
|
||||
if (format == BACKUP_FORMAT_VMA) {
|
||||
- vma_object_add_config_file(vmaobj, basename, cdata, clen, errp);
|
||||
+ 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);
|
||||
@@ -3145,28 +3214,30 @@ static int config_to_vma(const char *file, BackupFormat format,
|
||||
}
|
||||
|
||||
void block_job_resume(BlockJob *job);
|
||||
+bool block_job_should_pause(BlockJob *job);
|
||||
static void pvebackup_run_next_job(void)
|
||||
{
|
||||
- bool cancel = backup_state.error || backup_state.cancel;
|
||||
qemu_mutex_lock(&backup_state.backup_mutex);
|
||||
|
||||
- GList *next = g_list_nth(backup_state.di_list, backup_state.next_job);
|
||||
- while (next) {
|
||||
- PVEBackupDevInfo *di = (PVEBackupDevInfo *)next->data;
|
||||
@ -572,26 +515,28 @@ index 534c00f5da..19a82e8774 100644
|
||||
+ l = g_list_next(l);
|
||||
if (!di->completed && di->bs && di->bs->job) {
|
||||
BlockJob *job = di->bs->job;
|
||||
- if (cancel) {
|
||||
- block_job_cancel(job);
|
||||
AioContext *aio_context = blk_get_aio_context(job->blk);
|
||||
aio_context_acquire(aio_context);
|
||||
qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
- if (backup_state.error || backup_state.cancel) {
|
||||
- block_job_cancel_sync(job);
|
||||
- } else {
|
||||
- block_job_resume(job);
|
||||
+ if (block_job_should_pause(job)) {
|
||||
+ bool cancel = backup_state.error || backup_state.cancel;
|
||||
+ if (cancel) {
|
||||
+ block_job_cancel(job);
|
||||
+ if (backup_state.error || backup_state.cancel) {
|
||||
+ block_job_cancel_sync(job);
|
||||
+ } else {
|
||||
+ block_job_resume(job);
|
||||
+ }
|
||||
}
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
- next = g_list_next(next);
|
||||
}
|
||||
+
|
||||
pvebackup_cleanup();
|
||||
}
|
||||
qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
|
||||
@@ -3177,7 +3248,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,
|
||||
@ -600,7 +545,7 @@ index 534c00f5da..19a82e8774 100644
|
||||
bool has_devlist, const char *devlist,
|
||||
bool has_speed, int64_t speed, Error **errp)
|
||||
{
|
||||
@@ -3124,14 +3225,15 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||
@@ -3185,7 +3256,8 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||
BlockDriverState *bs = NULL;
|
||||
const char *backup_dir = NULL;
|
||||
Error *local_err = NULL;
|
||||
@ -610,15 +555,16 @@ index 534c00f5da..19a82e8774 100644
|
||||
gchar **devs = NULL;
|
||||
GList *di_list = NULL;
|
||||
GList *l;
|
||||
UuidInfo *uuid_info;
|
||||
BlockJob *job;
|
||||
@@ -3197,7 +3269,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||
backup_state.backup_mutex_initialized = true;
|
||||
}
|
||||
|
||||
- if (backup_state.di_list || backup_state.vmaobj) {
|
||||
+ if (backup_state.di_list) {
|
||||
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
|
||||
"previous backup not finished");
|
||||
return NULL;
|
||||
@@ -3206,40 +3308,28 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||
@@ -3272,40 +3344,28 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||
total += size;
|
||||
}
|
||||
|
||||
@ -667,27 +613,24 @@ index 534c00f5da..19a82e8774 100644
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
@@ -3280,15 +3370,15 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||
@@ -3346,14 +3406,14 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||
|
||||
/* add configuration file to archive */
|
||||
if (has_config_file) {
|
||||
- if(config_to_vma(config_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
|
||||
- goto err;
|
||||
+ if(config_to_vma(config_file, format, backup_dir, vmaw, errp) != 0) {
|
||||
+ goto err;
|
||||
}
|
||||
- if(config_to_vma(config_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
|
||||
+ 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_state.vmaobj, backup_dir, errp) != 0) {
|
||||
- goto err;
|
||||
+ if(config_to_vma(firewall_file, format, backup_dir, vmaw, errp) != 0) {
|
||||
+ goto err;
|
||||
}
|
||||
- if(config_to_vma(firewall_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
|
||||
+ if (config_to_vma(firewall_file, format, backup_dir, vmaw, errp) != 0) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
/* initialize global backup_state now */
|
||||
@@ -3310,11 +3400,12 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||
@@ -3376,12 +3436,13 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||
}
|
||||
backup_state.backup_file = g_strdup(backup_file);
|
||||
|
||||
@ -698,12 +641,13 @@ index 534c00f5da..19a82e8774 100644
|
||||
+ uuid_copy(backup_state.uuid, uuid);
|
||||
+ uuid_unparse_lower(uuid, backup_state.uuid_str);
|
||||
|
||||
qemu_mutex_lock(&backup_state.backup_mutex);
|
||||
backup_state.di_list = di_list;
|
||||
- backup_state.next_job = 0;
|
||||
|
||||
backup_state.total = total;
|
||||
backup_state.transferred = 0;
|
||||
@@ -3325,21 +3416,16 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||
@@ -3392,21 +3453,16 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||
while (l) {
|
||||
PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
|
||||
l = g_list_next(l);
|
||||
@ -727,8 +671,8 @@ index 534c00f5da..19a82e8774 100644
|
||||
+ block_job_start(job);
|
||||
}
|
||||
|
||||
if (!backup_state.error) {
|
||||
@@ -3373,9 +3459,10 @@ err:
|
||||
qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
@@ -3442,9 +3498,10 @@ err:
|
||||
g_strfreev(devs);
|
||||
}
|
||||
|
||||
@ -742,7 +686,7 @@ index 534c00f5da..19a82e8774 100644
|
||||
}
|
||||
|
||||
if (backup_dir) {
|
||||
@@ -3760,7 +3847,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
|
||||
@@ -3829,7 +3886,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
|
||||
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
|
||||
backup->sync, bmap, backup->compress,
|
||||
backup->on_source_error, backup->on_target_error,
|
||||
@ -751,7 +695,7 @@ index 534c00f5da..19a82e8774 100644
|
||||
bdrv_unref(target_bs);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
@@ -3839,7 +3926,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
|
||||
@@ -3908,7 +3965,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
|
||||
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
|
||||
backup->sync, NULL, backup->compress,
|
||||
backup->on_source_error, backup->on_target_error,
|
||||
@ -761,22 +705,11 @@ index 534c00f5da..19a82e8774 100644
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
diff --git a/blockjob.c b/blockjob.c
|
||||
index 764d41863e..cb3741f6dd 100644
|
||||
index 2de9f8f4dd..1df33bd194 100644
|
||||
--- a/blockjob.c
|
||||
+++ b/blockjob.c
|
||||
@@ -37,8 +37,8 @@
|
||||
#include "qemu/timer.h"
|
||||
#include "qapi-event.h"
|
||||
|
||||
-static void block_job_event_cancelled(BlockJob *job);
|
||||
-static void block_job_event_completed(BlockJob *job, const char *msg);
|
||||
+void block_job_event_cancelled(BlockJob *job);
|
||||
+void block_job_event_completed(BlockJob *job, const char *msg);
|
||||
|
||||
/* Transactional group of block jobs */
|
||||
struct BlockJobTxn {
|
||||
@@ -473,7 +473,8 @@ void block_job_user_pause(BlockJob *job)
|
||||
block_job_pause(job);
|
||||
@@ -757,7 +757,8 @@ void block_job_completed(BlockJob *job, int ret)
|
||||
}
|
||||
}
|
||||
|
||||
-static bool block_job_should_pause(BlockJob *job)
|
||||
@ -785,39 +718,21 @@ index 764d41863e..cb3741f6dd 100644
|
||||
{
|
||||
return job->pause_count > 0;
|
||||
}
|
||||
@@ -687,7 +688,7 @@ static void block_job_iostatus_set_err(BlockJob *job, int error)
|
||||
}
|
||||
}
|
||||
|
||||
-static void block_job_event_cancelled(BlockJob *job)
|
||||
+void block_job_event_cancelled(BlockJob *job)
|
||||
{
|
||||
if (block_job_is_internal(job)) {
|
||||
return;
|
||||
@@ -701,7 +702,7 @@ static void block_job_event_cancelled(BlockJob *job)
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
-static void block_job_event_completed(BlockJob *job, const char *msg)
|
||||
+void block_job_event_completed(BlockJob *job, const char *msg)
|
||||
{
|
||||
if (block_job_is_internal(job)) {
|
||||
return;
|
||||
diff --git a/include/block/block_int.h b/include/block/block_int.h
|
||||
index 19b84b027f..fc1c53a059 100644
|
||||
index 1dbbdafd31..2ed3e41437 100644
|
||||
--- a/include/block/block_int.h
|
||||
+++ b/include/block/block_int.h
|
||||
@@ -59,6 +59,9 @@
|
||||
@@ -60,6 +60,9 @@
|
||||
|
||||
#define BLOCK_PROBE_BUF_SIZE 512
|
||||
|
||||
+typedef int BackupDumpFunc(void *opaque, BlockBackend *be,
|
||||
+ int64_t sector_num, int n_sectors, unsigned char *buf);
|
||||
+ uint64_t offset, uint64_t bytes, const void *buf);
|
||||
+
|
||||
enum BdrvTrackedRequestType {
|
||||
BDRV_TRACKED_READ,
|
||||
BDRV_TRACKED_WRITE,
|
||||
@@ -878,6 +881,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
@@ -984,6 +987,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
int creation_flags,
|
||||
@ -1690,7 +1605,7 @@ index 0000000000..2000889bd3
|
||||
+
|
||||
diff --git a/vma-writer.c b/vma-writer.c
|
||||
new file mode 100644
|
||||
index 0000000000..9001cbdd2b
|
||||
index 0000000000..fd9567634d
|
||||
--- /dev/null
|
||||
+++ b/vma-writer.c
|
||||
@@ -0,0 +1,771 @@
|
||||
@ -2279,7 +2194,7 @@ index 0000000000..9001cbdd2b
|
||||
+
|
||||
+int64_t coroutine_fn
|
||||
+vma_writer_write(VmaWriter *vmaw, uint8_t dev_id, int64_t cluster_num,
|
||||
+ unsigned char *buf, size_t *zero_bytes)
|
||||
+ const unsigned char *buf, size_t *zero_bytes)
|
||||
+{
|
||||
+ g_assert(vmaw != NULL);
|
||||
+ g_assert(zero_bytes != NULL);
|
||||
@ -2335,7 +2250,7 @@ index 0000000000..9001cbdd2b
|
||||
+ int i;
|
||||
+ int bit = 1;
|
||||
+ for (i = 0; i < 16; i++) {
|
||||
+ unsigned char *vmablock = buf + (i*VMA_BLOCK_SIZE);
|
||||
+ const unsigned char *vmablock = buf + (i*VMA_BLOCK_SIZE);
|
||||
+ if (!buffer_is_zero(vmablock, VMA_BLOCK_SIZE)) {
|
||||
+ mask |= bit;
|
||||
+ memcpy(vmaw->outbuf + vmaw->outbuf_pos, vmablock,
|
||||
@ -2467,10 +2382,10 @@ index 0000000000..9001cbdd2b
|
||||
+}
|
||||
diff --git a/vma.c b/vma.c
|
||||
new file mode 100644
|
||||
index 0000000000..04915427c8
|
||||
index 0000000000..1b59fd1555
|
||||
--- /dev/null
|
||||
+++ b/vma.c
|
||||
@@ -0,0 +1,757 @@
|
||||
@@ -0,0 +1,756 @@
|
||||
+/*
|
||||
+ * VMA: Virtual Machine Archive
|
||||
+ *
|
||||
@ -2492,7 +2407,6 @@ index 0000000000..04915427c8
|
||||
+#include "qemu/error-report.h"
|
||||
+#include "qemu/main-loop.h"
|
||||
+#include "qapi/qmp/qstring.h"
|
||||
+#include "sysemu/char.h" /* qstring_from_str */
|
||||
+#include "sysemu/block-backend.h"
|
||||
+
|
||||
+static void help(void)
|
||||
@ -2772,7 +2686,7 @@ index 0000000000..04915427c8
|
||||
+ printf("DEVINFO %s %zd\n", devfn, di->size);
|
||||
+
|
||||
+ bdrv_img_create(devfn, "raw", NULL, NULL, NULL, di->size,
|
||||
+ flags, &errp, 0);
|
||||
+ flags, true, &errp);
|
||||
+ if (errp) {
|
||||
+ g_error("can't create file %s: %s", devfn,
|
||||
+ error_get_pretty(errp));
|
||||
@ -3230,10 +3144,10 @@ index 0000000000..04915427c8
|
||||
+}
|
||||
diff --git a/vma.h b/vma.h
|
||||
new file mode 100644
|
||||
index 0000000000..fa6f4df7e7
|
||||
index 0000000000..c895c97f6d
|
||||
--- /dev/null
|
||||
+++ b/vma.h
|
||||
@@ -0,0 +1,149 @@
|
||||
@@ -0,0 +1,150 @@
|
||||
+/*
|
||||
+ * VMA: Virtual Machine Archive
|
||||
+ *
|
||||
@ -3360,7 +3274,8 @@ index 0000000000..fa6f4df7e7
|
||||
+ size_t size);
|
||||
+
|
||||
+int64_t coroutine_fn vma_writer_write(VmaWriter *vmaw, uint8_t dev_id,
|
||||
+ int64_t cluster_num, unsigned char *buf,
|
||||
+ int64_t cluster_num,
|
||||
+ const unsigned char *buf,
|
||||
+ size_t *zero_bytes);
|
||||
+
|
||||
+int coroutine_fn vma_writer_close_stream(VmaWriter *vmaw, uint8_t dev_id);
|
@ -1,253 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
Date: Tue, 5 Dec 2017 12:12:15 +0100
|
||||
Subject: [PATCH] backup: fix race in backup-stop command
|
||||
|
||||
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
---
|
||||
blockdev.c | 90 +++++++++++++++++++++++++++++++++-----------------------------
|
||||
blockjob.c | 8 +++---
|
||||
2 files changed, 52 insertions(+), 46 deletions(-)
|
||||
|
||||
diff --git a/blockdev.c b/blockdev.c
|
||||
index 19a82e8774..d3490936d8 100644
|
||||
--- a/blockdev.c
|
||||
+++ b/blockdev.c
|
||||
@@ -2934,31 +2934,6 @@ out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
-void block_job_event_cancelled(BlockJob *job);
|
||||
-void block_job_event_completed(BlockJob *job, const char *msg);
|
||||
-static void block_job_cb(void *opaque, int ret)
|
||||
-{
|
||||
- /* Note that this function may be executed from another AioContext besides
|
||||
- * the QEMU main loop. If you need to access anything that assumes the
|
||||
- * QEMU global mutex, use a BH or introduce a mutex.
|
||||
- */
|
||||
-
|
||||
- BlockDriverState *bs = opaque;
|
||||
- const char *msg = NULL;
|
||||
-
|
||||
- assert(bs->job);
|
||||
-
|
||||
- if (ret < 0) {
|
||||
- msg = strerror(-ret);
|
||||
- }
|
||||
-
|
||||
- if (block_job_is_cancelled(bs->job)) {
|
||||
- block_job_event_cancelled(bs->job);
|
||||
- } else {
|
||||
- block_job_event_completed(bs->job, msg);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
/* PVE backup related function */
|
||||
|
||||
static struct PVEBackupState {
|
||||
@@ -2975,6 +2950,8 @@ static struct PVEBackupState {
|
||||
size_t total;
|
||||
size_t transferred;
|
||||
size_t zero_bytes;
|
||||
+ QemuMutex backup_mutex;
|
||||
+ bool backup_mutex_initialized;
|
||||
} backup_state;
|
||||
|
||||
typedef struct PVEBackupDevInfo {
|
||||
@@ -3055,6 +3032,13 @@ static int pvebackup_dump_cb(void *opaque, BlockBackend *target,
|
||||
|
||||
static void pvebackup_cleanup(void)
|
||||
{
|
||||
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||
+ // Avoid race between block jobs and backup-cancel command:
|
||||
+ if (!backup_state.vmaw) {
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
backup_state.end_time = time(NULL);
|
||||
|
||||
if (backup_state.vmaw) {
|
||||
@@ -3064,16 +3048,9 @@ static void pvebackup_cleanup(void)
|
||||
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;
|
||||
- }
|
||||
+ g_list_free(backup_state.di_list);
|
||||
+ backup_state.di_list = NULL;
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
}
|
||||
|
||||
static void coroutine_fn backup_close_vma_stream(void *opaque)
|
||||
@@ -3085,6 +3062,8 @@ static void coroutine_fn backup_close_vma_stream(void *opaque)
|
||||
|
||||
static void pvebackup_complete_cb(void *opaque, int ret)
|
||||
{
|
||||
+ // This always runs in the main loop
|
||||
+
|
||||
PVEBackupDevInfo *di = opaque;
|
||||
|
||||
di->completed = true;
|
||||
@@ -3094,8 +3073,6 @@ static void pvebackup_complete_cb(void *opaque, int ret)
|
||||
ret, strerror(-ret));
|
||||
}
|
||||
|
||||
- BlockDriverState *bs = di->bs;
|
||||
-
|
||||
di->bs = NULL;
|
||||
di->target = NULL;
|
||||
|
||||
@@ -3104,7 +3081,11 @@ static void pvebackup_complete_cb(void *opaque, int ret)
|
||||
qemu_coroutine_enter(co);
|
||||
}
|
||||
|
||||
- block_job_cb(bs, ret);
|
||||
+ // remove self from job queue
|
||||
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||
+ backup_state.di_list = g_list_remove(backup_state.di_list, di);
|
||||
+ g_free(di);
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
|
||||
if (!backup_state.cancel) {
|
||||
pvebackup_run_next_job();
|
||||
@@ -3114,6 +3095,12 @@ static void pvebackup_complete_cb(void *opaque, int ret)
|
||||
static void pvebackup_cancel(void *opaque)
|
||||
{
|
||||
backup_state.cancel = true;
|
||||
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||
+ // Avoid race between block jobs and backup-cancel command:
|
||||
+ if (!backup_state.vmaw) {
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
if (!backup_state.error) {
|
||||
error_setg(&backup_state.error, "backup cancelled");
|
||||
@@ -3131,13 +3118,17 @@ static void pvebackup_cancel(void *opaque)
|
||||
if (!di->completed && di->bs) {
|
||||
BlockJob *job = di->bs->job;
|
||||
if (job) {
|
||||
+ AioContext *aio_context = blk_get_aio_context(job->blk);
|
||||
+ aio_context_acquire(aio_context);
|
||||
if (!di->completed) {
|
||||
- block_job_cancel_sync(job);
|
||||
+ block_job_cancel(job);
|
||||
}
|
||||
+ aio_context_release(aio_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
pvebackup_cleanup();
|
||||
}
|
||||
|
||||
@@ -3193,24 +3184,31 @@ static int config_to_vma(const char *file, BackupFormat format,
|
||||
bool block_job_should_pause(BlockJob *job);
|
||||
static void pvebackup_run_next_job(void)
|
||||
{
|
||||
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||
+
|
||||
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;
|
||||
+ AioContext *aio_context = blk_get_aio_context(job->blk);
|
||||
+ aio_context_acquire(aio_context);
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
if (block_job_should_pause(job)) {
|
||||
- bool cancel = backup_state.error || backup_state.cancel;
|
||||
- if (cancel) {
|
||||
- block_job_cancel(job);
|
||||
+ if (backup_state.error || backup_state.cancel) {
|
||||
+ block_job_cancel_sync(job);
|
||||
} else {
|
||||
block_job_resume(job);
|
||||
}
|
||||
}
|
||||
+ aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
|
||||
+ // no more jobs, run the cleanup
|
||||
pvebackup_cleanup();
|
||||
}
|
||||
|
||||
@@ -3233,6 +3231,11 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||
UuidInfo *uuid_info;
|
||||
BlockJob *job;
|
||||
|
||||
+ if (!backup_state.backup_mutex_initialized) {
|
||||
+ qemu_mutex_init(&backup_state.backup_mutex);
|
||||
+ backup_state.backup_mutex_initialized = true;
|
||||
+ }
|
||||
+
|
||||
if (backup_state.di_list) {
|
||||
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
|
||||
"previous backup not finished");
|
||||
@@ -3405,6 +3408,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||
uuid_copy(backup_state.uuid, uuid);
|
||||
uuid_unparse_lower(uuid, backup_state.uuid_str);
|
||||
|
||||
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||
backup_state.di_list = di_list;
|
||||
|
||||
backup_state.total = total;
|
||||
@@ -3428,6 +3432,8 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||
block_job_start(job);
|
||||
}
|
||||
|
||||
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||
+
|
||||
if (!backup_state.error) {
|
||||
pvebackup_run_next_job(); // run one job
|
||||
}
|
||||
diff --git a/blockjob.c b/blockjob.c
|
||||
index cb3741f6dd..199d5852db 100644
|
||||
--- a/blockjob.c
|
||||
+++ b/blockjob.c
|
||||
@@ -37,8 +37,8 @@
|
||||
#include "qemu/timer.h"
|
||||
#include "qapi-event.h"
|
||||
|
||||
-void block_job_event_cancelled(BlockJob *job);
|
||||
-void block_job_event_completed(BlockJob *job, const char *msg);
|
||||
+static void block_job_event_cancelled(BlockJob *job);
|
||||
+static void block_job_event_completed(BlockJob *job, const char *msg);
|
||||
|
||||
/* Transactional group of block jobs */
|
||||
struct BlockJobTxn {
|
||||
@@ -688,7 +688,7 @@ static void block_job_iostatus_set_err(BlockJob *job, int error)
|
||||
}
|
||||
}
|
||||
|
||||
-void block_job_event_cancelled(BlockJob *job)
|
||||
+static void block_job_event_cancelled(BlockJob *job)
|
||||
{
|
||||
if (block_job_is_internal(job)) {
|
||||
return;
|
||||
@@ -702,7 +702,7 @@ void block_job_event_cancelled(BlockJob *job)
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
-void block_job_event_completed(BlockJob *job, const char *msg)
|
||||
+static void block_job_event_completed(BlockJob *job, const char *msg)
|
||||
{
|
||||
if (block_job_is_internal(job)) {
|
||||
return;
|
||||
--
|
||||
2.11.0
|
||||
|
@ -1,165 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
Date: Thu, 15 Feb 2018 11:07:56 +0100
|
||||
Subject: [PATCH] vma: add throttling options to drive mapping fifo protocol
|
||||
|
||||
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
---
|
||||
vma.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
|
||||
1 file changed, 73 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/vma.c b/vma.c
|
||||
index 04915427c8..91ae14cdc3 100644
|
||||
--- a/vma.c
|
||||
+++ b/vma.c
|
||||
@@ -18,7 +18,9 @@
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/main-loop.h"
|
||||
+#include "qemu/cutils.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
+#include "qapi/qmp/qint.h"
|
||||
#include "sysemu/char.h" /* qstring_from_str */
|
||||
#include "sysemu/block-backend.h"
|
||||
|
||||
@@ -133,9 +135,39 @@ typedef struct RestoreMap {
|
||||
char *devname;
|
||||
char *path;
|
||||
char *format;
|
||||
+ uint64_t throttling_bps;
|
||||
+ char *throttling_group;
|
||||
bool write_zero;
|
||||
} RestoreMap;
|
||||
|
||||
+static bool try_parse_option(char **line, const char *optname, char **out, const char *inbuf) {
|
||||
+ size_t optlen = strlen(optname);
|
||||
+ if (strncmp(*line, optname, optlen) != 0 || (*line)[optlen] != '=') {
|
||||
+ return false;
|
||||
+ }
|
||||
+ if (*out) {
|
||||
+ g_error("read map failed - duplicate value for option '%s'", optname);
|
||||
+ }
|
||||
+ char *value = (*line) + optlen + 1; /* including a '=' */
|
||||
+ char *colon = strchr(value, ':');
|
||||
+ if (!colon) {
|
||||
+ g_error("read map failed - option '%s' not terminated ('%s')",
|
||||
+ optname, inbuf);
|
||||
+ }
|
||||
+ *line = colon+1;
|
||||
+ *out = g_strndup(value, colon - value);
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static uint64_t verify_u64(const char *text) {
|
||||
+ uint64_t value;
|
||||
+ const char *endptr = NULL;
|
||||
+ if (qemu_strtou64(text, &endptr, 0, &value) != 0 || !endptr || *endptr) {
|
||||
+ g_error("read map failed - not a number: %s", text);
|
||||
+ }
|
||||
+ return value;
|
||||
+}
|
||||
+
|
||||
static int extract_content(int argc, char **argv)
|
||||
{
|
||||
int c, ret = 0;
|
||||
@@ -209,6 +241,9 @@ static int extract_content(int argc, char **argv)
|
||||
while (1) {
|
||||
char inbuf[8192];
|
||||
char *line = fgets(inbuf, sizeof(inbuf), map);
|
||||
+ char *format = NULL;
|
||||
+ char *bps = NULL;
|
||||
+ char *group = NULL;
|
||||
if (!line || line[0] == '\0' || !strcmp(line, "done\n")) {
|
||||
break;
|
||||
}
|
||||
@@ -220,15 +255,19 @@ 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);
|
||||
+ while (1) {
|
||||
+ if (!try_parse_option(&line, "format", &format, inbuf) &&
|
||||
+ !try_parse_option(&line, "throttling.bps", &bps, inbuf) &&
|
||||
+ !try_parse_option(&line, "throttling.group", &group, inbuf))
|
||||
+ {
|
||||
+ break;
|
||||
}
|
||||
- format = g_strndup(format, colon - format);
|
||||
- line = colon+1;
|
||||
+ }
|
||||
+
|
||||
+ uint64_t bps_value = 0;
|
||||
+ if (bps) {
|
||||
+ bps_value = verify_u64(bps);
|
||||
+ g_free(bps);
|
||||
}
|
||||
|
||||
const char *path;
|
||||
@@ -254,6 +293,8 @@ static int extract_content(int argc, char **argv)
|
||||
map->devname = g_strdup(devname);
|
||||
map->path = g_strdup(path);
|
||||
map->format = format;
|
||||
+ map->throttling_bps = bps_value;
|
||||
+ map->throttling_group = group;
|
||||
map->write_zero = write_zero;
|
||||
|
||||
g_hash_table_insert(devmap, map->devname, map);
|
||||
@@ -281,6 +322,8 @@ static int extract_content(int argc, char **argv)
|
||||
} else if (di) {
|
||||
char *devfn = NULL;
|
||||
const char *format = NULL;
|
||||
+ uint64_t throttling_bps = 0;
|
||||
+ const char *throttling_group = NULL;
|
||||
int flags = BDRV_O_RDWR | BDRV_O_NO_FLUSH;
|
||||
bool write_zero = true;
|
||||
|
||||
@@ -292,6 +335,8 @@ static int extract_content(int argc, char **argv)
|
||||
}
|
||||
devfn = map->path;
|
||||
format = map->format;
|
||||
+ throttling_bps = map->throttling_bps;
|
||||
+ throttling_group = map->throttling_group;
|
||||
write_zero = map->write_zero;
|
||||
} else {
|
||||
devfn = g_strdup_printf("%s/tmp-disk-%s.raw",
|
||||
@@ -328,12 +373,31 @@ static int extract_content(int argc, char **argv)
|
||||
qdict_put(options, "driver", qstring_from_str("raw"));
|
||||
}
|
||||
|
||||
-
|
||||
if (errp || !(blk = blk_new_open(devfn, NULL, options, flags, &errp))) {
|
||||
g_error("can't open file %s - %s", devfn,
|
||||
error_get_pretty(errp));
|
||||
}
|
||||
|
||||
+ if (throttling_group) {
|
||||
+ blk_io_limits_enable(blk, throttling_group);
|
||||
+ }
|
||||
+
|
||||
+ if (throttling_bps) {
|
||||
+ if (!throttling_group) {
|
||||
+ blk_io_limits_enable(blk, devfn);
|
||||
+ }
|
||||
+
|
||||
+ ThrottleConfig cfg;
|
||||
+ throttle_config_init(&cfg);
|
||||
+ cfg.buckets[THROTTLE_BPS_WRITE].avg = throttling_bps;
|
||||
+ Error *err = NULL;
|
||||
+ if (!throttle_is_valid(&cfg, &err)) {
|
||||
+ error_report_err(err);
|
||||
+ g_error("failed to apply throttling");
|
||||
+ }
|
||||
+ blk_set_io_limits(blk, &cfg);
|
||||
+ }
|
||||
+
|
||||
if (vma_reader_register_bs(vmar, i, blk, write_zero, &errp) < 0) {
|
||||
g_error("%s", error_get_pretty(errp));
|
||||
}
|
||||
--
|
||||
2.11.0
|
||||
|
74
debian/patches/series
vendored
74
debian/patches/series
vendored
@ -1,4 +1,4 @@
|
||||
pve/0001-fr-ca-keymap-corrections.patch
|
||||
pve/0001-block-file-change-locking-default-to-off.patch
|
||||
pve/0002-Adjust-network-script-path-to-etc-kvm.patch
|
||||
pve/0003-qemu-img-return-success-on-info-without-snapshots.patch
|
||||
pve/0004-use-kvm-by-default.patch
|
||||
@ -15,65 +15,15 @@ pve/0014-use-whitespace-between-VERSION-and-PKGVERSION.patch
|
||||
pve/0015-vnc-altgr-emulation.patch
|
||||
pve/0016-vnc-make-x509-imply-tls-again.patch
|
||||
pve/0017-vnc-PVE-VNC-authentication.patch
|
||||
pve/0018-migrate-fix-possible-unitialised-return-value.patch
|
||||
pve/0019-block-rbd-disable-rbd_cache_writethrough_until_flush.patch
|
||||
pve/0020-block-snapshot-qmp_snapshot_drive-add-aiocontext.patch
|
||||
pve/0021-block-snapshot-qmp_delete_drive_snapshot-add-aiocont.patch
|
||||
pve/0022-glusterfs-no-default-logfile-if-daemonized.patch
|
||||
pve/0023-glusterfs-allow-partial-reads.patch
|
||||
pve/0024-block-add-the-zeroinit-block-driver-filter.patch
|
||||
pve/0025-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch
|
||||
pve/0026-backup-modify-job-api.patch
|
||||
pve/0027-backup-introduce-vma-archive-format.patch
|
||||
pve/0028-adding-old-vma-files.patch
|
||||
pve/0029-backup-fix-race-in-backup-stop-command.patch
|
||||
pve/0030-vma-add-throttling-options-to-drive-mapping-fifo-pro.patch
|
||||
pve/0018-block-rbd-disable-rbd_cache_writethrough_until_flush.patch
|
||||
pve/0019-block-snapshot-qmp_snapshot_drive-add-aiocontext.patch
|
||||
pve/0020-block-snapshot-qmp_delete_drive_snapshot-add-aiocont.patch
|
||||
pve/0021-glusterfs-no-default-logfile-if-daemonized.patch
|
||||
pve/0022-glusterfs-allow-partial-reads.patch
|
||||
pve/0023-block-add-the-zeroinit-block-driver-filter.patch
|
||||
pve/0024-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch
|
||||
pve/0025-backup-modify-job-api.patch
|
||||
pve/0026-backup-introduce-vma-archive-format.patch
|
||||
pve/0027-adding-old-vma-files.patch
|
||||
extra/0001-Revert-target-i386-disable-LINT0-after-reset.patch
|
||||
extra/0002-virtio-serial-fix-segfault-on-disconnect.patch
|
||||
extra/0003-megasas-always-store-SCSIRequest-into-MegasasCmd.patch
|
||||
extra/0004-slirp-check-len-against-dhcp-options-array-end.patch
|
||||
extra/0005-IDE-Do-not-flush-empty-CDROM-drives.patch
|
||||
extra/0006-bitmap-add-bitmap_copy_and_clear_atomic.patch
|
||||
extra/0007-memory-add-support-getting-and-using-a-dirty-bitmap-.patch
|
||||
extra/0008-vga-add-vga_scanline_invalidated-helper.patch
|
||||
extra/0009-vga-make-display-updates-thread-safe.patch
|
||||
extra/0010-vga-fix-display-update-region-calculation.patch
|
||||
extra/0011-vga-fix-display-update-region-calculation-split-scre.patch
|
||||
extra/0012-vga-stop-passing-pointers-to-vga_draw_line-functions.patch
|
||||
extra/0013-multiboot-validate-multiboot-header-address-values.patch
|
||||
extra/0014-virtio-fix-descriptor-counting-in-virtqueue_pop.patch
|
||||
extra/0015-nbd-server-CVE-2017-15119-Reject-options-larger-than.patch
|
||||
extra/0016-vga-migration-Update-memory-map-in-post_load.patch
|
||||
extra/0017-vga-drop-line_offset-variable.patch
|
||||
extra/0018-vga-handle-cirrus-vbe-mode-wraparounds.patch
|
||||
extra/0019-vga-add-ram_addr_t-cast.patch
|
||||
extra/0020-vga-fix-region-checks-in-wraparound-case.patch
|
||||
extra/0021-io-monitor-encoutput-buffer-size-from-websocket-GSou.patch
|
||||
extra/0022-9pfs-use-g_malloc0-to-allocate-space-for-xattr.patch
|
||||
extra/0023-cirrus-fix-oob-access-in-mode4and5-write-functions.patch
|
||||
extra/0024-virtio-check-VirtQueue-Vring-object-is-set.patch
|
||||
extra/0025-block-gluster-glfs_lseek-workaround.patch
|
||||
extra/0026-gluster-add-support-for-PREALLOC_MODE_FALLOC.patch
|
||||
extra/0027-target-i386-Use-host_vendor_fms-in-max_x86_cpu_initf.patch
|
||||
extra/0028-target-i386-Define-CPUID_MODEL_ID_SZ-macro.patch
|
||||
extra/0029-target-i386-Don-t-use-x86_cpu_load_def-on-max-CPU-mo.patch
|
||||
extra/0030-i386-Change-X86CPUDefinition-model_id-to-const-char.patch
|
||||
extra/0031-i386-Add-support-for-SPEC_CTRL-MSR.patch
|
||||
extra/0032-i386-Add-spec-ctrl-CPUID-bit.patch
|
||||
extra/0033-i386-Add-FEAT_8000_0008_EBX-CPUID-feature-word.patch
|
||||
extra/0034-i386-Add-new-IBRS-versions-of-Intel-CPU-models.patch
|
||||
extra/0035-ratelimit-don-t-align-wait-time-with-slices.patch
|
||||
extra/0036-nbd-make-it-thread-safe-fix-qcow2-over-nbd.patch
|
||||
extra/0037-nbd-strict-nbd_wr_syncv.patch
|
||||
extra/0038-nbd-read_sync-and-friends-return-0-on-success.patch
|
||||
extra/0039-nbd-make-nbd_drop-public.patch
|
||||
extra/0040-nbd-server-get-rid-of-nbd_negotiate_read-and-friends.patch
|
||||
extra/0041-nbd-client-Fix-regression-when-server-sends-garbage.patch
|
||||
extra/0042-fix-build-failure-in-nbd_read_reply_entry.patch
|
||||
extra/0043-nbd-client-avoid-spurious-qio_channel_yield-re-entry.patch
|
||||
extra/0044-nbd-client-avoid-read_reply_co-entry-if-send-failed.patch
|
||||
extra/0045-qemu-iotests-improve-nbd-fault-injector.py-startup-p.patch
|
||||
extra/0046-qemu-iotests-test-NBD-over-UNIX-domain-sockets-in-08.patch
|
||||
extra/0047-block-nbd-client-nbd_co_send_request-fix-return-code.patch
|
||||
extra/0048-target-i386-cpu-Add-new-EPYC-CPU-model.patch
|
||||
extra/0049-i386-Add-EPYC-IBPB-CPU-model.patch
|
||||
extra/0002-ratelimit-don-t-align-wait-time-with-slices.patch
|
||||
|
27
keycodemapdb/LICENSE.BSD
Normal file
27
keycodemapdb/LICENSE.BSD
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) Individual contributors.
|
||||
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 PyCA Cryptography 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
339
keycodemapdb/LICENSE.GPL2
Normal file
339
keycodemapdb/LICENSE.GPL2
Normal file
@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
114
keycodemapdb/README
Normal file
114
keycodemapdb/README
Normal file
@ -0,0 +1,114 @@
|
||||
Key code / scan code / key symbol mapping database
|
||||
==================================================
|
||||
|
||||
This module provides a database that maps between different
|
||||
key code / scan code / key symbol sets:
|
||||
|
||||
- Linux evdev
|
||||
- OS-X
|
||||
- AT Set 1
|
||||
- AT Set 2
|
||||
- AT Set 3
|
||||
- XT
|
||||
- Linux XT KBD driver
|
||||
- USB HID
|
||||
- Win32
|
||||
- XWin XT
|
||||
- XKBD XT
|
||||
- Xorg Evdev
|
||||
- Xorg KBD
|
||||
- Xorg OS-X
|
||||
- XOrg Cygwin
|
||||
- RFB
|
||||
|
||||
Licensing
|
||||
---------
|
||||
|
||||
The contents of this package are dual licensed under the terms of:
|
||||
|
||||
- GNU General Public License (version 2 or later)
|
||||
- 3-clause BSD License
|
||||
|
||||
The output files generated by keymap-gen may be distributed & used under
|
||||
the terms of either of the above licenses.
|
||||
|
||||
Data formats
|
||||
------------
|
||||
|
||||
The following output formats are possible
|
||||
|
||||
- Code map
|
||||
|
||||
An array mapping between key code sets values
|
||||
|
||||
Indexes in the array are values from the source code set.
|
||||
Entries in the array are values from the target code set
|
||||
|
||||
|
||||
- Code table
|
||||
|
||||
An array listing all values in a key code set
|
||||
|
||||
Indexes in the array are simply a numeric counter
|
||||
Entries in the array are values from the key code set
|
||||
|
||||
The size of the array matches the total number of entries in
|
||||
the keycode database.
|
||||
|
||||
|
||||
- Name map
|
||||
|
||||
An array mapping between key code sets values and names
|
||||
|
||||
Indexes in the array are values from the source code set
|
||||
Entries in the array are names from the target code set
|
||||
|
||||
|
||||
- Name table
|
||||
|
||||
An array listing all names in a key code set
|
||||
|
||||
Indexes in the array are simply a numeric counter
|
||||
Entries in the array are values from the key code set
|
||||
|
||||
The size of the array matches the total number of entries in
|
||||
the keycode database.
|
||||
|
||||
|
||||
Output languages
|
||||
----------------
|
||||
|
||||
The tool is capable of generating data tables for the following
|
||||
programming languages / environments
|
||||
|
||||
- Standard C
|
||||
- GLib2 (standard C, but with GLib2 data types)
|
||||
- Python
|
||||
- Perl
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Map values from AT Set 1 to USB HID, generating tables for the
|
||||
C programming language
|
||||
|
||||
$ keymap-gen --lang stdc code-map data/keymaps.csv atset1 usb
|
||||
|
||||
Generate a tables of names for Linux key codes, OS-X key codes,
|
||||
in python - equivalent array indexes map between the two sets.
|
||||
A variable name override is used
|
||||
|
||||
$ keymap-gen --varname linux_keycodes --lang stdc \
|
||||
code-table data/keymaps.csv linux
|
||||
$ keymap-gen --varname osx_keycodes --lang stdc \
|
||||
code-table data/keymaps.csv os-x
|
||||
|
||||
Generate a mapping from XOrg XWin values to Win32 names
|
||||
|
||||
$ keymap-gen --lang perl name-map data/keymaps.csv xorgxwin win32
|
||||
|
||||
Generate a table of names for Linux key codes in Perl
|
||||
|
||||
$ keymap-gen --lang perl name-table data/keymaps.csv linux
|
||||
|
89
keycodemapdb/data/README
Normal file
89
keycodemapdb/data/README
Normal file
@ -0,0 +1,89 @@
|
||||
This directory contains the raw data for mapping between different
|
||||
keyboard codes. Naming if often based on the US keyboard layout, but
|
||||
does not indicate the symbol actually generated by the key.
|
||||
|
||||
The columns currently in this data set are:
|
||||
|
||||
Linux
|
||||
-----
|
||||
|
||||
Name and value of the hardware independent keycodes used by the linux
|
||||
kernel and exposed through the input subsystem.
|
||||
|
||||
References: linux/input.h
|
||||
|
||||
macOS
|
||||
-----
|
||||
|
||||
Low level key codes as exposed by Mac OS X/macOS.
|
||||
|
||||
References: Carbon/HIToolbox/Events.h
|
||||
|
||||
PC scan code sets
|
||||
-----------------
|
||||
|
||||
Scan codes for the three orignal PC keyboard generations:
|
||||
|
||||
Set 1: XT
|
||||
Set 2: AT
|
||||
Set 3: PS/2
|
||||
|
||||
The sets include codes for modern keys as well and not just the keys
|
||||
present on those original keyboards.
|
||||
|
||||
References: linux/drivers/input/keyboard/atkbd.c
|
||||
|
||||
USB HID
|
||||
-------
|
||||
|
||||
Codes as specified by the HID profile in USB.
|
||||
|
||||
References: linux/drivers/hid/usbhid/usbkbd.c
|
||||
|
||||
Windows Virtual-key codes
|
||||
-------------------------
|
||||
|
||||
The low level, hardware independent "VKEYs" exposed by Windows.
|
||||
|
||||
References: mingw32/winuser.h
|
||||
|
||||
XWin XT
|
||||
-------
|
||||
|
||||
X11 keycodes generated by the XWin server. Based on the XT scan code
|
||||
set.
|
||||
|
||||
References: xorg-server/hw/xwin/{winkeybd.c,winkeynames.h}
|
||||
|
||||
Xfree86 KBD XT
|
||||
--------------
|
||||
|
||||
X11 keycodes generated by the Xfree86 keyboard drivers. Based on the XT
|
||||
scan code set.
|
||||
|
||||
References: xf86-input-keyboard/src/at_scancode.c
|
||||
|
||||
X11 keysyms
|
||||
-----------
|
||||
|
||||
Corresponding X11 keysym value(s) for a US keyboard layout.
|
||||
|
||||
WARNING: These columns represent symbols, not physical keys, and should
|
||||
be used with extreme care.
|
||||
|
||||
References: http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
|
||||
|
||||
HTML KeyboardEvent.code
|
||||
-----------------------
|
||||
|
||||
Key codes seen in the KeyboardEvent.code attribute as part of the
|
||||
UI Events specification.
|
||||
|
||||
References: https://www.w3.org/TR/uievents-code/
|
||||
|
||||
XKEYBOARD key names
|
||||
-------------------
|
||||
|
||||
Hardware independent key names as used in the XKEYBOARD extension.
|
||||
|
||||
References: /usr/share/X11/xkb/keycodes/
|
539
keycodemapdb/data/keymaps.csv
Normal file
539
keycodemapdb/data/keymaps.csv
Normal file
@ -0,0 +1,539 @@
|
||||
"Linux Name","Linux Keycode","OS-X Name","OS-X Keycode","AT set1 keycode","AT set2 keycode","AT set3 keycode","USB Keycodes","Win32 Name","Win32 Keycode","Xwin XT","Xfree86 KBD XT","X11 keysym name","X11 keysym","HTML code","XKB key name","QEMU QKeyCode","Sun KBD","Apple ADB"
|
||||
KEY_RESERVED,0,,0xff,,,,,,,,,,,,,unmapped,,0xff
|
||||
KEY_ESC,1,Escape,0x35,0x01,0x76,0x08,41,VK_ESCAPE,0x1b,1,1,XK_Escape,0xff1b,Escape,ESC,esc,0x1d,0x35
|
||||
KEY_1,2,ANSI_1,0x12,0x02,0x16,0x16,30,VK_1,0x31,2,2,XK_1,0x0031,Digit1,AE01,1,0x1e,0x12
|
||||
KEY_1,2,ANSI_1,0x12,0x02,0x16,0x16,30,VK_1,0x31,2,2,XK_exclam,0x0021,Digit1,AE01,1,0x1e,0x12
|
||||
KEY_2,3,ANSI_2,0x13,0x03,0x1e,0x1e,31,VK_2,0x32,3,3,XK_2,0x0032,Digit2,AE02,2,0x1f,0x13
|
||||
KEY_2,3,ANSI_2,0x13,0x03,0x1e,0x1e,31,VK_2,0x32,3,3,XK_at,0x0040,Digit2,AE02,2,0x1f,0x13
|
||||
KEY_3,4,ANSI_3,0x14,0x04,0x26,0x26,32,VK_3,0x33,4,4,XK_3,0x0033,Digit3,AE03,3,0x20,0x14
|
||||
KEY_3,4,ANSI_3,0x14,0x04,0x26,0x26,32,VK_3,0x33,4,4,XK_numbersign,0x0023,Digit3,AE03,3,0x20,0x14
|
||||
KEY_4,5,ANSI_4,0x15,0x05,0x25,0x25,33,VK_4,0x34,5,5,XK_4,0x0034,Digit4,AE04,4,0x21,0x15
|
||||
KEY_4,5,ANSI_4,0x15,0x05,0x25,0x25,33,VK_4,0x34,5,5,XK_dollar,0x0024,Digit4,AE04,4,0x21,0x15
|
||||
KEY_5,6,ANSI_5,0x17,0x06,0x2e,0x2e,34,VK_5,0x35,6,6,XK_5,0x0035,Digit5,AE05,5,0x22,0x17
|
||||
KEY_5,6,ANSI_5,0x17,0x06,0x2e,0x2e,34,VK_5,0x35,6,6,XK_percent,0x0025,Digit5,AE05,5,0x22,0x17
|
||||
KEY_6,7,ANSI_6,0x16,0x07,0x36,0x36,35,VK_6,0x36,7,7,XK_6,0x0036,Digit6,AE06,6,0x23,0x16
|
||||
KEY_6,7,ANSI_6,0x16,0x07,0x36,0x36,35,VK_6,0x36,7,7,XK_asciicircum,0x005e,Digit6,AE06,6,0x23,0x16
|
||||
KEY_7,8,ANSI_7,0x1a,0x08,0x3d,0x3d,36,VK_7,0x37,8,8,XK_7,0x0037,Digit7,AE07,7,0x24,0x1a
|
||||
KEY_7,8,ANSI_7,0x1a,0x08,0x3d,0x3d,36,VK_7,0x37,8,8,XK_ampersand,0x0026,Digit7,AE07,7,0x24,0x1a
|
||||
KEY_8,9,ANSI_8,0x1c,0x09,0x3e,0x3e,37,VK_8,0x38,9,9,XK_8,0x0038,Digit8,AE08,8,0x25,0x1c
|
||||
KEY_8,9,ANSI_8,0x1c,0x09,0x3e,0x3e,37,VK_8,0x38,9,9,XK_asterisk,0x002a,Digit8,AE08,8,0x25,0x1c
|
||||
KEY_9,10,ANSI_9,0x19,0x0a,0x46,0x46,38,VK_9,0x39,10,10,XK_9,0x0039,Digit9,AE09,9,0x26,0x19
|
||||
KEY_9,10,ANSI_9,0x19,0x0a,0x46,0x46,38,VK_9,0x39,10,10,XK_parenleft,0x0028,Digit9,AE09,9,0x26,0x19
|
||||
KEY_0,11,ANSI_0,0x1d,0x0b,0x45,0x45,39,VK_0,0x30,11,11,XK_0,0x0030,Digit0,AE10,0,0x27,0x1d
|
||||
KEY_0,11,ANSI_0,0x1d,0x0b,0x45,0x45,39,VK_0,0x30,11,11,XK_parenright,0x0029,Digit0,AE10,0,0x27,0x1d
|
||||
KEY_MINUS,12,ANSI_Minus,0x1b,0x0c,0x4e,0x4e,45,VK_OEM_MINUS,0xbd,12,12,XK_minus,0x002d,Minus,AE11,minus,0x28,0x1b
|
||||
KEY_MINUS,12,ANSI_Minus,0x1b,0x0c,0x4e,0x4e,45,VK_OEM_MINUS,0xbd,12,12,XK_underscore,0x005f,Minus,AE11,minus,0x28,0x1b
|
||||
KEY_EQUAL,13,ANSI_Equal,0x18,0x0d,0x55,0x55,46,VK_OEM_PLUS,0xbb,13,13,XK_equal,0x003d,Equal,AE12,equal,0x29,0x18
|
||||
KEY_EQUAL,13,ANSI_Equal,0x18,0x0d,0x55,0x55,46,VK_OEM_PLUS,0xbb,13,13,XK_plus,0x002b,Equal,AE12,equal,0x29,0x18
|
||||
KEY_BACKSPACE,14,Delete,0x33,0x0e,0x66,0x66,42,VK_BACK,0x08,14,14,XK_BackSpace,0xff08,Backspace,BKSP,backspace,0x2b,0x33
|
||||
KEY_TAB,15,Tab,0x30,0x0f,0x0d,0x0d,43,VK_TAB,0x09,15,15,XK_Tab,0xff09,Tab,TAB,tab,0x35,0x30
|
||||
KEY_Q,16,ANSI_Q,0xc,0x10,0x15,0x15,20,VK_Q,0x51,16,16,XK_Q,0x0051,KeyQ,AD01,q,0x36,0xc
|
||||
KEY_Q,16,ANSI_Q,0xc,0x10,0x15,0x15,20,VK_Q,0x51,16,16,XK_q,0x0071,KeyQ,AD01,q,0x36,0xc
|
||||
KEY_W,17,ANSI_W,0xd,0x11,0x1d,0x1d,26,VK_W,0x57,17,17,XK_W,0x0057,KeyW,AD02,w,0x37,0xd
|
||||
KEY_W,17,ANSI_W,0xd,0x11,0x1d,0x1d,26,VK_W,0x57,17,17,XK_w,0x0077,KeyW,AD02,w,0x37,0xd
|
||||
KEY_E,18,ANSI_E,0xe,0x12,0x24,0x24,8,VK_E,0x45,18,18,XK_E,0x0045,KeyE,AD03,e,0x38,0xe
|
||||
KEY_E,18,ANSI_E,0xe,0x12,0x24,0x24,8,VK_E,0x45,18,18,XK_e,0x0065,KeyE,AD03,e,0x38,0xe
|
||||
KEY_R,19,ANSI_R,0xf,0x13,0x2d,0x2d,21,VK_R,0x52,19,19,XK_R,0x0052,KeyR,AD04,r,0x39,0xf
|
||||
KEY_R,19,ANSI_R,0xf,0x13,0x2d,0x2d,21,VK_R,0x52,19,19,XK_r,0x0072,KeyR,AD04,r,0x39,0xf
|
||||
KEY_T,20,ANSI_T,0x11,0x14,0x2c,0x2c,23,VK_T,0x54,20,20,XK_T,0x0054,KeyT,AD05,t,0x3a,0x11
|
||||
KEY_T,20,ANSI_T,0x11,0x14,0x2c,0x2c,23,VK_T,0x54,20,20,XK_t,0x0074,KeyT,AD05,t,0x3a,0x11
|
||||
KEY_Y,21,ANSI_Y,0x10,0x15,0x35,0x35,28,VK_Y,0x59,21,21,XK_Y,0x0059,KeyY,AD06,y,0x3b,0x10
|
||||
KEY_Y,21,ANSI_Y,0x10,0x15,0x35,0x35,28,VK_Y,0x59,21,21,XK_y,0x0079,KeyY,AD06,y,0x3b,0x10
|
||||
KEY_U,22,ANSI_U,0x20,0x16,0x3c,0x3c,24,VK_U,0x55,22,22,XK_U,0x0055,KeyU,AD07,u,0x3c,0x20
|
||||
KEY_U,22,ANSI_U,0x20,0x16,0x3c,0x3c,24,VK_U,0x55,22,22,XK_u,0x0075,KeyU,AD07,u,0x3c,0x20
|
||||
KEY_I,23,ANSI_I,0x22,0x17,0x43,0x43,12,VK_I,0x49,23,23,XK_I,0x0049,KeyI,AD08,i,0x3d,0x22
|
||||
KEY_I,23,ANSI_I,0x22,0x17,0x43,0x43,12,VK_I,0x49,23,23,XK_i,0x0069,KeyI,AD08,i,0x3d,0x22
|
||||
KEY_O,24,ANSI_O,0x1f,0x18,0x44,0x44,18,VK_O,0x4f,24,24,XK_O,0x004f,KeyO,AD09,o,0x3e,0x1f
|
||||
KEY_O,24,ANSI_O,0x1f,0x18,0x44,0x44,18,VK_O,0x4f,24,24,XK_o,0x006f,KeyO,AD09,o,0x3e,0x1f
|
||||
KEY_P,25,ANSI_P,0x23,0x19,0x4d,0x4d,19,VK_P,0x50,25,25,XK_P,0x0050,KeyP,AD10,p,0x3f,0x23
|
||||
KEY_P,25,ANSI_P,0x23,0x19,0x4d,0x4d,19,VK_P,0x50,25,25,XK_p,0x0070,KeyP,AD10,p,0x3f,0x23
|
||||
KEY_LEFTBRACE,26,ANSI_LeftBracket,0x21,0x1a,0x54,0x54,47,VK_OEM_4,0xdb,26,26,XK_bracketleft,0x005b,BracketLeft,AD11,bracket_left,0x40,0x21
|
||||
KEY_LEFTBRACE,26,ANSI_LeftBracket,0x21,0x1a,0x54,0x54,47,VK_OEM_4,0xdb,26,26,XK_braceleft,0x007b,BracketLeft,AD11,bracket_left,0x40,0x21
|
||||
KEY_RIGHTBRACE,27,ANSI_RightBracket,0x1e,0x1b,0x5b,0x5b,48,VK_OEM_6,0xdd,27,27,XK_bracketright,0x005d,BracketRight,AD12,bracket_right,0x41,0x1e
|
||||
KEY_RIGHTBRACE,27,ANSI_RightBracket,0x1e,0x1b,0x5b,0x5b,48,VK_OEM_6,0xdd,27,27,XK_braceright,0x007d,BracketRight,AD12,bracket_right,0x41,0x1e
|
||||
KEY_ENTER,28,Return,0x24,0x1c,0x5a,0x5a,40,VK_RETURN,0x0d,28,28,XK_Return,0xff0d,Enter,RTRN,ret,0x59,0x24
|
||||
KEY_LEFTCTRL,29,Control,0x3b,0x1d,0x14,0x11,224,VK_LCONTROL,0xa2,29,29,XK_Control_L,0xffe3,ControlLeft,LCTL,ctrl,0x4c,0x36
|
||||
KEY_LEFTCTRL,29,Control,0x3b,0x1d,0x14,0x11,224,VK_CONTROL,0x11,29,29,XK_Control_L,0xffe3,ControlLeft,LCTL,ctrl,0x4c,0x36
|
||||
KEY_A,30,ANSI_A,0x0,0x1e,0x1c,0x1c,4,VK_A,0x41,30,30,XK_A,0x0041,KeyA,AC01,a,0x4d,0x0
|
||||
KEY_A,30,ANSI_A,0x0,0x1e,0x1c,0x1c,4,VK_A,0x41,30,30,XK_a,0x0061,KeyA,AC01,a,0x4d,0x0
|
||||
KEY_S,31,ANSI_S,0x1,0x1f,0x1b,0x1b,22,VK_S,0x53,31,31,XK_S,0x0053,KeyS,AC02,s,0x4e,0x1
|
||||
KEY_S,31,ANSI_S,0x1,0x1f,0x1b,0x1b,22,VK_S,0x53,31,31,XK_s,0x0073,KeyS,AC02,s,0x4e,0x1
|
||||
KEY_D,32,ANSI_D,0x2,0x20,0x23,0x23,7,VK_D,0x44,32,32,XK_D,0x0044,KeyD,AC03,d,0x4f,0x2
|
||||
KEY_D,32,ANSI_D,0x2,0x20,0x23,0x23,7,VK_D,0x44,32,32,XK_d,0x0064,KeyD,AC03,d,0x4f,0x2
|
||||
KEY_F,33,ANSI_F,0x3,0x21,0x2b,0x2b,9,VK_F,0x46,33,33,XK_F,0x0046,KeyF,AC04,f,0x50,0x3
|
||||
KEY_F,33,ANSI_F,0x3,0x21,0x2b,0x2b,9,VK_F,0x46,33,33,XK_f,0x0066,KeyF,AC04,f,0x50,0x3
|
||||
KEY_G,34,ANSI_G,0x5,0x22,0x34,0x34,10,VK_G,0x47,34,34,XK_G,0x0047,KeyG,AC05,g,0x51,0x5
|
||||
KEY_G,34,ANSI_G,0x5,0x22,0x34,0x34,10,VK_G,0x47,34,34,XK_g,0x0067,KeyG,AC05,g,0x51,0x5
|
||||
KEY_H,35,ANSI_H,0x4,0x23,0x33,0x33,11,VK_H,0x48,35,35,XK_H,0x0048,KeyH,AC06,h,0x52,0x4
|
||||
KEY_H,35,ANSI_H,0x4,0x23,0x33,0x33,11,VK_H,0x48,35,35,XK_h,0x0068,KeyH,AC06,h,0x52,0x4
|
||||
KEY_J,36,ANSI_J,0x26,0x24,0x3b,0x3b,13,VK_J,0x4a,36,36,XK_J,0x004a,KeyJ,AC07,j,0x53,0x26
|
||||
KEY_J,36,ANSI_J,0x26,0x24,0x3b,0x3b,13,VK_J,0x4a,36,36,XK_j,0x006a,KeyJ,AC07,j,0x53,0x26
|
||||
KEY_K,37,ANSI_K,0x28,0x25,0x42,0x42,14,VK_K,0x4b,37,37,XK_K,0x004b,KeyK,AC08,k,0x54,0x28
|
||||
KEY_K,37,ANSI_K,0x28,0x25,0x42,0x42,14,VK_K,0x4b,37,37,XK_k,0x006b,KeyK,AC08,k,0x54,0x28
|
||||
KEY_L,38,ANSI_L,0x25,0x26,0x4b,0x4b,15,VK_L,0x4c,38,38,XK_L,0x004c,KeyL,AC09,l,0x55,0x25
|
||||
KEY_L,38,ANSI_L,0x25,0x26,0x4b,0x4b,15,VK_L,0x4c,38,38,XK_l,0x006c,KeyL,AC09,l,0x55,0x25
|
||||
KEY_SEMICOLON,39,ANSI_Semicolon,0x29,0x27,0x4c,0x4c,51,VK_OEM_1,0xba,39,39,XK_semicolon,0x003b,Semicolon,AC10,semicolon,0x56,0x29
|
||||
KEY_SEMICOLON,39,ANSI_Semicolon,0x29,0x27,0x4c,0x4c,51,VK_OEM_1,0xba,39,39,XK_colon,0x003a,Semicolon,AC10,semicolon,0x56,0x29
|
||||
KEY_APOSTROPHE,40,ANSI_Quote,0x27,0x28,0x52,0x52,52,VK_OEM_7,0xde,40,40,XK_apostrophe,0x0027,Quote,AC11,apostrophe,0x57,0x27
|
||||
KEY_APOSTROPHE,40,ANSI_Quote,0x27,0x28,0x52,0x52,52,VK_OEM_7,0xde,40,40,XK_quotedbl,0x0022,Quote,AC11,apostrophe,0x57,0x27
|
||||
KEY_GRAVE,41,ANSI_Grave,0x32,0x29,0x0e,0x0e,53,VK_OEM_3,0xc0,41,41,XK_grave,0x0060,Backquote,TLDE,grave_accent,0x2a,0x32
|
||||
KEY_GRAVE,41,ANSI_Grave,0x32,0x29,0x0e,0x0e,53,VK_OEM_3,0xc0,41,41,XK_grave,0x0060,Backquote,AB00,grave_accent,0x2a,0x32
|
||||
KEY_GRAVE,41,ANSI_Grave,0x32,0x29,0x0e,0x0e,53,VK_OEM_3,0xc0,41,41,XK_asciitilde,0x007e,Backquote,TLDE,grave_accent,0x2a,0x32
|
||||
KEY_GRAVE,41,ANSI_Grave,0x32,0x29,0x0e,0x0e,53,VK_OEM_3,0xc0,41,41,XK_asciitilde,0x007e,Backquote,AB00,grave_accent,0x2a,0x32
|
||||
KEY_SHIFT,42,Shift,0x38,0x2a,0x12,0x12,225,VK_SHIFT,0x10,42,42,XK_Shift_L,0xffe1,ShiftLeft,LFSH,shift,0x63,0x38
|
||||
KEY_LEFTSHIFT,42,Shift,0x38,0x2a,0x12,0x12,225,VK_LSHIFT,0xa0,42,42,XK_Shift_L,0xffe1,ShiftLeft,LFSH,shift,0x63,0x38
|
||||
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,49,VK_OEM_5,0xdc,43,43,XK_backslash,0x005c,Backslash,BKSL,backslash,0x58,0x2a
|
||||
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,49,VK_OEM_5,0xdc,43,43,XK_backslash,0x005c,Backslash,AC12,backslash,0x58,0x2a
|
||||
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,49,VK_OEM_5,0xdc,43,43,XK_bar,0x007c,Backslash,BKSL,backslash,0x58,0x2a
|
||||
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,49,VK_OEM_5,0xdc,43,43,XK_bar,0x007c,Backslash,AC12,backslash,0x58,0x2a
|
||||
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,50,VK_OEM_5,0xdc,43,43,XK_backslash,0x005c,Backslash,BKSL,backslash,0x58,0x2a
|
||||
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,50,VK_OEM_5,0xdc,43,43,XK_backslash,0x005c,Backslash,AC12,backslash,0x58,0x2a
|
||||
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,50,VK_OEM_5,0xdc,43,43,XK_bar,0x007c,Backslash,BKSL,backslash,0x58,0x2a
|
||||
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,50,VK_OEM_5,0xdc,43,43,XK_bar,0x007c,Backslash,AC12,backslash,0x58,0x2a
|
||||
KEY_Z,44,ANSI_Z,0x6,0x2c,0x1a,0x1a,29,VK_Z,0x5a,44,44,XK_Z,0x005a,KeyZ,AB01,z,0x64,0x6
|
||||
KEY_Z,44,ANSI_Z,0x6,0x2c,0x1a,0x1a,29,VK_Z,0x5a,44,44,XK_z,0x007a,KeyZ,AB01,z,0x64,0x6
|
||||
KEY_X,45,ANSI_X,0x7,0x2d,0x22,0x22,27,VK_X,0x58,45,45,XK_X,0x0058,KeyX,AB02,x,0x65,0x7
|
||||
KEY_X,45,ANSI_X,0x7,0x2d,0x22,0x22,27,VK_X,0x58,45,45,XK_x,0x0078,KeyX,AB02,x,0x65,0x7
|
||||
KEY_C,46,ANSI_C,0x8,0x2e,0x21,0x21,6,VK_C,0x43,46,46,XK_C,0x0043,KeyC,AB03,c,0x66,0x8
|
||||
KEY_C,46,ANSI_C,0x8,0x2e,0x21,0x21,6,VK_C,0x43,46,46,XK_c,0x0063,KeyC,AB03,c,0x66,0x8
|
||||
KEY_V,47,ANSI_V,0x9,0x2f,0x2a,0x2a,25,VK_V,0x56,47,47,XK_V,0x0056,KeyV,AB04,v,0x67,0x9
|
||||
KEY_V,47,ANSI_V,0x9,0x2f,0x2a,0x2a,25,VK_V,0x56,47,47,XK_v,0x0076,KeyV,AB04,v,0x67,0x9
|
||||
KEY_B,48,ANSI_B,0xb,0x30,0x32,0x32,5,VK_B,0x42,48,48,XK_B,0x0042,KeyB,AB05,b,0x68,0xb
|
||||
KEY_B,48,ANSI_B,0xb,0x30,0x32,0x32,5,VK_B,0x42,48,48,XK_b,0x0062,KeyB,AB05,b,0x68,0xb
|
||||
KEY_N,49,ANSI_N,0x2d,0x31,0x31,0x31,17,VK_N,0x4e,49,49,XK_N,0x004e,KeyN,AB06,n,0x69,0x2d
|
||||
KEY_N,49,ANSI_N,0x2d,0x31,0x31,0x31,17,VK_N,0x4e,49,49,XK_n,0x006e,KeyN,AB06,n,0x69,0x2d
|
||||
KEY_M,50,ANSI_M,0x2e,0x32,0x3a,0x3a,16,VK_M,0x4d,50,50,XK_M,0x004d,KeyM,AB07,m,0x6a,0x2e
|
||||
KEY_M,50,ANSI_M,0x2e,0x32,0x3a,0x3a,16,VK_M,0x4d,50,50,XK_m,0x006d,KeyM,AB07,m,0x6a,0x2e
|
||||
KEY_COMMA,51,ANSI_Comma,0x2b,0x33,0x41,0x41,54,VK_OEM_COMMA,0xbc,51,51,XK_comma,0x002c,Comma,AB08,comma,0x6b,0x2b
|
||||
KEY_COMMA,51,ANSI_Comma,0x2b,0x33,0x41,0x41,54,VK_OEM_COMMA,0xbc,51,51,XK_less,0x003c,Comma,AB08,comma,0x6b,0x2b
|
||||
KEY_DOT,52,ANSI_Period,0x2f,0x34,0x49,0x49,55,VK_OEM_PERIOD,0xbe,52,52,XK_period,0x002e,Period,AB09,dot,0x6c,0x2f
|
||||
KEY_DOT,52,ANSI_Period,0x2f,0x34,0x49,0x49,55,VK_OEM_PERIOD,0xbe,52,52,XK_greater,0x003e,Period,AB09,dot,0x6c,0x2f
|
||||
KEY_SLASH,53,ANSI_Slash,0x2c,0x35,0x4a,0x4a,56,VK_OEM_2,0xbf,53,53,XK_slash,0x002f,Slash,AB10,slash,0x6d,0x2c
|
||||
KEY_SLASH,53,ANSI_Slash,0x2c,0x35,0x4a,0x4a,56,VK_OEM_2,0xbf,53,53,XK_question,0x003f,Slash,AB10,slash,0x6d,0x2c
|
||||
KEY_RIGHTSHIFT,54,RightShift,0x3c,0x36,0x59,0x59,229,VK_RSHIFT,0xa1,54,54,XK_Shift_R,0xffe2,ShiftRight,RTSH,shift_r,0x6e,0x7b
|
||||
KEY_KPASTERISK,55,ANSI_KeypadMultiply,0x43,0x37,0x7c,0x7e,85,VK_MULTIPLY,0x6a,55,55,XK_multiply,0x00d7,NumpadMultiply,KPMU,asterisk,0x2f,0x43
|
||||
KEY_KPASTERISK,55,ANSI_KeypadMultiply,0x43,0x37,0x7c,0x7e,85,VK_MULTIPLY,0x6a,55,55,XK_multiply,0x00d7,NumpadMultiply,KPMU,kp_multiply,0x2f,0x43
|
||||
KEY_LEFTALT,56,Option,0x3a,0x38,0x11,0x19,226,VK_LMENU,0xa4,56,56,XK_Alt_L,0xffe9,AltLeft,LALT,alt,0x13,0x3a
|
||||
KEY_LEFTALT,56,Option,0x3a,0x38,0x11,0x19,226,VK_MENU,0x12,56,56,XK_Alt_L,0xffe9,AltLeft,LALT,alt,0x13,0x3a
|
||||
KEY_SPACE,57,Space,0x31,0x39,0x29,0x29,44,VK_SPACE,0x20,57,57,XK_space,0x0020,Space,SPCE,spc,0x79,0x31
|
||||
KEY_CAPSLOCK,58,CapsLock,0x39,0x3a,0x58,0x14,57,VK_CAPITAL,0x14,58,58,XK_Caps_Lock,0xffe5,CapsLock,CAPS,caps_lock,0x77,0x39
|
||||
KEY_F1,59,F1,0x7a,0x3b,0x05,0x07,58,VK_F1,0x70,59,59,XK_F1,0xffbe,F1,FK01,f1,0x05,0x7a
|
||||
KEY_F2,60,F2,0x78,0x3c,0x06,0x0f,59,VK_F2,0x71,60,60,XK_F2,0xffbf,F2,FK02,f2,0x06,0x78
|
||||
KEY_F3,61,F3,0x63,0x3d,0x04,0x17,60,VK_F3,0x72,61,61,XK_F3,0xffc0,F3,FK03,f3,0x08,0x63
|
||||
KEY_F4,62,F4,0x76,0x3e,0x0c,0x1f,61,VK_F4,0x73,62,62,XK_F4,0xffc1,F4,FK04,f4,0x0a,0x76
|
||||
KEY_F5,63,F5,0x60,0x3f,0x03,0x27,62,VK_F5,0x74,63,63,XK_F5,0xffc2,F5,FK05,f5,0x0c,0x60
|
||||
KEY_F6,64,F6,0x61,0x40,0x0b,0x2f,63,VK_F6,0x75,64,64,XK_F6,0xffc3,F6,FK06,f6,0x0e,0x61
|
||||
KEY_F7,65,F7,0x62,0x41,0x83,0x37,64,VK_F7,0x76,65,65,XK_F7,0xffc4,F7,FK07,f7,0x10,0x62
|
||||
KEY_F8,66,F8,0x64,0x42,0x0a,0x3f,65,VK_F8,0x77,66,66,XK_F8,0xffc5,F8,FK08,f8,0x11,0x64
|
||||
KEY_F9,67,F9,0x65,0x43,0x01,0x47,66,VK_F9,0x78,67,67,XK_F9,0xffc6,F9,FK09,f9,0x12,0x65
|
||||
KEY_F10,68,F10,0x6d,0x44,0x09,0x4f,67,VK_F10,0x79,68,68,XK_F10,0xffc7,F10,FK10,f10,0x07,0x6d
|
||||
KEY_NUMLOCK,69,ANSI_KeypadClear,0x47,0x45,0x77,0x76,83,VK_NUMLOCK,0x90,69,69,XK_Num_Lock,0xff7f,NumLock,NMLK,num_lock,0x62,0x47
|
||||
KEY_SCROLLLOCK,70,,,0x46,0x7e,0x5f,71,VK_SCROLL,0x91,70,70,XK_Scroll_Lock,0xff14,ScrollLock,SCLK,scroll_lock,0x17,0x6b
|
||||
KEY_KP7,71,ANSI_Keypad7,0x59,0x47,0x6c,0x6c,95,VK_NUMPAD7,0x67,71,71,XK_KP_7,0xffb7,Numpad7,KP7,kp_7,0x44,0x59
|
||||
KEY_KP8,72,ANSI_Keypad8,0x5b,0x48,0x75,0x75,96,VK_NUMPAD8,0x68,72,72,XK_KP_8,0xffb8,Numpad8,KP8,kp_8,0x45,0x5b
|
||||
KEY_KP9,73,ANSI_Keypad9,0x5c,0x49,0x7d,0x7d,97,VK_NUMPAD9,0x69,73,73,XK_KP_9,0xffb9,Numpad9,KP9,kp_9,0x46,0x5c
|
||||
KEY_KPMINUS,74,ANSI_KeypadMinus,0x4e,0x4a,0x7b,0x4e,86,VK_SUBTRACT,0x6d,74,74,XK_KP_Subtract,0xffad,NumpadSubtract,KPSU,kp_subtract,0x47,0x4e
|
||||
KEY_KP4,75,ANSI_Keypad4,0x56,0x4b,0x6b,0x6b,92,VK_NUMPAD4,0x64,75,75,XK_KP_4,0xffb4,Numpad4,KP4,kp_4,0x5b,0x56
|
||||
KEY_KP5,76,ANSI_Keypad5,0x57,0x4c,0x73,0x73,93,VK_NUMPAD5,0x65,76,76,XK_KP_5,0xffb5,Numpad5,KP5,kp_5,0x5c,0x57
|
||||
KEY_KP6,77,ANSI_Keypad6,0x58,0x4d,0x74,0x74,94,VK_NUMPAD6,0x66,77,77,XK_KP_6,0xffb6,Numpad6,KP6,kp_6,0x5d,0x58
|
||||
KEY_KPPLUS,78,ANSI_KeypadPlus,0x45,0x4e,0x79,0x7c,87,VK_ADD,0x6b,78,78,XK_KP_Add,0xffab,NumpadAdd,KPAD,kp_add,0x7d,0x45
|
||||
KEY_KP1,79,ANSI_Keypad1,0x53,0x4f,0x69,0x69,89,VK_NUMPAD1,0x61,79,79,XK_KP_1,0xffb1,Numpad1,KP1,kp_1,0x70,0x53
|
||||
KEY_KP2,80,ANSI_Keypad2,0x54,0x50,0x72,0x72,90,VK_NUMPAD2,0x62,80,80,XK_KP_2,0xffb2,Numpad2,KP2,kp_2,0x71,0x54
|
||||
KEY_KP3,81,ANSI_Keypad3,0x55,0x51,0x7a,0x7a,91,VK_NUMPAD3,0x63,81,81,XK_KP_3,0xffb3,Numpad3,KP3,kp_3,0x72,0x55
|
||||
KEY_KP0,82,ANSI_Keypad0,0x52,0x52,0x70,0x70,98,VK_NUMPAD0,0x60,82,82,XK_KP_0,0xffb0,Numpad0,KP0,kp_0,0x5e,0x52
|
||||
KEY_KPDOT,83,ANSI_KeypadDecimal,0x41,0x53,0x71,0x71,99,VK_DECIMAL,0x6e,83,83,XK_KP_Decimal,0xffae,NumpadDecimal,KPDL,kp_decimal,0x32,0x41
|
||||
KEY_KPDOT,83,ANSI_KeypadDecimal,0x41,0x53,0x71,0x71,99,VK_DECIMAL,0x6e,83,83,XK_KP_Decimal,0xffae,NumpadDecimal,KPDC,kp_decimal,0x32,0x41
|
||||
,84,,,0x54,,,,,,,,,,,,,,
|
||||
KEY_ZENKAKUHANKAKU,85,,,0x76,0x5f,,148,,,,,,,Lang5,HZTG,,,
|
||||
KEY_102ND,86,,,0x56,0x61,0x13,100,VK_OEM_102,0xe1,86,86,,,IntlBackslash,LSGT,less,0x7c,
|
||||
KEY_F11,87,F11,0x67,0x57,0x78,0x56,68,VK_F11,0x7a,87,87,XK_F11,0xffc8,F11,FK11,f11,0x09,0x67
|
||||
KEY_F12,88,F12,0x6f,0x58,0x07,0x5e,69,VK_F12,0x7b,88,88,XK_F12,0xffc9,F12,FK12,f12,0x0b,0x6f
|
||||
KEY_RO,89,,,0x73,0x51,,135,,,,,,,IntlRo,AB11,ro,,
|
||||
KEY_KATAKANA,90,JIS_Kana,0x68,0x78,0x63,,146,VK_KANA,0x15,,,,,Katakana,KATA,,,
|
||||
KEY_KATAKANA,90,JIS_Kana,0x68,0x78,0x63,,146,VK_KANA,0x15,,,,,Lang3,KATA,,,
|
||||
KEY_HIRAGANA,91,,,0x77,0x62,0x87,147,,,,,,,Hiragana,HIRA,hiragana,,
|
||||
KEY_HIRAGANA,91,,,0x77,0x62,0x87,147,,,,,,,Lang4,HIRA,hiragana,,
|
||||
KEY_HENKAN,92,,,0x79,0x64,0x86,138,,,,,,,Convert,HENK,henkan,,
|
||||
KEY_KATAKANAHIRAGANA,93,,,0x70,0x13,0x87,136,,,0xc8,0xc8,,,KanaMode,HKTG,,,
|
||||
KEY_MUHENKAN,94,,,0x7b,0x67,0x85,139,,,,,,,NonConvert,NFER,,,
|
||||
KEY_MUHENKAN,94,,,0x7b,0x67,0x85,139,,,,,,,NonConvert,MUHE,,,
|
||||
KEY_KPJPCOMMA,95,JIS_KeypadComma,0x5f,0x5c,0x27,,140,,,,,XK_KP_Separator,0xffac,,KPSP,,,
|
||||
KEY_KPJPCOMMA,95,JIS_KeypadComma,0x5f,0x5c,0x27,,140,,,,,XK_KP_Separator,0xffac,,JPCM,,,
|
||||
KEY_KPENTER,96,ANSI_KeypadEnter,0x4c,0xe01c,0xe05a,0x79,88,,,0x64,0x64,XK_KP_Enter,0xff8d,NumpadEnter,KPEN,kp_enter,0x5a,0x4c
|
||||
KEY_RIGHTCTRL,97,RightControl,0x3e,0xe01d,0xe014,0x58,228,VK_RCONTROL,0xa3,0x65,0x65,XK_Control_R,0xffe4,ControlRight,RCTL,ctrl_r,0x4c,0x7d
|
||||
KEY_KPSLASH,98,ANSI_KeypadDivide,0x4b,0xe035,0xe04a,0x4a,84,VK_DIVIDE,0x6f,0x68,0x68,XK_KP_Divide,0xffaf,NumpadDivide,KPDV,kp_divide,0x2e,0x4b
|
||||
KEY_SYSRQ,99,,,0x54,0x7f,0x57,70,VK_SNAPSHOT,0x2c,0x67,0x67,XK_Sys_Req,0xff15,PrintScreen,PRSC,print,0x16,0x69
|
||||
KEY_SYSRQ,99,,,0x54,0x7f,0x57,70,VK_SNAPSHOT,0x2c,0x67,0x67,XK_Sys_Req,0xff15,PrintScreen,SYRQ,sysrq,0x16,0x69
|
||||
KEY_RIGHTALT,100,RightOption,0x3d,0xe038,0xe011,0x39,230,VK_RMENU,0xa5,0x69,0x69,XK_Alt_R,0xffea,AltRight,ALGR,alt_r,0x0d,0x7c
|
||||
KEY_RIGHTALT,100,RightOption,0x3d,0xe038,0xe011,0x39,230,VK_RMENU,0xa5,0x69,0x69,XK_Alt_R,0xffea,AltRight,RALT,alt_r,0x0d,0x7c
|
||||
KEY_LINEFEED,101,,,0x5b,,,,,,,,,,,LNFD,lf,0x6f,
|
||||
KEY_HOME,102,Home,0x73,0xe047,0xe06c,0x6e,74,VK_HOME,0x24,0x59,0x59,XK_Home,0xff50,Home,HOME,home,0x34,0x73
|
||||
KEY_UP,103,UpArrow,0x7e,0xe048,0xe075,0x63,82,VK_UP,0x26,0x5a,0x5a,XK_Up,0xff52,ArrowUp,UP,up,0x14,0x3e
|
||||
KEY_PAGEUP,104,PageUp,0x74,0xe049,0xe07d,0x6f,75,VK_PRIOR,0x21,0x5b,0x5b,XK_Page_Up,0xff55,PageUp,PGUP,pgup,0x60,0x74
|
||||
KEY_LEFT,105,LeftArrow,0x7b,0xe04b,0xe06b,0x61,80,VK_LEFT,0x25,0x5c,0x5c,XK_Left,0xff51,ArrowLeft,LEFT,left,0x18,0x3b
|
||||
KEY_RIGHT,106,RightArrow,0x7c,0xe04d,0xe074,0x6a,79,VK_RIGHT,0x27,0x5e,0x5e,XK_Right,0xff53,ArrowRight,RGHT,right,0x1c,0x3c
|
||||
KEY_END,107,End,0x77,0xe04f,0xe069,0x65,77,VK_END,0x23,0x5f,0x5f,XK_End,0xff57,End,END,end,0x4a,0x77
|
||||
KEY_DOWN,108,DownArrow,0x7d,0xe050,0xe072,0x60,81,VK_DOWN,0x28,0x60,0x60,XK_Down,0xff54,ArrowDown,DOWN,down,0x1b,0x3d
|
||||
KEY_PAGEDOWN,109,PageDown,0x79,0xe051,0xe07a,0x6d,78,VK_NEXT,0x22,0x61,0x61,XK_Page_Down,0xff56,PageDown,PGDN,pgdn,0x7b,0x79
|
||||
KEY_INSERT,110,,,0xe052,0xe070,0x67,73,VK_INSERT,0x2d,0x62,0x62,XK_Insert,0xff63,Insert,INS,insert,0x2c,0x72
|
||||
KEY_DELETE,111,ForwardDelete,0x75,0xe053,0xe071,0x64,76,VK_DELETE,0x2e,0x63,0x63,XK_Delete,0xffff,Delete,DEL,delete,0x42,0x75
|
||||
KEY_DELETE,111,ForwardDelete,0x75,0xe053,0xe071,0x64,76,VK_DELETE,0x2e,0x63,0x63,XK_Delete,0xffff,Delete,DELE,,0x42,0x75
|
||||
KEY_MACRO,112,,,0xe06f,0xe06f,0x8e,,,,,,,,,I120,,,
|
||||
KEY_MUTE,113,Mute,0x4a,0xe020,0xe023,0x9c,127,VK_VOLUME_MUTE,0xad,,,,,AudioVolumeMute,MUTE,audiomute,,
|
||||
KEY_MUTE,113,Mute,0x4a,0xe020,0xe023,0x9c,239,VK_VOLUME_MUTE,0xad,,,,,AudioVolumeMute,MUTE,audiomute,,
|
||||
KEY_VOLUMEDOWN,114,VolumeDown,0x49,0xe02e,0xe021,0x9d,129,VK_VOLUME_DOWN,0xae,,,,,AudioVolumeDown,VOL-,volumedown,,
|
||||
KEY_VOLUMEDOWN,114,VolumeDown,0x49,0xe02e,0xe021,0x9d,238,VK_VOLUME_DOWN,0xae,,,,,AudioVolumeDown,VOL-,volumedown,,
|
||||
KEY_VOLUMEUP,115,VolumeUp,0x48,0xe030,0xe032,0x95,128,VK_VOLUME_UP,0xaf,,,,,AudioVolumeUp,VOL+,volumeup,,
|
||||
KEY_VOLUMEUP,115,VolumeUp,0x48,0xe030,0xe032,0x95,237,VK_VOLUME_UP,0xaf,,,,,AudioVolumeUp,VOL+,volumeup,,
|
||||
KEY_POWER,116,,,0xe05e,0xe037,,102,,,,,,,Power,POWR,power,,0x7f7f
|
||||
KEY_KPEQUAL,117,ANSI_KeypadEquals,0x51,0x59,0x0f,,103,,,0x76,0x76,XK_KP_Equal,0xffbd,NumpadEqual,KPEQ,kp_equals,0x2d,0x51
|
||||
KEY_KPPLUSMINUS,118,,,0xe04e,0xe079,,,,,,,,,,I126,,,
|
||||
KEY_PAUSE,119,,,0xe046,0xe077,0x62,72,VK_PAUSE,0x013,0x66,0x66,XK_Pause,0xff13,Pause,PAUS,pause,0x15,0x71
|
||||
KEY_SCALE,120,,,0xe00b,,,,,,,,,,,I128,,,
|
||||
KEY_KPCOMMA,121,,,0x7e,0x6d,,133,VK_SEPARATOR??,0x6c,,,,,NumpadComma,KPCO,kp_comma,,
|
||||
KEY_KPCOMMA,121,,,0x7e,0x6d,,133,VK_SEPARATOR??,0x6c,,,,,NumpadComma,I129,,,
|
||||
KEY_HANGEUL,122,,,,,,144,VK_HANGEUL,0x15,,,,,,HNGL,,,
|
||||
KEY_HANJA,123,,,0xe00d,,,145,VK_HANJA,0x19,,,,,,HJCV,,,
|
||||
KEY_YEN,124,JIS_Yen,0x5d,0x7d,0x6a,0x5d,137,,,0x7d,0x7d,,,IntlYen,AE13,yen,,
|
||||
KEY_LEFTMETA,125,Command,0x37,0xe05b,0xe01f,0x8b,227,VK_LWIN,0x5b,0x6b,0x6b,XK_Meta_L,0xffe7,MetaLeft,LMTA,meta_l,0x78,0x37
|
||||
KEY_LEFTMETA,125,Command,0x37,0xe05b,0xe01f,0x8b,227,VK_LWIN,0x5b,0x6b,0x6b,XK_Meta_L,0xffe7,MetaLeft,LWIN,meta_l,0x78,0x37
|
||||
KEY_RIGHTMETA,126,RightCommand,0x36,0xe05c,0xe027,0x8c,231,VK_RWIN,0x5c,0x6c,0x6c,XK_Meta_R,0xffe8,MetaRight,RMTA,meta_r,0x7a,0x37
|
||||
KEY_RIGHTMETA,126,RightCommand,0x36,0xe05c,0xe027,0x8c,231,VK_RWIN,0x5c,0x6c,0x6c,XK_Meta_R,0xffe8,MetaRight,RWIN,meta_r,0x7a,0x37
|
||||
KEY_COMPOSE,127,,0x6e,0xe05d,0xe02f,0x8d,101,VK_APPS,0x5d,0x6d,0x6d,,,ContextMenu,MENU,compose,0x43,
|
||||
KEY_COMPOSE,127,,0x6e,0xe05d,0xe02f,0x8d,101,VK_APPS,0x5d,0x6d,0x6d,,,ContextMenu,COMP,compose,0x43,
|
||||
KEY_STOP,128,,,0xe068,0xe028,0x0a,120,VK_BROWSER_STOP,0xa9,,,,,BrowserStop,STOP,stop,0x01,
|
||||
KEY_STOP,128,,,0xe068,0xe028,0x0a,243,VK_BROWSER_STOP,0xa9,,,,,BrowserStop,STOP,stop,0x01,
|
||||
KEY_AGAIN,129,,,0xe005,,0x0b,121,,,,,,,Again,AGAI,again,0x03,
|
||||
KEY_PROPS,130,,,0xe006,,0x0c,,,,,,,,Props,PROP,props,0x19,
|
||||
KEY_UNDO,131,,,0xe007,,0x10,122,,,,,,,Undo,UNDO,undo,0x1a,
|
||||
KEY_FRONT,132,,,0xe00c,,,119,,,,,,,,FRNT,front,0x31,
|
||||
KEY_COPY,133,,,0xe078,,0x18,124,,,,,,,Copy,COPY,copy,0x33,
|
||||
KEY_OPEN,134,,,0x64,,0x20,116,,,,,,,Open,OPEN,open,0x48,
|
||||
KEY_PASTE,135,,,0x65,,0x28,125,,,,,,,Paste,PAST,paste,0x49,
|
||||
KEY_FIND,136,,,0xe041,,0x30,126,,,,,,,Find,FIND,find,0x5f,
|
||||
KEY_FIND,136,,,0xe041,,0x30,244,,,,,,,Find,FIND,find,0x5f,
|
||||
KEY_CUT,137,,,0xe03c,,0x38,123,,,,,,,Cut,CUT,cut,0x61,
|
||||
KEY_HELP,138,Help,0x72,0xe075,,0x09,117,VK_HELP,0x2f,,,XK_Help,0xff6a,Help,HELP,help,0x76,
|
||||
KEY_MENU,139,,,0xe01e,,0x91,118,,,,,,,,I147,menu,,
|
||||
KEY_CALC,140,,,0xe021,0xe02b,0xa3,251,,,,,,,LaunchApp2,I148,calculator,,
|
||||
KEY_SETUP,141,,,0x66,,,,,,,,,,,I149,,,
|
||||
KEY_SLEEP,142,,,0xe05f,0xe03f,,248,VK_SLEEP,0x5f,,,,,Sleep,I150,sleep,,
|
||||
KEY_WAKEUP,143,,,0xe063,0xe05e,,,,,,,,,WakeUp,I151,wake,,
|
||||
KEY_FILE,144,,,0x67,,,,,,,,,,,I152,,,
|
||||
KEY_SENDFILE,145,,,0x68,,,,,,,,,,,I153,,,
|
||||
KEY_DELETEFILE,146,,,0x69,,,,,,,,,,,I154,,,
|
||||
KEY_XFER,147,,,0xe013,,0xa2,,,,,,,,,XFER,,,
|
||||
KEY_XFER,147,,,0xe013,,0xa2,,,,,,,,,I155,,,
|
||||
KEY_PROG1,148,,,0xe01f,,0xa0,,,,,,,,,I156,,,
|
||||
KEY_PROG2,149,,,0xe017,,0xa1,,,,,,,,,I157,,,
|
||||
KEY_WWW,150,,,0xe002,,,240,,,,,,,,I158,,,
|
||||
KEY_MSDOS,151,,,0x6a,,,,,,,,,,,I159,,,
|
||||
KEY_SCREENLOCK,152,,,0xe012,,0x96,249,,,,,,,,I160,,,
|
||||
KEY_DIRECTION,153,,,0x6b,,,,,,,,,,,I161,,,
|
||||
KEY_CYCLEWINDOWS,154,,,0xe026,,0x9b,,,,,,,,,I162,,,
|
||||
KEY_MAIL,155,,,0xe06c,0xe048,,,,,,,,,LaunchMail,I163,mail,,
|
||||
KEY_BOOKMARKS,156,,,0xe066,0xe018,,,,,,,,,BrowserFavorites,I164,ac_bookmarks,,
|
||||
KEY_COMPUTER,157,,,0xe06b,0xe040,,,,,,,,,LaunchApp1,I165,computer,,
|
||||
KEY_BACK,158,,,0xe06a,0xe038,,241,VK_BROWSER_BACK,0xa6,,,,,BrowserBack,I166,ac_back,,
|
||||
KEY_FORWARD,159,,,0xe069,0xe030,,242,VK_BROWSER_FORWARD,0xa7,,,,,BrowserForward,I167,ac_forward,,
|
||||
KEY_CLOSECD,160,,,0xe023,,0x9a,,,,,,,,,I168,,,
|
||||
KEY_EJECTCD,161,,,0x6c,,,236,,,,,,,,I169,,,
|
||||
KEY_EJECTCLOSECD,162,,,0xe07d,,,,,,,,,,Eject,I170,,,
|
||||
KEY_NEXTSONG,163,,,0xe019,0xe04d,0x93,235,VK_MEDIA_NEXT_TRACK,0xb0,,,,,MediaTrackNext,I171,audionext,,
|
||||
KEY_PLAYPAUSE,164,,,0xe022,0xe034,,232,VK_MEDIA_PLAY_PAUSE,0xb3,,,,,MediaPlayPause,I172,audioplay,,
|
||||
KEY_PREVIOUSSONG,165,,,0xe010,0xe015,0x94,234,VK_MEDIA_PREV_TRACK,0xb1,,,,,MediaTrackPrevious,I173,audioprev,,
|
||||
KEY_STOPCD,166,,,0xe024,0xe03b,0x98,233,VK_MEDIA_STOP,0xb2,,,,,MediaStop,I174,audiostop,,
|
||||
KEY_RECORD,167,,,0xe031,,0x9e,,,,,,,,,I175,,,
|
||||
KEY_REWIND,168,,,0xe018,,0x9f,,,,,,,,,I176,,,
|
||||
KEY_PHONE,169,,,0x63,,,,,,,,,,,I177,,,
|
||||
KEY_ISO,170,ISO_Section,0xa,0x70,,,,,,,,,,,I178,,,
|
||||
KEY_CONFIG,171,,,0xe001,,,,,,,,,,,I179,,,
|
||||
KEY_HOMEPAGE,172,,,0xe032,0xe03a,0x97,,VK_BROWSER_HOME,0xac,,,,,BrowserHome,I180,ac_home,,
|
||||
KEY_REFRESH,173,,,0xe067,0xe020,,250,VK_BROWSER_REFRESH,0xa8,,,,,BrowserRefresh,I181,ac_refresh,,
|
||||
KEY_EXIT,174,,,0x71,,,,,,,,,,,I182,,,
|
||||
KEY_MOVE,175,,,0x72,,,,,,,,,,,I183,,,
|
||||
KEY_EDIT,176,,,0xe008,,,247,,,,,,,,I184,,,
|
||||
KEY_SCROLLUP,177,,,0x75,,,245,,,,,,,,I185,,,
|
||||
KEY_SCROLLDOWN,178,,,0xe00f,,,246,,,,,,,,I186,,,
|
||||
KEY_KPLEFTPAREN,179,,,0xe076,,,182,,,,,,,NumpadParenLeft,I187,,,
|
||||
KEY_KPRIGHTPAREN,180,,,0xe07b,,,183,,,,,,,NumpadParenRight,I188,,,
|
||||
KEY_NEW,181,,,0xe009,,,,,,,,,,,I189,,,
|
||||
KEY_REDO,182,,,0xe00a,,,,,,,,,,,I190,,,
|
||||
KEY_F13,183,F13,0x69,0x5d,0x2f,0x7f,104,VK_F13,0x7c,0x6e,0x6e,,,F13,FK13,,,0x69
|
||||
KEY_F14,184,F14,0x6b,0x5e,0x37,0x80,105,VK_F14,0x7d,0x6f,0x6f,,,F14,FK14,,,0x6b
|
||||
KEY_F15,185,F15,0x71,0x5f,0x3f,0x81,106,VK_F15,0x7e,0x70,0x70,,,F15,FK15,,,0x71
|
||||
KEY_F16,186,F16,0x6a,0x55,,0x82,107,VK_F16,0x7f,0x71,0x71,,,F16,FK16,,,
|
||||
KEY_F17,187,F17,0x40,0xe003,,0x83,108,VK_F17,0x80,0x72,0x72,,,F17,FK17,,,
|
||||
KEY_F18,188,F18,0x4f,0xe077,,,109,VK_F18,0x81,,,,,F18,FK18,,,
|
||||
KEY_F19,189,F19,0x50,0xe004,,,110,VK_F19,0x82,,,,,F19,FK19,,,
|
||||
KEY_F20,190,F20,0x5a,0x5a,,,111,VK_F20,0x83,,,,,F20,FK20,,,
|
||||
KEY_F21,191,,,0x74,,,112,VK_F21,0x84,,,,,F21,FK21,,,
|
||||
KEY_F22,192,,,0xe079,,,113,VK_F22,0x85,,,,,F22,FK22,,,
|
||||
KEY_F23,193,,,0x6d,,,114,VK_F23,0x86,,,,,F23,FK23,,,
|
||||
KEY_F24,194,,,0x6f,,,115,VK_F24,0x87,,,,,F24,FK24,,,
|
||||
,195,,,0xe015,,,,,,,,,,,,,,
|
||||
,196,,,0xe016,,,,,,,,,,,,,,
|
||||
,197,,,0xe01a,,,,,,,,,,,,,,
|
||||
,198,,,0xe01b,,,,,,,,,,,,,,
|
||||
,199,,,0xe027,,,,,,,,,,,,,,
|
||||
KEY_PLAYCD,200,,,0xe028,,,,,,,,,,,I208,,,
|
||||
KEY_PAUSECD,201,,,0xe029,,,,,,,,,,,I209,,,
|
||||
KEY_PROG3,202,,,0xe02b,,,,,,,,,,,I210,,,
|
||||
KEY_PROG4,203,,,0xe02c,,,,,,,,,,,I211,,,
|
||||
KEY_DASHBOARD,204,,,0xe02d,,,,,,,,,,,I212,,,
|
||||
KEY_SUSPEND,205,,,0xe025,,,,,,,,,,Suspend,I213,,,
|
||||
KEY_CLOSE,206,,,0xe02f,,,,,,,,,,,I214,,,
|
||||
KEY_PLAY,207,,,0xe033,,,,VK_PLAY,0xfa,,,,,,I215,,,
|
||||
KEY_FASTFORWARD,208,,,0xe034,,,,,,,,,,,I216,,,
|
||||
KEY_BASSBOOST,209,,,0xe036,,,,,,,,,,,I217,,,
|
||||
KEY_PRINT,210,,,0xe039,,,,VK_PRINT,0x2a,,,,,,I218,,,
|
||||
KEY_HP,211,,,0xe03a,,,,,,,,,,,I219,,,
|
||||
KEY_CAMERA,212,,,0xe03b,,,,,,,,,,,I220,,,
|
||||
KEY_SOUND,213,,,0xe03d,,,,,,,,,,,I221,,,
|
||||
KEY_QUESTION,214,,,0xe03e,,,,,,,,,,,I222,,,
|
||||
KEY_EMAIL,215,,,0xe03f,,,,VK_LAUNCH_MAIL,0xb4,,,,,,I223,,,
|
||||
KEY_CHAT,216,,,0xe040,,,,,,,,,,,I224,,,
|
||||
KEY_SEARCH,217,,,0xe065,0xe010,,,VK_BROWSER_SEARCH,0xaa,,,,,BrowserSearch,I225,,,
|
||||
KEY_CONNECT,218,,,0xe042,,,,,,,,,,,I226,,,
|
||||
KEY_FINANCE,219,,,0xe043,,,,,,,,,,,I227,,,
|
||||
KEY_SPORT,220,,,0xe044,,,,,,,,,,,I228,,,
|
||||
KEY_SHOP,221,,,0xe045,,,,,,,,,,,I229,,,
|
||||
KEY_ALTERASE,222,,,0xe014,,,,,,,,,,,I230,,,
|
||||
KEY_CANCEL,223,,,0xe04a,,,,,,,,,,,I231,,,
|
||||
KEY_BRIGHTNESSDOWN,224,,,0xe04c,,,,,,,,,,,I232,,,
|
||||
KEY_BRIGHTNESSUP,225,,,0xe054,,,,,,,,,,,I233,,,
|
||||
KEY_MEDIA,226,,,0xe06d,0xe050,,,,,,,,,MediaSelect,I234,mediaselect,,
|
||||
KEY_SWITCHVIDEOMODE,227,,,0xe056,,,,,,,,,,,I235,,,
|
||||
KEY_KBDILLUMTOGGLE,228,,,0xe057,,,,,,,,,,,I236,,,
|
||||
KEY_KBDILLUMDOWN,229,,,0xe058,,,,,,,,,,,I237,,,
|
||||
KEY_KBDILLUMUP,230,,,0xe059,,,,,,,,,,,I238,,,
|
||||
KEY_SEND,231,,,0xe05a,,,,,,,,,,,I239,,,
|
||||
KEY_REPLY,232,,,0xe064,,,,,,,,,,,I240,,,
|
||||
KEY_FORWARDMAIL,233,,,0xe00e,,,,,,,,,,,I241,,,
|
||||
KEY_SAVE,234,,,0xe055,,,,,,,,,,,I242,,,
|
||||
KEY_DOCUMENTS,235,,,0xe070,,,,,,,,,,,I243,,,
|
||||
KEY_BATTERY,236,,,0xe071,,,,,,,,,,,I244,,,
|
||||
KEY_BLUETOOTH,237,,,0xe072,,,,,,,,,,,I245,,,
|
||||
KEY_WLAN,238,,,0xe073,,,,,,,,,,,I246,,,
|
||||
KEY_UWB,239,,,0xe074,,,,,,,,,,,I247,,,
|
||||
KEY_UNKNOWN,240,,,,,,,,,,,,,,I248,,,
|
||||
KEY_VIDEO_NEXT,241,,,,,,,,,,,,,,I249,,,
|
||||
KEY_VIDEO_PREV,242,,,,,,,,,,,,,,I250,,,
|
||||
KEY_BRIGHTNESS_CYCLE,243,,,,,,,,,,,,,,I251,,,
|
||||
KEY_BRIGHTNESS_ZERO,244,,,,,,,,,,,,,,I252,,,
|
||||
KEY_DISPLAY_OFF,245,,,,,,,,,,,,,,I253,,,
|
||||
KEY_WIMAX,246,,,,,,,,,,,,,,,,,
|
||||
,247,,,,,,,,,,,,,,,,,
|
||||
,248,,,,,,,,,,,,,,,,,
|
||||
,249,,,,,,,,,,,,,,,,,
|
||||
,250,,,,,,,,,,,,,,,,,
|
||||
,251,,,,,,,,,,,,,,,,,
|
||||
,252,,,,,,,,,,,,,,,,,
|
||||
,253,,,,,,,,,,,,,,,,,
|
||||
,254,,,,,,,,,,,,,,,,,
|
||||
,255,,,,0xe012,,,,,,,,,,,,,
|
||||
BTN_MISC,0x100,,,,,,,,,,,,,,,,,
|
||||
BTN_0,0x100,,,,,,,VK_LBUTTON,0x01,,,,,,,,,
|
||||
BTN_1,0x101,,,,,,,VK_RBUTTON,0x02,,,,,,,,,
|
||||
BTN_2,0x102,,,,,,,VK_MBUTTON,0x04,,,,,,,,,
|
||||
BTN_3,0x103,,,,,,,VK_XBUTTON1,0x05,,,,,,,,,
|
||||
BTN_4,0x104,,,,,,,VK_XBUTTON2,0x06,,,,,,,,,
|
||||
BTN_5,0x105,,,,,,,,,,,,,,,,,
|
||||
BTN_6,0x106,,,,,,,,,,,,,,,,,
|
||||
BTN_7,0x107,,,,,,,,,,,,,,,,,
|
||||
BTN_8,0x108,,,,,,,,,,,,,,,,,
|
||||
BTN_9,0x109,,,,,,,,,,,,,,,,,
|
||||
BTN_MOUSE,0x110,,,,,,,,,,,,,,,,,
|
||||
BTN_LEFT,0x110,,,,,,,,,,,,,,,,,
|
||||
BTN_RIGHT,0x111,,,,,,,,,,,,,,,,,
|
||||
BTN_MIDDLE,0x112,,,,,,,,,,,,,,,,,
|
||||
BTN_SIDE,0x113,,,,,,,,,,,,,,,,,
|
||||
BTN_EXTRA,0x114,,,,,,,,,,,,,,,,,
|
||||
BTN_FORWARD,0x115,,,,,,,,,,,,,,,,,
|
||||
BTN_BACK,0x116,,,,,,,,,,,,,,,,,
|
||||
BTN_TASK,0x117,,,,,,,,,,,,,,,,,
|
||||
BTN_JOYSTICK,0x120,,,,,,,,,,,,,,,,,
|
||||
BTN_TRIGGER,0x120,,,,,,,,,,,,,,,,,
|
||||
BTN_THUMB,0x121,,,,,,,,,,,,,,,,,
|
||||
BTN_THUMB2,0x122,,,,,,,,,,,,,,,,,
|
||||
BTN_TOP,0x123,,,,,,,,,,,,,,,,,
|
||||
BTN_TOP2,0x124,,,,,,,,,,,,,,,,,
|
||||
BTN_PINKIE,0x125,,,,,,,,,,,,,,,,,
|
||||
BTN_BASE,0x126,,,,,,,,,,,,,,,,,
|
||||
BTN_BASE2,0x127,,,,,,,,,,,,,,,,,
|
||||
BTN_BASE3,0x128,,,,,,,,,,,,,,,,,
|
||||
BTN_BASE4,0x129,,,,,,,,,,,,,,,,,
|
||||
BTN_BASE5,0x12a,,,,,,,,,,,,,,,,,
|
||||
BTN_BASE6,0x12b,,,,,,,,,,,,,,,,,
|
||||
BTN_DEAD,0x12f,,,,,,,,,,,,,,,,,
|
||||
BTN_GAMEPAD,0x130,,,,,,,,,,,,,,,,,
|
||||
BTN_A,0x130,,,,,,,,,,,,,,,,,
|
||||
BTN_B,0x131,,,,,,,,,,,,,,,,,
|
||||
BTN_C,0x132,,,,,,,,,,,,,,,,,
|
||||
BTN_X,0x133,,,,,,,,,,,,,,,,,
|
||||
BTN_Y,0x134,,,,,,,,,,,,,,,,,
|
||||
BTN_Z,0x135,,,,,,,,,,,,,,,,,
|
||||
BTN_TL,0x136,,,,,,,,,,,,,,,,,
|
||||
BTN_TR,0x137,,,,,,,,,,,,,,,,,
|
||||
BTN_TL2,0x138,,,,,,,,,,,,,,,,,
|
||||
BTN_TR2,0x139,,,,,,,,,,,,,,,,,
|
||||
BTN_SELECT,0x13a,,,,,,,,,,,,,,,,,
|
||||
BTN_START,0x13b,,,,,,,,,,,,,,,,,
|
||||
BTN_MODE,0x13c,,,,,,,,,,,,,,,,,
|
||||
BTN_THUMBL,0x13d,,,,,,,,,,,,,,,,,
|
||||
BTN_THUMBR,0x13e,,,,,,,,,,,,,,,,,
|
||||
BTN_DIGI,0x140,,,,,,,,,,,,,,,,,
|
||||
BTN_TOOL_PEN,0x140,,,,,,,,,,,,,,,,,
|
||||
BTN_TOOL_RUBBER,0x141,,,,,,,,,,,,,,,,,
|
||||
BTN_TOOL_BRUSH,0x142,,,,,,,,,,,,,,,,,
|
||||
BTN_TOOL_PENCIL,0x143,,,,,,,,,,,,,,,,,
|
||||
BTN_TOOL_AIRBRUSH,0x144,,,,,,,,,,,,,,,,,
|
||||
BTN_TOOL_FINGER,0x145,,,,,,,,,,,,,,,,,
|
||||
BTN_TOOL_MOUSE,0x146,,,,,,,,,,,,,,,,,
|
||||
BTN_TOOL_LENS,0x147,,,,,,,,,,,,,,,,,
|
||||
BTN_TOUCH,0x14a,,,,,,,,,,,,,,,,,
|
||||
BTN_STYLUS,0x14b,,,,,,,,,,,,,,,,,
|
||||
BTN_STYLUS2,0x14c,,,,,,,,,,,,,,,,,
|
||||
BTN_TOOL_DOUBLETAP,0x14d,,,,,,,,,,,,,,,,,
|
||||
BTN_TOOL_TRIPLETAP,0x14e,,,,,,,,,,,,,,,,,
|
||||
BTN_TOOL_QUADTAP,0x14f,,,,,,,,,,,,,,,,,
|
||||
BTN_WHEEL,0x150,,,,,,,,,,,,,,,,,
|
||||
BTN_GEAR_DOWN,0x150,,,,,,,,,,,,,,,,,
|
||||
BTN_GEAR_UP,0x151,,,,,,,,,,,,,,,,,
|
||||
KEY_OK,0x160,,,,,,,,,,,,,,,,,
|
||||
KEY_SELECT,0x161,,,,,,,VK_SELECT,0x29,,,XK_Select,0xff60,Select,SELE,,,
|
||||
KEY_GOTO,0x162,,,,,,,,,,,,,,,,,
|
||||
KEY_CLEAR,0x163,,,,,,,,,,,,,NumpadClear,CLR,,,
|
||||
KEY_POWER2,0x164,,,,,,,,,,,,,,,,,
|
||||
KEY_OPTION,0x165,,,,,,,,,,,,,,,,,
|
||||
KEY_INFO,0x166,,,,,,,,,,,,,,,,,
|
||||
KEY_TIME,0x167,,,,,,,,,,,,,,,,,
|
||||
KEY_VENDOR,0x168,,,,,,,,,,,,,,,,,
|
||||
KEY_ARCHIVE,0x169,,,,,,,,,,,,,,,,,
|
||||
KEY_PROGRAM,0x16a,,,,,,,,,,,,,,,,,
|
||||
KEY_CHANNEL,0x16b,,,,,,,,,,,,,,,,,
|
||||
KEY_FAVORITES,0x16c,,,,,,,VK_BROWSER_FAVOURITES,0xab,,,,,,,,,
|
||||
KEY_EPG,0x16d,,,,,,,,,,,,,,,,,
|
||||
KEY_PVR,0x16e,,,,,,,,,,,,,,,,,
|
||||
KEY_MHP,0x16f,,,,,,,,,,,,,,,,,
|
||||
KEY_LANGUAGE,0x170,,,,,,,,,,,,,,,,,
|
||||
KEY_TITLE,0x171,,,,,,,,,,,,,,,,,
|
||||
KEY_SUBTITLE,0x172,,,,,,,,,,,,,,,,,
|
||||
KEY_ANGLE,0x173,,,,,,,,,,,,,,,,,
|
||||
KEY_ZOOM,0x174,,,,,,,VK_ZOOM,0xfb,,,,,,,,,
|
||||
KEY_MODE,0x175,,,,,,,,,,,,,,,,,
|
||||
KEY_KEYBOARD,0x176,,,,,,,,,,,,,,,,,
|
||||
KEY_SCREEN,0x177,,,,,,,,,,,,,,,,,
|
||||
KEY_PC,0x178,,,,,,,,,,,,,,,,,
|
||||
KEY_TV,0x179,,,,,,,,,,,,,,,,,
|
||||
KEY_TV2,0x17a,,,,,,,,,,,,,,,,,
|
||||
KEY_VCR,0x17b,,,,,,,,,,,,,,,,,
|
||||
KEY_VCR2,0x17c,,,,,,,,,,,,,,,,,
|
||||
KEY_SAT,0x17d,,,,,,,,,,,,,,,,,
|
||||
KEY_SAT2,0x17e,,,,,,,,,,,,,,,,,
|
||||
KEY_CD,0x17f,,,,,,,,,,,,,,,,,
|
||||
KEY_TAPE,0x180,,,,,,,,,,,,,,,,,
|
||||
KEY_RADIO,0x181,,,,,,,,,,,,,,,,,
|
||||
KEY_TUNER,0x182,,,,,,,,,,,,,,,,,
|
||||
KEY_PLAYER,0x183,,,,,,,,,,,,,,,,,
|
||||
KEY_TEXT,0x184,,,,,,,,,,,,,,,,,
|
||||
KEY_DVD,0x185,,,,,,,,,,,,,,,,,
|
||||
KEY_AUX,0x186,,,,,,,,,,,,,,,,,
|
||||
KEY_MP3,0x187,,,,,,,,,,,,,,,,,
|
||||
KEY_AUDIO,0x188,,,,,,,,,,,,,,,,,
|
||||
KEY_VIDEO,0x189,,,,,,,,,,,,,,,,,
|
||||
KEY_DIRECTORY,0x18a,,,,,,,,,,,,,,,,,
|
||||
KEY_LIST,0x18b,,,,,,,,,,,,,,,,,
|
||||
KEY_MEMO,0x18c,,,,,,,,,,,,,,,,,
|
||||
KEY_CALENDAR,0x18d,,,,,,,,,,,,,,,,,
|
||||
KEY_RED,0x18e,,,,,,,,,,,,,,,,,
|
||||
KEY_GREEN,0x18f,,,,,,,,,,,,,,,,,
|
||||
KEY_YELLOW,0x190,,,,,,,,,,,,,,,,,
|
||||
KEY_BLUE,0x191,,,,,,,,,,,,,,,,,
|
||||
KEY_CHANNELUP,0x192,,,,,,,,,,,,,,,,,
|
||||
KEY_CHANNELDOWN,0x193,,,,,,,,,,,,,,,,,
|
||||
KEY_FIRST,0x194,,,,,,,,,,,,,,,,,
|
||||
KEY_LAST,0x195,,,,,,,,,,,,,,,,,
|
||||
KEY_AB,0x196,,,,,,,,,,,,,,,,,
|
||||
KEY_NEXT,0x197,,,,,,,,,,,,,,,,,
|
||||
KEY_RESTART,0x198,,,,,,,,,,,,,,,,,
|
||||
KEY_SLOW,0x199,,,,,,,,,,,,,,,,,
|
||||
KEY_SHUFFLE,0x19a,,,,,,,,,,,,,,,,,
|
||||
KEY_BREAK,0x19b,,,,,,,,,,,,,,BREA,,,
|
||||
KEY_BREAK,0x19b,,,,,,,,,,,,,,BRK,,,
|
||||
KEY_PREVIOUS,0x19c,,,,,,,,,,,,,,,,,
|
||||
KEY_DIGITS,0x19d,,,,,,,,,,,,,,,,,
|
||||
KEY_TEEN,0x19e,,,,,,,,,,,,,,,,,
|
||||
KEY_TWEN,0x19f,,,,,,,,,,,,,,,,,
|
||||
KEY_VIDEOPHONE,0x1a0,,,,,,,,,,,,,,,,,
|
||||
KEY_GAMES,0x1a1,,,,,,,,,,,,,,,,,
|
||||
KEY_ZOOMIN,0x1a2,,,,,,,,,,,,,,,,,
|
||||
KEY_ZOOMOUT,0x1a3,,,,,,,,,,,,,,,,,
|
||||
KEY_ZOOMRESET,0x1a4,,,,,,,,,,,,,,,,,
|
||||
KEY_WORDPROCESSOR,0x1a5,,,,,,,,,,,,,,,,,
|
||||
KEY_EDITOR,0x1a6,,,,,,,,,,,,,,,,,
|
||||
KEY_SPREADSHEET,0x1a7,,,,,,,,,,,,,,,,,
|
||||
KEY_GRAPHICSEDITOR,0x1a8,,,,,,,,,,,,,,,,,
|
||||
KEY_PRESENTATION,0x1a9,,,,,,,,,,,,,,,,,
|
||||
KEY_DATABASE,0x1aa,,,,,,,,,,,,,,,,,
|
||||
KEY_NEWS,0x1ab,,,,,,,,,,,,,,,,,
|
||||
KEY_VOICEMAIL,0x1ac,,,,,,,,,,,,,,,,,
|
||||
KEY_ADDRESSBOOK,0x1ad,,,,,,,,,,,,,,,,,
|
||||
KEY_MESSENGER,0x1ae,,,,,,,,,,,,,,,,,
|
||||
KEY_DISPLAYTOGGLE,0x1af,,,,,,,,,,,,,,,,,
|
||||
KEY_SPELLCHECK,0x1b0,,,,,,,,,,,,,,,,,
|
||||
KEY_LOGOFF,0x1b1,,,,,,,,,,,,,,,,,
|
||||
KEY_DOLLAR,0x1b2,,,,,,,,,,,,,,,,,
|
||||
KEY_EURO,0x1b3,,,,,,,,,,,,,,,,,
|
||||
KEY_FRAMEBACK,0x1b4,,,,,,,,,,,,,,,,,
|
||||
KEY_FRAMEFORWARD,0x1b5,,,,,,,,,,,,,,,,,
|
||||
KEY_CONTEXT_MENU,0x1b6,,,,,,,,,,,,,,,,,
|
||||
KEY_MEDIA_REPEAT,0x1b7,,,,,,,,,,,,,,,,,
|
||||
KEY_DEL_EOL,0x1c0,,,,,,,,,,,,,,,,,
|
||||
KEY_DEL_EOS,0x1c1,,,,,,,,,,,,,,,,,
|
||||
KEY_INS_LINE,0x1c2,,,,,,,,,,,,,,,,,
|
||||
KEY_DEL_LINE,0x1c3,,,,,,,,,,,,,,,,,
|
||||
KEY_FN,0x1d0,Function,0x3f,,,,,,,,,,,Fn,,,,
|
||||
KEY_FN_ESC,0x1d1,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_F1,0x1d2,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_F2,0x1d3,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_F3,0x1d4,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_F4,0x1d5,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_F5,0x1d6,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_F6,0x1d7,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_F7,0x1d8,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_F8,0x1d9,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_F9,0x1da,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_F10,0x1db,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_F11,0x1dc,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_F12,0x1dd,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_1,0x1de,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_2,0x1df,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_D,0x1e0,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_E,0x1e1,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_F,0x1e2,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_S,0x1e3,,,,,,,,,,,,,,,,,
|
||||
KEY_FN_B,0x1e4,,,,,,,,,,,,,,,,,
|
||||
KEY_BRL_DOT1,0x1f1,,,,,,,,,,,,,,,,,
|
||||
KEY_BRL_DOT2,0x1f2,,,,,,,,,,,,,,,,,
|
||||
KEY_BRL_DOT3,0x1f3,,,,,,,,,,,,,,,,,
|
||||
KEY_BRL_DOT4,0x1f4,,,,,,,,,,,,,,,,,
|
||||
KEY_BRL_DOT5,0x1f5,,,,,,,,,,,,,,,,,
|
||||
KEY_BRL_DOT6,0x1f6,,,,,,,,,,,,,,,,,
|
||||
KEY_BRL_DOT7,0x1f7,,,,,,,,,,,,,,,,,
|
||||
KEY_BRL_DOT8,0x1f8,,,,,,,,,,,,,,,,,
|
||||
KEY_BRL_DOT9,0x1f9,,,,,,,,,,,,,,,,,
|
||||
KEY_BRL_DOT10,0x1fa,,,,,,,,,,,,,,,,,
|
||||
KEY_NUMERIC_0,0x200,,,,,,,,,,,,,,,,,
|
||||
KEY_NUMERIC_1,0x201,,,,,,,,,,,,,,,,,
|
||||
KEY_NUMERIC_2,0x202,,,,,,,,,,,,,,,,,
|
||||
KEY_NUMERIC_3,0x203,,,,,,,,,,,,,,,,,
|
||||
KEY_NUMERIC_4,0x204,,,,,,,,,,,,,,,,,
|
||||
KEY_NUMERIC_5,0x205,,,,,,,,,,,,,,,,,
|
||||
KEY_NUMERIC_6,0x206,,,,,,,,,,,,,,,,,
|
||||
KEY_NUMERIC_7,0x207,,,,,,,,,,,,,,,,,
|
||||
KEY_NUMERIC_8,0x208,,,,,,,,,,,,,,,,,
|
||||
KEY_NUMERIC_9,0x209,,,,,,,,,,,,,,,,,
|
||||
KEY_NUMERIC_STAR,0x20a,,,,,,,,,,,,,NumpadStar,,,,
|
||||
KEY_NUMERIC_POUND,0x20b,,,,,,,,,,,,,NumpadHash,,,,
|
||||
KEY_RFKILL,0x20c,,,,,,,,,,,,,,,,,
|
|
11
keycodemapdb/tests/.gitignore
vendored
Normal file
11
keycodemapdb/tests/.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
osx2win32.*
|
||||
osx2win32_name.*
|
||||
osx2xkb.*
|
||||
osx2xkb_name.*
|
||||
html2win32.*
|
||||
html2win32_name.*
|
||||
osx.*
|
||||
osx_name.*
|
||||
stdc
|
||||
stdc++
|
||||
node_modules/
|
118
keycodemapdb/tests/Makefile
Normal file
118
keycodemapdb/tests/Makefile
Normal file
@ -0,0 +1,118 @@
|
||||
TESTS := stdc stdc++ python2 python3 javascript
|
||||
|
||||
check: $(TESTS)
|
||||
@set -e; for fn in $(TESTS); do \
|
||||
./$$fn; \
|
||||
echo $$fn: OK; \
|
||||
done
|
||||
@echo Done.
|
||||
|
||||
GEN := ../tools/keymap-gen
|
||||
DATA := ../data/keymaps.csv
|
||||
SOURCES := $(GEN) $(DATA)
|
||||
|
||||
.DELETE_ON_ERROR:
|
||||
|
||||
stdc: stdc.c osx2win32.h osx2win32_name.h \
|
||||
osx2xkb.h osx2xkb_name.h \
|
||||
html2win32.h html2win32_name.h \
|
||||
osx.h osx_name.h
|
||||
$(CC) -Wall -o $@ $^
|
||||
osx2win32.h: $(SOURCES)
|
||||
$(GEN) --lang stdc code-map $(DATA) osx win32 > $@
|
||||
osx2win32_name.h: $(SOURCES)
|
||||
$(GEN) --lang stdc name-map $(DATA) osx win32 > $@
|
||||
osx2xkb.h: $(SOURCES)
|
||||
$(GEN) --lang stdc code-map $(DATA) osx xkb > $@
|
||||
osx2xkb_name.h: $(SOURCES)
|
||||
$(GEN) --lang stdc name-map $(DATA) osx xkb > $@
|
||||
html2win32.h: $(SOURCES)
|
||||
$(GEN) --lang stdc code-map $(DATA) html win32 > $@
|
||||
html2win32_name.h: $(SOURCES)
|
||||
$(GEN) --lang stdc name-map $(DATA) html win32 > $@
|
||||
osx.h: $(SOURCES)
|
||||
$(GEN) --lang stdc code-table $(DATA) osx > $@
|
||||
osx_name.h: $(SOURCES)
|
||||
$(GEN) --lang stdc name-table $(DATA) osx > $@
|
||||
|
||||
stdc++: stdc++.cc osx2win32.hh osx2win32_name.hh \
|
||||
osx2xkb.hh osx2xkb_name.hh \
|
||||
html2win32.hh html2win32_name.hh \
|
||||
osx.hh osx_name.hh
|
||||
$(CXX) -Wall -std=c++11 -o $@ $^
|
||||
osx2win32.hh: $(SOURCES)
|
||||
$(GEN) --lang stdc++ code-map $(DATA) osx win32 > $@
|
||||
osx2win32_name.hh: $(SOURCES)
|
||||
$(GEN) --lang stdc++ name-map $(DATA) osx win32 > $@
|
||||
osx2xkb.hh: $(SOURCES)
|
||||
$(GEN) --lang stdc++ code-map $(DATA) osx xkb > $@
|
||||
osx2xkb_name.hh: $(SOURCES)
|
||||
$(GEN) --lang stdc++ name-map $(DATA) osx xkb > $@
|
||||
html2win32.hh: $(SOURCES)
|
||||
$(GEN) --lang stdc++ code-map $(DATA) html win32 > $@
|
||||
html2win32_name.hh: $(SOURCES)
|
||||
$(GEN) --lang stdc++ name-map $(DATA) html win32 > $@
|
||||
osx.hh: $(SOURCES)
|
||||
$(GEN) --lang stdc++ code-table $(DATA) osx > $@
|
||||
osx_name.hh: $(SOURCES)
|
||||
$(GEN) --lang stdc++ name-table $(DATA) osx > $@
|
||||
|
||||
python2: osx2win32.py osx2win32_name.py \
|
||||
osx2xkb.py osx2xkb_name.py \
|
||||
html2win32.py html2win32_name.py \
|
||||
osx.py osx_name.py
|
||||
osx2win32.py: $(SOURCES)
|
||||
$(GEN) --lang python2 code-map $(DATA) osx win32 > $@
|
||||
osx2win32_name.py: $(SOURCES)
|
||||
$(GEN) --lang python2 name-map $(DATA) osx win32 > $@
|
||||
osx2xkb.py: $(SOURCES)
|
||||
$(GEN) --lang python2 code-map $(DATA) osx xkb > $@
|
||||
osx2xkb_name.py: $(SOURCES)
|
||||
$(GEN) --lang python2 name-map $(DATA) osx xkb > $@
|
||||
html2win32.py: $(SOURCES)
|
||||
$(GEN) --lang python2 code-map $(DATA) html win32 > $@
|
||||
html2win32_name.py: $(SOURCES)
|
||||
$(GEN) --lang python2 name-map $(DATA) html win32 > $@
|
||||
osx.py: $(SOURCES)
|
||||
$(GEN) --lang python2 code-table $(DATA) osx > $@
|
||||
osx_name.py: $(SOURCES)
|
||||
$(GEN) --lang python2 name-table $(DATA) osx > $@
|
||||
|
||||
javascript: node_modules/babel-core \
|
||||
node_modules/babel-plugin-transform-es2015-modules-commonjs \
|
||||
osx2win32.js osx2win32_name.js \
|
||||
osx2xkb.js osx2xkb_name.js \
|
||||
html2win32.js html2win32_name.js \
|
||||
osx.js osx_name.js
|
||||
node_modules/babel-core:
|
||||
npm install babel-core
|
||||
node_modules/babel-plugin-transform-es2015-modules-commonjs:
|
||||
npm install babel-plugin-transform-es2015-modules-commonjs
|
||||
osx2win32.js: $(SOURCES)
|
||||
$(GEN) --lang js code-map $(DATA) osx win32 > $@
|
||||
osx2win32_name.js: $(SOURCES)
|
||||
$(GEN) --lang js name-map $(DATA) osx win32 > $@
|
||||
osx2xkb.js: $(SOURCES)
|
||||
$(GEN) --lang js code-map $(DATA) osx xkb > $@
|
||||
osx2xkb_name.js: $(SOURCES)
|
||||
$(GEN) --lang js name-map $(DATA) osx xkb > $@
|
||||
html2win32.js: $(SOURCES)
|
||||
$(GEN) --lang js code-map $(DATA) html win32 > $@
|
||||
html2win32_name.js: $(SOURCES)
|
||||
$(GEN) --lang js name-map $(DATA) html win32 > $@
|
||||
osx.js: $(SOURCES)
|
||||
$(GEN) --lang js code-table $(DATA) osx > $@
|
||||
osx_name.js: $(SOURCES)
|
||||
$(GEN) --lang js name-table $(DATA) osx > $@
|
||||
|
||||
clean:
|
||||
rm -rf node_modules
|
||||
rm -f osx2win32.*
|
||||
rm -f osx2win32_name.*
|
||||
rm -f osx2xkb.*
|
||||
rm -f osx2xkb_name.*
|
||||
rm -f html2win32.*
|
||||
rm -f html2win32_name.*
|
||||
rm -f osx.*
|
||||
rm -f osx_name.*
|
||||
rm -f stdc stdc++
|
53
keycodemapdb/tests/javascript
Executable file
53
keycodemapdb/tests/javascript
Executable file
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env node
|
||||
/*
|
||||
* Keycode Map Generator JavaScript Tests
|
||||
*
|
||||
* Copyright 2017 Pierre Ossman for Cendio AB
|
||||
*
|
||||
* This file is dual license under the terms of the GPLv2 or later
|
||||
* and 3-clause BSD licenses.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var assert = require('assert');
|
||||
var babel = require('babel-core');
|
||||
var fs = require('fs');
|
||||
|
||||
function include(fn) {
|
||||
var options = {
|
||||
plugins: ["transform-es2015-modules-commonjs"]
|
||||
};
|
||||
|
||||
var code = babel.transformFileSync(fn, options).code;
|
||||
fs.writeFileSync("." + fn + "_nodejs.js", code);
|
||||
var imp = require("./." + fn + "_nodejs.js");
|
||||
fs.unlinkSync("./." + fn + "_nodejs.js");
|
||||
|
||||
return imp
|
||||
}
|
||||
|
||||
var code_map_osx_to_win32 = include("osx2win32.js").default;
|
||||
var name_map_osx_to_win32 = include("osx2win32_name.js").default;
|
||||
|
||||
var code_map_osx_to_xkb = include("osx2xkb.js").default;
|
||||
var name_map_osx_to_xkb = include("osx2xkb_name.js").default;
|
||||
|
||||
var code_map_html_to_win32 = include("html2win32.js").default;
|
||||
var name_map_html_to_win32 = include("html2win32_name.js").default;
|
||||
|
||||
var code_table_osx = include("osx.js").default;
|
||||
var name_table_osx = include("osx_name.js").default;
|
||||
|
||||
assert.equal(code_map_osx_to_win32[0x1d], 0x30);
|
||||
assert.equal(name_map_osx_to_win32[0x1d], "VK_0");
|
||||
|
||||
assert.equal(code_map_osx_to_xkb[0x1d], "AE10");
|
||||
assert.equal(name_map_osx_to_xkb[0x1d], "AE10");
|
||||
|
||||
assert.equal(code_map_html_to_win32["ControlLeft"], 0x11);
|
||||
assert.equal(name_map_html_to_win32["ControlLeft"], "VK_CONTROL");
|
||||
|
||||
assert.equal(code_table_osx[0x1d], 0x3b);
|
||||
assert.equal(name_table_osx[0x1d], "Control");
|
||||
|
3
keycodemapdb/tests/python2
Executable file
3
keycodemapdb/tests/python2
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
python ./test.py
|
3
keycodemapdb/tests/python3
Executable file
3
keycodemapdb/tests/python3
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
python3 ./test.py
|
40
keycodemapdb/tests/stdc++.cc
Normal file
40
keycodemapdb/tests/stdc++.cc
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Keycode Map Generator C++ Tests
|
||||
*
|
||||
* Copyright 2017 Pierre Ossman for Cendio AB
|
||||
*
|
||||
* This file is dual license under the terms of the GPLv2 or later
|
||||
* and 3-clause BSD licenses.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "osx2win32.hh"
|
||||
#include "osx2win32_name.hh"
|
||||
|
||||
#include "osx2xkb.hh"
|
||||
#include "osx2xkb_name.hh"
|
||||
|
||||
#include "html2win32.hh"
|
||||
#include "html2win32_name.hh"
|
||||
|
||||
#include "osx.hh"
|
||||
#include "osx_name.hh"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
assert(code_map_osx_to_win32[0x1d] == 0x30);
|
||||
assert(strcmp(name_map_osx_to_win32[0x1d], "VK_0") == 0);
|
||||
|
||||
assert(strcmp(code_map_osx_to_xkb[0x1d], "AE10") == 0);
|
||||
assert(strcmp(name_map_osx_to_xkb[0x1d], "AE10") == 0);
|
||||
|
||||
assert(code_map_html_to_win32.at("ControlLeft") == 0x11);
|
||||
assert(strcmp(name_map_html_to_win32.at("ControlLeft"), "VK_CONTROL") == 0);
|
||||
|
||||
assert(code_table_osx[0x1d] == 0x3b);
|
||||
assert(strcmp(name_table_osx[0x1d], "Control") == 0);
|
||||
|
||||
return 0;
|
||||
}
|
64
keycodemapdb/tests/stdc.c
Normal file
64
keycodemapdb/tests/stdc.c
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Keycode Map Generator C Tests
|
||||
*
|
||||
* Copyright 2017 Pierre Ossman for Cendio AB
|
||||
*
|
||||
* This file is dual license under the terms of the GPLv2 or later
|
||||
* and 3-clause BSD licenses.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "osx2win32.h"
|
||||
#include "osx2win32_name.h"
|
||||
|
||||
#include "osx2xkb.h"
|
||||
#include "osx2xkb_name.h"
|
||||
|
||||
#include "html2win32.h"
|
||||
#include "html2win32_name.h"
|
||||
|
||||
#include "osx.h"
|
||||
#include "osx_name.h"
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
assert(code_map_osx_to_win32_len == ARRAY_SIZE(code_map_osx_to_win32));
|
||||
assert(code_map_osx_to_win32[0x1d] == 0x30);
|
||||
assert(name_map_osx_to_win32_len == ARRAY_SIZE(name_map_osx_to_win32));
|
||||
assert(strcmp(name_map_osx_to_win32[0x1d], "VK_0") == 0);
|
||||
|
||||
assert(code_map_osx_to_xkb_len == ARRAY_SIZE(code_map_osx_to_xkb));
|
||||
assert(strcmp(code_map_osx_to_xkb[0x1d], "AE10") == 0);
|
||||
assert(name_map_osx_to_xkb_len == ARRAY_SIZE(name_map_osx_to_xkb));
|
||||
assert(strcmp(name_map_osx_to_xkb[0x1d], "AE10") == 0);
|
||||
|
||||
assert(code_map_html_to_win32_len == ARRAY_SIZE(code_map_html_to_win32));
|
||||
for (i = 0;i < code_map_html_to_win32_len;i++) {
|
||||
if (strcmp(code_map_html_to_win32[i].from, "ControlLeft") == 0) {
|
||||
assert(code_map_html_to_win32[i].to == 0x11);
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(i != code_map_html_to_win32_len);
|
||||
assert(name_map_html_to_win32_len == ARRAY_SIZE(name_map_html_to_win32));
|
||||
for (i = 0;i < name_map_html_to_win32_len;i++) {
|
||||
if (strcmp(name_map_html_to_win32[i].from, "ControlLeft") == 0) {
|
||||
assert(strcmp(name_map_html_to_win32[i].to, "VK_CONTROL") == 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(i != name_map_html_to_win32_len);
|
||||
|
||||
assert(code_table_osx_len == ARRAY_SIZE(code_table_osx));
|
||||
assert(code_table_osx[0x1d] == 0x3b);
|
||||
assert(name_table_osx_len == ARRAY_SIZE(name_table_osx));
|
||||
assert(strcmp(name_table_osx[0x1d], "Control") == 0);
|
||||
|
||||
return 0;
|
||||
}
|
30
keycodemapdb/tests/test.py
Normal file
30
keycodemapdb/tests/test.py
Normal file
@ -0,0 +1,30 @@
|
||||
# Keycode Map Generator Python Tests
|
||||
#
|
||||
# Copyright 2017 Pierre Ossman for Cendio AB
|
||||
#
|
||||
# This file is dual license under the terms of the GPLv2 or later
|
||||
# and 3-clause BSD licenses.
|
||||
|
||||
import osx2win32
|
||||
import osx2win32_name
|
||||
|
||||
import osx2xkb
|
||||
import osx2xkb_name
|
||||
|
||||
import html2win32
|
||||
import html2win32_name
|
||||
|
||||
import osx
|
||||
import osx_name
|
||||
|
||||
assert osx2win32.code_map_osx_to_win32[0x1d] == 0x30
|
||||
assert osx2win32_name.name_map_osx_to_win32[0x1d] == "VK_0"
|
||||
|
||||
assert osx2xkb.code_map_osx_to_xkb[0x1d] == "AE10"
|
||||
assert osx2xkb_name.name_map_osx_to_xkb[0x1d] == "AE10"
|
||||
|
||||
assert html2win32.code_map_html_to_win32["ControlLeft"] == 0x11
|
||||
assert html2win32_name.name_map_html_to_win32["ControlLeft"] == "VK_CONTROL"
|
||||
|
||||
assert osx.code_table_osx[0x1d] == 0x3b;
|
||||
assert osx_name.name_table_osx[0x1d] == "Control";
|
20
keycodemapdb/thirdparty/LICENSE-argparse.txt
vendored
Normal file
20
keycodemapdb/thirdparty/LICENSE-argparse.txt
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
argparse is (c) 2006-2009 Steven J. Bethard <steven.bethard@gmail.com>.
|
||||
|
||||
The argparse module was contributed to Python as of Python 2.7 and thus
|
||||
was licensed under the Python license. Same license applies to all files in
|
||||
the argparse package project.
|
||||
|
||||
For details about the Python License, please see doc/Python-License.txt.
|
||||
|
||||
History
|
||||
-------
|
||||
|
||||
Before (and including) argparse 1.1, the argparse package was licensed under
|
||||
Apache License v2.0.
|
||||
|
||||
After argparse 1.1, all project files from the argparse project were deleted
|
||||
due to license compatibility issues between Apache License 2.0 and GNU GPL v2.
|
||||
|
||||
The project repository then had a clean start with some files taken from
|
||||
Python 2.7.1, so definitely all files are under Python License now.
|
||||
|
0
keycodemapdb/thirdparty/__init__.py
vendored
Normal file
0
keycodemapdb/thirdparty/__init__.py
vendored
Normal file
2392
keycodemapdb/thirdparty/argparse.py
vendored
Normal file
2392
keycodemapdb/thirdparty/argparse.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
972
keycodemapdb/tools/keymap-gen
Executable file
972
keycodemapdb/tools/keymap-gen
Executable file
@ -0,0 +1,972 @@
|
||||
#!/usr/bin/python
|
||||
# -*- python -*-
|
||||
#
|
||||
# Keycode Map Generator
|
||||
#
|
||||
# Copyright (C) 2009-2017 Red Hat, Inc.
|
||||
#
|
||||
# This file is dual license under the terms of the GPLv2 or later
|
||||
# and 3-clause BSD licenses.
|
||||
#
|
||||
|
||||
# Requires >= 2.6
|
||||
from __future__ import print_function
|
||||
|
||||
import csv
|
||||
try:
|
||||
import argparse
|
||||
except:
|
||||
import os, sys
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), "../thirdparty"))
|
||||
import argparse
|
||||
import hashlib
|
||||
import time
|
||||
import sys
|
||||
|
||||
class Database:
|
||||
|
||||
# Linux: linux/input.h
|
||||
MAP_LINUX = "linux"
|
||||
|
||||
# OS-X: Carbon/HIToolbox/Events.h
|
||||
MAP_OSX = "osx"
|
||||
|
||||
# AT Set 1: linux/drivers/input/keyboard/atkbd.c
|
||||
# (atkbd_set2_keycode + atkbd_unxlate_table)
|
||||
MAP_ATSET1 = "atset1"
|
||||
|
||||
# AT Set 2: linux/drivers/input/keyboard/atkbd.c
|
||||
# (atkbd_set2_keycode)
|
||||
MAP_ATSET2 = "atset2"
|
||||
|
||||
# AT Set 3: linux/drivers/input/keyboard/atkbd.c
|
||||
# (atkbd_set3_keycode)
|
||||
MAP_ATSET3 = "atset3"
|
||||
|
||||
# Linux RAW: linux/drivers/char/keyboard.c (x86_keycodes)
|
||||
MAP_XTKBD = "xtkbd"
|
||||
|
||||
# USB HID: linux/drivers/hid/usbhid/usbkbd.c (usb_kbd_keycode)
|
||||
MAP_USB = "usb"
|
||||
|
||||
# Win32: mingw32/winuser.h
|
||||
MAP_WIN32 = "win32"
|
||||
|
||||
# XWin XT: xorg-server/hw/xwin/{winkeybd.c,winkeynames.h}
|
||||
# (xt + manually transcribed)
|
||||
MAP_XWINXT = "xwinxt"
|
||||
|
||||
# X11: http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
|
||||
MAP_X11 = "x11"
|
||||
|
||||
# XKBD XT: xf86-input-keyboard/src/at_scancode.c
|
||||
# (xt + manually transcribed)
|
||||
MAP_XKBDXT = "xkbdxt"
|
||||
|
||||
# Xorg with evdev: linux + an offset
|
||||
MAP_XORGEVDEV = "xorgevdev"
|
||||
|
||||
# Xorg with kbd: xkbdxt + an offset
|
||||
MAP_XORGKBD = "xorgkbd"
|
||||
|
||||
# Xorg with OS-X: osx + an offset
|
||||
MAP_XORGXQUARTZ = "xorgxquartz"
|
||||
|
||||
# Xorg + Cygwin: xwinxt + an offset
|
||||
MAP_XORGXWIN = "xorgxwin"
|
||||
|
||||
# QEMU key numbers: xtkbd + special re-encoding of high bit
|
||||
MAP_QNUM = "qnum"
|
||||
|
||||
# HTML codes
|
||||
MAP_HTML = "html"
|
||||
|
||||
# XKB key names
|
||||
MAP_XKB = "xkb"
|
||||
|
||||
# QEMU keycodes
|
||||
MAP_QCODE = "qcode"
|
||||
|
||||
# Sun / Sparc scan codes
|
||||
# Reference: "SPARC International Keyboard Spec 1", page 7 "US scan set"
|
||||
MAP_SUN = "sun"
|
||||
|
||||
# Apple Desktop Bus
|
||||
# Reference: http://www.archive.org/stream/apple-guide-macintosh-family-hardware/Apple_Guide_to_the_Macintosh_Family_Hardware_2e#page/n345/mode/2up
|
||||
MAP_ADB = "adb"
|
||||
|
||||
MAP_LIST = (
|
||||
MAP_LINUX,
|
||||
MAP_OSX,
|
||||
MAP_ATSET1,
|
||||
MAP_ATSET2,
|
||||
MAP_ATSET3,
|
||||
MAP_USB,
|
||||
MAP_WIN32,
|
||||
MAP_XWINXT,
|
||||
MAP_XKBDXT,
|
||||
MAP_X11,
|
||||
MAP_HTML,
|
||||
MAP_XKB,
|
||||
MAP_QCODE,
|
||||
MAP_SUN,
|
||||
MAP_ADB,
|
||||
|
||||
# These are derived from maps above
|
||||
MAP_XTKBD,
|
||||
MAP_XORGEVDEV,
|
||||
MAP_XORGKBD,
|
||||
MAP_XORGXQUARTZ,
|
||||
MAP_XORGXWIN,
|
||||
MAP_QNUM,
|
||||
)
|
||||
|
||||
CODE_COLUMNS = {
|
||||
MAP_LINUX: 1,
|
||||
MAP_OSX: 3,
|
||||
MAP_ATSET1: 4,
|
||||
MAP_ATSET2: 5,
|
||||
MAP_ATSET3: 6,
|
||||
MAP_USB: 7,
|
||||
MAP_WIN32: 9,
|
||||
MAP_XWINXT: 10,
|
||||
MAP_XKBDXT: 11,
|
||||
MAP_X11: 13,
|
||||
MAP_HTML: 14,
|
||||
MAP_XKB: 15,
|
||||
MAP_SUN: 17,
|
||||
MAP_ADB: 18,
|
||||
}
|
||||
|
||||
ENUM_COLUMNS = {
|
||||
MAP_QCODE: 14,
|
||||
}
|
||||
|
||||
NAME_COLUMNS = {
|
||||
MAP_LINUX: 0,
|
||||
MAP_OSX: 2,
|
||||
MAP_WIN32: 8,
|
||||
MAP_X11: 12,
|
||||
MAP_HTML: 14,
|
||||
MAP_XKB: 15,
|
||||
MAP_QCODE: 16,
|
||||
}
|
||||
|
||||
ENUM_BOUND = {
|
||||
MAP_QCODE: "Q_KEY_CODE__MAX",
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.mapto = {}
|
||||
self.mapfrom = {}
|
||||
self.mapname = {}
|
||||
self.mapchecksum = None
|
||||
|
||||
for name in self.MAP_LIST:
|
||||
# Key is a MAP_LINUX, value is a MAP_XXX
|
||||
self.mapto[name] = {}
|
||||
# key is a MAP_XXX, value is a MAP_LINUX
|
||||
self.mapfrom[name] = {}
|
||||
|
||||
for name in self.NAME_COLUMNS.keys():
|
||||
# key is a MAP_LINUX, value is a string
|
||||
self.mapname[name] = {}
|
||||
|
||||
def _generate_checksum(self, filename):
|
||||
hash = hashlib.sha256()
|
||||
with open(filename, "rb") as f:
|
||||
for chunk in iter(lambda: f.read(4096), b""):
|
||||
hash.update(chunk)
|
||||
self.mapchecksum = hash.hexdigest()
|
||||
|
||||
def load(self, filename):
|
||||
self._generate_checksum(filename)
|
||||
|
||||
with open(filename, 'r') as f:
|
||||
reader = csv.reader(f)
|
||||
|
||||
first = True
|
||||
|
||||
for row in reader:
|
||||
# Discard column headings
|
||||
if first:
|
||||
first = False
|
||||
continue
|
||||
|
||||
# We special case MAP_LINUX since that is out
|
||||
# master via which all other mappings are done
|
||||
linux = self.load_linux(row)
|
||||
|
||||
# Now load all the remaining master data values
|
||||
self.load_data(row, linux)
|
||||
|
||||
# Then load all the keycode names
|
||||
self.load_names(row, linux)
|
||||
|
||||
# Finally calculate derived key maps
|
||||
self.derive_data(row, linux)
|
||||
|
||||
def load_linux(self, row):
|
||||
col = self.CODE_COLUMNS[self.MAP_LINUX]
|
||||
linux = row[col]
|
||||
|
||||
if linux.startswith("0x"):
|
||||
linux = int(linux, 16)
|
||||
else:
|
||||
linux = int(linux, 10)
|
||||
|
||||
self.mapto[self.MAP_LINUX][linux] = linux
|
||||
self.mapfrom[self.MAP_LINUX][linux] = linux
|
||||
|
||||
return linux
|
||||
|
||||
|
||||
def load_data(self, row, linux):
|
||||
for mapname in self.CODE_COLUMNS:
|
||||
if mapname == self.MAP_LINUX:
|
||||
continue
|
||||
|
||||
col = self.CODE_COLUMNS[mapname]
|
||||
val = row[col]
|
||||
|
||||
if val == "":
|
||||
continue
|
||||
|
||||
if val.startswith("0x"):
|
||||
val = int(val, 16)
|
||||
elif val.isdigit():
|
||||
val = int(val, 10)
|
||||
|
||||
self.mapto[mapname][linux] = val
|
||||
self.mapfrom[mapname][val] = linux
|
||||
|
||||
def load_names(self, row, linux):
|
||||
for mapname in self.NAME_COLUMNS:
|
||||
col = self.NAME_COLUMNS[mapname]
|
||||
val = row[col]
|
||||
|
||||
if val == "":
|
||||
continue
|
||||
|
||||
self.mapname[mapname][linux] = val
|
||||
|
||||
|
||||
def derive_data(self, row, linux):
|
||||
# Linux RAW is XT scan codes with special encoding of the
|
||||
# 0xe0 scan codes
|
||||
if linux in self.mapto[self.MAP_ATSET1]:
|
||||
at1 = self.mapto[self.MAP_ATSET1][linux]
|
||||
if at1 > 0x7f:
|
||||
assert((at1 & ~0x7f) == 0xe000)
|
||||
xtkbd = 0x100 | (at1 & 0x7f)
|
||||
else:
|
||||
xtkbd = at1
|
||||
self.mapto[self.MAP_XTKBD][linux] = xtkbd
|
||||
self.mapfrom[self.MAP_XTKBD][xtkbd] = linux
|
||||
|
||||
# Xorg KBD is XKBD XT offset by 8
|
||||
if linux in self.mapto[self.MAP_XKBDXT]:
|
||||
xorgkbd = self.mapto[self.MAP_XKBDXT][linux] + 8
|
||||
self.mapto[self.MAP_XORGKBD][linux] = xorgkbd
|
||||
self.mapfrom[self.MAP_XORGKBD][xorgkbd] = linux
|
||||
|
||||
# Xorg evdev is Linux offset by 8
|
||||
self.mapto[self.MAP_XORGEVDEV][linux] = linux + 8
|
||||
self.mapfrom[self.MAP_XORGEVDEV][linux + 8] = linux
|
||||
|
||||
# Xorg XQuartx is OS-X offset by 8
|
||||
if linux in self.mapto[self.MAP_OSX]:
|
||||
xorgxquartz = self.mapto[self.MAP_OSX][linux] + 8
|
||||
self.mapto[self.MAP_XORGXQUARTZ][linux] = xorgxquartz
|
||||
self.mapfrom[self.MAP_XORGXQUARTZ][xorgxquartz] = linux
|
||||
|
||||
# Xorg Xwin (aka Cygwin) is XWin XT offset by 8
|
||||
if linux in self.mapto[self.MAP_XWINXT]:
|
||||
xorgxwin = self.mapto[self.MAP_XWINXT][linux] + 8
|
||||
self.mapto[self.MAP_XORGXWIN][linux] = xorgxwin
|
||||
self.mapfrom[self.MAP_XORGXWIN][xorgxwin] = linux
|
||||
|
||||
# QNUM keycodes are XT scan codes with a slightly
|
||||
# different encoding of 0xe0 scan codes
|
||||
if linux in self.mapto[self.MAP_ATSET1]:
|
||||
at1 = self.mapto[self.MAP_ATSET1][linux]
|
||||
if at1 > 0x7f:
|
||||
assert((at1 & ~0x7f) == 0xe000)
|
||||
qnum = 0x80 | (at1 & 0x7f)
|
||||
else:
|
||||
qnum = at1
|
||||
self.mapto[self.MAP_QNUM][linux] = qnum
|
||||
self.mapfrom[self.MAP_QNUM][qnum] = linux
|
||||
|
||||
# Hack for compatibility with previous mistakes in handling
|
||||
# Print/SysRq. The preferred qnum for Print/SysRq is 0x54,
|
||||
# but QEMU previously allowed 0xb7 too
|
||||
if qnum == 0x54:
|
||||
self.mapfrom[self.MAP_QNUM][0xb7] = self.mapfrom[self.MAP_QNUM][0x54]
|
||||
|
||||
if linux in self.mapname[self.MAP_QCODE]:
|
||||
qcodeenum = self.mapname[self.MAP_QCODE][linux]
|
||||
qcodeenum = "Q_KEY_CODE_" + qcodeenum.upper()
|
||||
self.mapto[self.MAP_QCODE][linux] = qcodeenum
|
||||
self.mapfrom[self.MAP_QCODE][qcodeenum] = linux
|
||||
|
||||
class LanguageGenerator(object):
|
||||
|
||||
def _boilerplate(self, lines):
|
||||
raise NotImplementedError()
|
||||
|
||||
def generate_header(self, database, args):
|
||||
today = time.strftime("%Y-%m-%d %H:%M")
|
||||
self._boilerplate([
|
||||
"This file is auto-generated from keymaps.csv on %s" % today,
|
||||
"Database checksum sha256(%s)" % database.mapchecksum,
|
||||
"To re-generate, run:",
|
||||
" %s" % args,
|
||||
])
|
||||
|
||||
class LanguageSrcGenerator(LanguageGenerator):
|
||||
|
||||
TYPE_INT = "integer"
|
||||
TYPE_STRING = "string"
|
||||
TYPE_ENUM = "enum"
|
||||
|
||||
def _array_start(self, varname, length, defvalue, fromtype, totype):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _array_end(self, fromtype, totype):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _array_entry(self, index, value, comment, fromtype, totype):
|
||||
raise NotImplementedError()
|
||||
|
||||
def generate_code_map(self, varname, database, frommapname, tomapname):
|
||||
if frommapname not in database.mapfrom:
|
||||
raise Exception("Unknown map %s, expected one of %s" % (
|
||||
frommapname, ", ".join(database.mapfrom.keys())))
|
||||
if tomapname not in database.mapto:
|
||||
raise Exception("Unknown map %s, expected one of %s" % (
|
||||
tomapname, ", ".join(database.mapto.keys())))
|
||||
|
||||
tolinux = database.mapfrom[frommapname]
|
||||
fromlinux = database.mapto[tomapname]
|
||||
|
||||
if varname is None:
|
||||
varname = "code_map_%s_to_%s" % (frommapname, tomapname)
|
||||
|
||||
if frommapname in database.ENUM_COLUMNS:
|
||||
fromtype = self.TYPE_ENUM
|
||||
elif type(tolinux.keys()[0]) == str:
|
||||
fromtype = self.TYPE_STRING
|
||||
else:
|
||||
fromtype = self.TYPE_INT
|
||||
|
||||
if tomapname in database.ENUM_COLUMNS:
|
||||
totype = self.TYPE_ENUM
|
||||
elif type(fromlinux.values()[0]) == str:
|
||||
totype = self.TYPE_STRING
|
||||
else:
|
||||
totype = self.TYPE_INT
|
||||
|
||||
keys = tolinux.keys()
|
||||
keys.sort()
|
||||
if fromtype == self.TYPE_INT:
|
||||
keys = range(keys[-1] + 1)
|
||||
|
||||
if fromtype == self.TYPE_ENUM:
|
||||
keymax = database.ENUM_BOUND[frommapname]
|
||||
else:
|
||||
keymax = len(keys)
|
||||
|
||||
defvalue = fromlinux.get(0, None)
|
||||
if fromtype == self.TYPE_ENUM:
|
||||
self._array_start(varname, keymax, defvalue, fromtype, totype)
|
||||
else:
|
||||
self._array_start(varname, keymax, None, fromtype, totype)
|
||||
|
||||
for src in keys:
|
||||
linux = tolinux.get(src, None)
|
||||
if linux is None:
|
||||
dst = None
|
||||
else:
|
||||
dst = fromlinux.get(linux, defvalue)
|
||||
|
||||
comment = "%s -> %s -> %s" % (self._label(database, frommapname, src, linux),
|
||||
self._label(database, Database.MAP_LINUX, linux, linux),
|
||||
self._label(database, tomapname, dst, linux))
|
||||
self._array_entry(src, dst, comment, fromtype, totype)
|
||||
self._array_end(fromtype, totype)
|
||||
|
||||
def generate_code_table(self, varname, database, mapname):
|
||||
if mapname not in database.mapto:
|
||||
raise Exception("Unknown map %s, expected one of %s" % (
|
||||
mapname, ", ".join(database.mapto.keys())))
|
||||
|
||||
keys = database.mapto[Database.MAP_LINUX].keys()
|
||||
keys.sort()
|
||||
names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
|
||||
|
||||
if varname is None:
|
||||
varname = "code_table_%s" % mapname
|
||||
|
||||
if mapname in database.ENUM_COLUMNS:
|
||||
totype = self.TYPE_ENUM
|
||||
elif type(database.mapto[mapname].values()[0]) == str:
|
||||
totype = self.TYPE_STRING
|
||||
else:
|
||||
totype = self.TYPE_INT
|
||||
|
||||
self._array_start(varname, len(keys), None, self.TYPE_INT, totype)
|
||||
|
||||
defvalue = database.mapto[mapname].get(0, None)
|
||||
for i in range(len(keys)):
|
||||
key = keys[i]
|
||||
dst = database.mapto[mapname].get(key, defvalue)
|
||||
self._array_entry(i, dst, names[i], self.TYPE_INT, totype)
|
||||
|
||||
self._array_end(self.TYPE_INT, totype)
|
||||
|
||||
def generate_name_map(self, varname, database, frommapname, tomapname):
|
||||
if frommapname not in database.mapfrom:
|
||||
raise Exception("Unknown map %s, expected one of %s" % (
|
||||
frommapname, ", ".join(database.mapfrom.keys())))
|
||||
if tomapname not in database.mapname:
|
||||
raise Exception("Unknown map %s, expected one of %s" % (
|
||||
tomapname, ", ".join(database.mapname.keys())))
|
||||
|
||||
tolinux = database.mapfrom[frommapname]
|
||||
fromlinux = database.mapname[tomapname]
|
||||
|
||||
if varname is None:
|
||||
varname = "name_map_%s_to_%s" % (frommapname, tomapname)
|
||||
|
||||
keys = tolinux.keys()
|
||||
keys.sort()
|
||||
if type(keys[0]) == int:
|
||||
keys = range(keys[-1] + 1)
|
||||
|
||||
if type(keys[0]) == int:
|
||||
fromtype = self.TYPE_INT
|
||||
else:
|
||||
fromtype = self.TYPE_STRING
|
||||
|
||||
self._array_start(varname, len(keys), None, fromtype, self.TYPE_STRING)
|
||||
|
||||
for src in keys:
|
||||
linux = tolinux.get(src, None)
|
||||
if linux is None:
|
||||
dst = None
|
||||
else:
|
||||
dst = fromlinux.get(linux, None)
|
||||
|
||||
comment = "%s -> %s -> %s" % (self._label(database, frommapname, src, linux),
|
||||
self._label(database, Database.MAP_LINUX, linux, linux),
|
||||
self._label(database, tomapname, dst, linux))
|
||||
self._array_entry(src, dst, comment, fromtype, self.TYPE_STRING)
|
||||
self._array_end(fromtype, self.TYPE_STRING)
|
||||
|
||||
def generate_name_table(self, varname, database, mapname):
|
||||
if mapname not in database.mapname:
|
||||
raise Exception("Unknown map %s, expected one of %s" % (
|
||||
mapname, ", ".join(database.mapname.keys())))
|
||||
|
||||
keys = database.mapto[Database.MAP_LINUX].keys()
|
||||
keys.sort()
|
||||
names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
|
||||
|
||||
if varname is None:
|
||||
varname = "name_table_%s" % mapname
|
||||
|
||||
self._array_start(varname, len(keys), None, self.TYPE_INT, self.TYPE_STRING)
|
||||
|
||||
for i in range(len(keys)):
|
||||
key = keys[i]
|
||||
dst = database.mapname[mapname].get(key, None)
|
||||
self._array_entry(i, dst, names[i], self.TYPE_INT, self.TYPE_STRING)
|
||||
|
||||
self._array_end(self.TYPE_INT, self.TYPE_STRING)
|
||||
|
||||
def _label(self, database, mapname, val, linux):
|
||||
if mapname in database.mapname:
|
||||
return "%s:%s (%s)" % (mapname, val, database.mapname[mapname].get(linux, "unnamed"))
|
||||
else:
|
||||
return "%s:%s" % (mapname, val)
|
||||
|
||||
class LanguageDocGenerator(LanguageGenerator):
|
||||
|
||||
def _array_start_name_doc(self, varname, namemap):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _array_start_code_doc(self, varname, namemap, codemap):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _array_end(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _array_name_entry(self, value, name):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _array_code_entry(self, value, name):
|
||||
raise NotImplementedError()
|
||||
|
||||
def generate_name_docs(self, varname, database, mapname):
|
||||
if mapname not in database.mapname:
|
||||
raise Exception("Unknown map %s, expected one of %s" % (
|
||||
mapname, ", ".join(database.mapname.keys())))
|
||||
|
||||
keys = database.mapto[Database.MAP_LINUX].keys()
|
||||
keys.sort()
|
||||
names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
|
||||
|
||||
if varname is None:
|
||||
varname = mapname
|
||||
|
||||
self._array_start_name_doc(varname, mapname)
|
||||
|
||||
for i in range(len(keys)):
|
||||
key = keys[i]
|
||||
dst = database.mapname[mapname].get(key, None)
|
||||
self._array_name_entry(key, dst)
|
||||
|
||||
self._array_end()
|
||||
|
||||
|
||||
def generate_code_docs(self, varname, database, mapname):
|
||||
if mapname not in database.mapfrom:
|
||||
raise Exception("Unknown map %s, expected one of %s" % (
|
||||
mapname, ", ".join(database.mapfrom.keys())))
|
||||
|
||||
tolinux = database.mapfrom[mapname]
|
||||
keys = tolinux.keys()
|
||||
keys.sort()
|
||||
if mapname in database.mapname:
|
||||
names = database.mapname[mapname]
|
||||
namemap = mapname
|
||||
else:
|
||||
names = database.mapname[Database.MAP_LINUX]
|
||||
namemap = Database.MAP_LINUX
|
||||
|
||||
if varname is None:
|
||||
varname = mapname
|
||||
|
||||
self._array_start_code_doc(varname, mapname, namemap)
|
||||
|
||||
for i in range(len(keys)):
|
||||
key = keys[i]
|
||||
self._array_code_entry(key, names.get(tolinux[key], "unnamed"))
|
||||
|
||||
self._array_end()
|
||||
|
||||
class CLanguageGenerator(LanguageSrcGenerator):
|
||||
|
||||
def __init__(self, inttypename, strtypename, lentypename):
|
||||
self.inttypename = inttypename
|
||||
self.strtypename = strtypename
|
||||
self.lentypename = lentypename
|
||||
|
||||
def _boilerplate(self, lines):
|
||||
print("/*")
|
||||
for line in lines:
|
||||
print(" * %s" % line)
|
||||
print("*/")
|
||||
|
||||
def _array_start(self, varname, length, defvalue, fromtype, totype):
|
||||
self._varname = varname;
|
||||
totypename = self.strtypename if totype == self.TYPE_STRING else self.inttypename
|
||||
if fromtype in (self.TYPE_INT, self.TYPE_ENUM):
|
||||
if type(length) == str:
|
||||
print("const %s %s[%s] = {" % (totypename, varname, length))
|
||||
else:
|
||||
print("const %s %s[%d] = {" % (totypename, varname, length))
|
||||
else:
|
||||
print("const struct _%s {" % varname)
|
||||
print(" const %s from;" % self.strtypename)
|
||||
print(" const %s to;" % totypename)
|
||||
print("} %s[] = {" % varname)
|
||||
|
||||
if defvalue != None:
|
||||
if totype == self.TYPE_ENUM:
|
||||
if type(length) == str:
|
||||
print(" [0 ... %s-1] = %s," % (length, defvalue))
|
||||
else:
|
||||
print(" [0 ... 0x%x-1] = %s," % (length, defvalue))
|
||||
else:
|
||||
if type(length) == str:
|
||||
print(" [0 ... %s-1] = 0x%x," % (length, defvalue))
|
||||
else:
|
||||
print(" [0 ... 0x%x-1] = 0x%x," % (length, defvalue))
|
||||
|
||||
def _array_end(self, fromtype, totype):
|
||||
print("};")
|
||||
print("const %s %s_len = sizeof(%s)/sizeof(%s[0]);" %
|
||||
(self.lentypename, self._varname, self._varname, self._varname))
|
||||
|
||||
def _array_entry(self, index, value, comment, fromtype, totype):
|
||||
if value is None:
|
||||
return
|
||||
if fromtype == self.TYPE_INT:
|
||||
indexfmt = "0x%x"
|
||||
elif fromtype == self.TYPE_ENUM:
|
||||
indexfmt = "%s"
|
||||
else:
|
||||
indexfmt = "\"%s\""
|
||||
|
||||
if totype == self.TYPE_INT:
|
||||
valuefmt = "0x%x"
|
||||
elif totype == self.TYPE_ENUM:
|
||||
valuefmt = "%s"
|
||||
else:
|
||||
valuefmt = "\"%s\""
|
||||
|
||||
if fromtype != self.TYPE_STRING:
|
||||
print((" [" + indexfmt + "] = " + valuefmt + ", /* %s */") % (index, value, comment))
|
||||
else:
|
||||
print((" {" + indexfmt + ", " + valuefmt + "}, /* %s */") % (index, value, comment))
|
||||
|
||||
class CppLanguageGenerator(CLanguageGenerator):
|
||||
|
||||
def _array_start(self, varname, length, defvalue, fromtype, totype):
|
||||
if fromtype == self.TYPE_ENUM:
|
||||
raise NotImplementedError("Enums not supported as source in C++ generator")
|
||||
totypename = "const " + self.strtypename if totype == self.TYPE_STRING else self.inttypename
|
||||
if fromtype == self.TYPE_INT:
|
||||
print("#include <vector>")
|
||||
print("const std::vector<%s> %s = {" % (totypename, varname))
|
||||
else:
|
||||
print("#include <map>")
|
||||
print("#include <string>")
|
||||
print("const std::map<const std::string, %s> %s = {" % (totypename, varname))
|
||||
|
||||
def _array_end(self, fromtype, totype):
|
||||
print("};")
|
||||
|
||||
# designated initializers not available in C++
|
||||
def _array_entry(self, index, value, comment, fromtype, totype):
|
||||
if fromtype == self.TYPE_STRING:
|
||||
return super(CppLanguageGenerator, self)._array_entry(index, value, comment, fromtype, totype)
|
||||
|
||||
if value is None:
|
||||
print(" 0, /* %s */" % comment)
|
||||
elif totype == self.TYPE_INT:
|
||||
print(" 0x%x, /* %s */" % (value, comment))
|
||||
elif totype == self.TYPE_ENUM:
|
||||
print(" %s, /* %s */" % (value, comment))
|
||||
else:
|
||||
print(" \"%s\", /* %s */" % (value, comment))
|
||||
|
||||
class StdCLanguageGenerator(CLanguageGenerator):
|
||||
|
||||
def __init__(self):
|
||||
super(StdCLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
|
||||
|
||||
class StdCppLanguageGenerator(CppLanguageGenerator):
|
||||
|
||||
def __init__(self):
|
||||
super(StdCppLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
|
||||
|
||||
class GLib2LanguageGenerator(CLanguageGenerator):
|
||||
|
||||
def __init__(self):
|
||||
super(GLib2LanguageGenerator, self).__init__("guint16", "gchar *", "guint")
|
||||
|
||||
class PythonLanguageGenerator(LanguageSrcGenerator):
|
||||
|
||||
def _boilerplate(self, lines):
|
||||
print("#")
|
||||
for line in lines:
|
||||
print("# %s" % line)
|
||||
print("#")
|
||||
|
||||
def _array_start(self, varname, length, defvalue, fromtype, totype):
|
||||
if fromtype == self.TYPE_ENUM:
|
||||
raise NotImplementedError("Enums not supported as source in Python generator")
|
||||
|
||||
if fromtype != self.TYPE_STRING:
|
||||
print("%s = [" % varname)
|
||||
else:
|
||||
print("%s = {" % varname)
|
||||
|
||||
def _array_end(self, fromtype, totype):
|
||||
if fromtype != self.TYPE_STRING:
|
||||
print("]")
|
||||
else:
|
||||
print("}")
|
||||
|
||||
def _array_entry(self, index, value, comment, fromtype, totype):
|
||||
if fromtype == self.TYPE_INT:
|
||||
if value is None:
|
||||
print(" None, # %s" % (comment))
|
||||
elif totype == self.TYPE_INT:
|
||||
print(" 0x%x, # %s" % (value, comment))
|
||||
elif totype == self.TYPE_ENUM:
|
||||
print(" %s, # %s" % (value, comment))
|
||||
else:
|
||||
print(" \"%s\", # %s" % (value, comment))
|
||||
else:
|
||||
if value is None:
|
||||
print(" \"%s\": None, # %s" % (index, comment))
|
||||
elif totype == self.TYPE_INT:
|
||||
print(" \"%s\": 0x%x, # %s" % (index, value, comment))
|
||||
elif totype == self.TYPE_ENUM:
|
||||
print(" \"%s\": %s, # %s" % (index, value, comment))
|
||||
else:
|
||||
print(" \"%s\": \"%s\", # %s" % (index, value, comment))
|
||||
|
||||
class PerlLanguageGenerator(LanguageSrcGenerator):
|
||||
|
||||
def _boilerplate(self, lines):
|
||||
print("#")
|
||||
for line in lines:
|
||||
print("# %s" % line)
|
||||
print("#")
|
||||
|
||||
def _array_start(self, varname, length, defvalue, fromtype, totype):
|
||||
if fromtype == self.TYPE_ENUN:
|
||||
raise NotImplementedError("Enums not supported as source in Python generator")
|
||||
if fromtype == self.TYPE_INT:
|
||||
print("my @%s = (" % varname)
|
||||
else:
|
||||
print("my %%%s = (" % varname)
|
||||
|
||||
def _array_end(self, fromtype, totype):
|
||||
print(");")
|
||||
|
||||
def _array_entry(self, index, value, comment, fromtype, totype):
|
||||
if fromtype == self.TYPE_INT:
|
||||
if value is None:
|
||||
print(" undef, # %s" % (comment))
|
||||
elif totype == self.TYPE_INT:
|
||||
print(" 0x%x, # %s" % (value, comment))
|
||||
elif totype == self.TYPE_ENUM:
|
||||
print(" %s, # %s" % (value, comment))
|
||||
else:
|
||||
print(" \"%s\", # %s" % (value, comment))
|
||||
else:
|
||||
if value is None:
|
||||
print(" \"%s\", undef, # %s" % (index, comment))
|
||||
elif totype == self.TYPE_INT:
|
||||
print(" \"%s\", 0x%x, # %s" % (index, value, comment))
|
||||
elif totype == self.TYPE_ENUM:
|
||||
print(" \"%s\", 0x%x, # %s" % (index, value, comment))
|
||||
else:
|
||||
print(" \"%s\", \"%s\", # %s" % (index, value, comment))
|
||||
|
||||
class JavaScriptLanguageGenerator(LanguageSrcGenerator):
|
||||
|
||||
def _boilerplate(self, lines):
|
||||
print("/*")
|
||||
for line in lines:
|
||||
print(" * %s" % line)
|
||||
print("*/")
|
||||
|
||||
def _array_start(self, varname, length, defvalue, fromtype, totype):
|
||||
print("export default {")
|
||||
|
||||
def _array_end(self, fromtype, totype):
|
||||
print("};")
|
||||
|
||||
def _array_entry(self, index, value, comment, fromtype, totype):
|
||||
if value is None:
|
||||
return
|
||||
|
||||
if fromtype == self.TYPE_INT:
|
||||
fromfmt = "0x%x"
|
||||
elif fromtype == self.TYPE_ENUM:
|
||||
fromfmt = "%s"
|
||||
else:
|
||||
fromfmt = "\"%s\""
|
||||
|
||||
if totype == self.TYPE_INT:
|
||||
tofmt = "0x%x"
|
||||
elif totype == self.TYPE_ENUM:
|
||||
tofmt = "%s"
|
||||
else:
|
||||
tofmt = "\"%s\""
|
||||
|
||||
print((" " + fromfmt + ": " + tofmt + ", /* %s */") % (index, value, comment))
|
||||
|
||||
class PodLanguageGenerator(LanguageDocGenerator):
|
||||
|
||||
def _boilerplate(self, lines):
|
||||
print("#")
|
||||
for line in lines:
|
||||
print("# %s" % line)
|
||||
print("#")
|
||||
|
||||
def _array_start_name_doc(self, varname, namemap):
|
||||
print("=head1 %s" % varname)
|
||||
print("")
|
||||
print("List of %s key code names, with corresponding key code values" % namemap)
|
||||
print("")
|
||||
print("=over 4")
|
||||
print("")
|
||||
|
||||
def _array_start_code_doc(self, varname, codemap, namemap):
|
||||
print("=head1 %s" % varname)
|
||||
print("")
|
||||
print("List of %s key code values, with corresponding %s key code names" % (codemap, namemap))
|
||||
print("")
|
||||
print("=over 4")
|
||||
print("")
|
||||
|
||||
def _array_end(self):
|
||||
print("=back")
|
||||
print("")
|
||||
|
||||
def _array_name_entry(self, value, name):
|
||||
print("=item %s" % name)
|
||||
print("")
|
||||
print("Key value %d (0x%x)" % (value, value))
|
||||
print("")
|
||||
|
||||
def _array_code_entry(self, value, name):
|
||||
print("=item %d (0x%x)" % (value, value))
|
||||
print("")
|
||||
print("Key name %s" % name)
|
||||
print("")
|
||||
|
||||
SRC_GENERATORS = {
|
||||
"stdc": StdCLanguageGenerator(),
|
||||
"stdc++": StdCppLanguageGenerator(),
|
||||
"glib2": GLib2LanguageGenerator(),
|
||||
"python2": PythonLanguageGenerator(),
|
||||
"python3": PythonLanguageGenerator(),
|
||||
"perl": PerlLanguageGenerator(),
|
||||
"js": JavaScriptLanguageGenerator(),
|
||||
}
|
||||
DOC_GENERATORS = {
|
||||
"pod": PodLanguageGenerator(),
|
||||
}
|
||||
|
||||
def code_map(args):
|
||||
database = Database()
|
||||
database.load(args.keymaps)
|
||||
|
||||
cliargs = ["keymap-gen", "--lang=%s" % args.lang]
|
||||
if args.varname is not None:
|
||||
cliargs.append("--varname=%s" % args.varname)
|
||||
cliargs.extend(["code-map", "keymaps.csv", args.frommapname, args.tomapname])
|
||||
SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
|
||||
|
||||
SRC_GENERATORS[args.lang].generate_code_map(args.varname, database, args.frommapname, args.tomapname)
|
||||
|
||||
def code_table(args):
|
||||
database = Database()
|
||||
database.load(args.keymaps)
|
||||
|
||||
cliargs = ["keymap-gen", "--lang=%s" % args.lang]
|
||||
if args.varname is not None:
|
||||
cliargs.append("--varname=%s" % args.varname)
|
||||
cliargs.extend(["code-table", "keymaps.csv", args.mapname])
|
||||
SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
|
||||
|
||||
SRC_GENERATORS[args.lang].generate_code_table(args.varname, database, args.mapname)
|
||||
|
||||
def name_map(args):
|
||||
database = Database()
|
||||
database.load(args.keymaps)
|
||||
|
||||
cliargs = ["keymap-gen", "--lang=%s" % args.lang]
|
||||
if args.varname is not None:
|
||||
cliargs.append("--varname=%s" % args.varname)
|
||||
cliargs.extend(["name-map", "keymaps.csv", args.frommapname, args.tomapname])
|
||||
SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
|
||||
|
||||
SRC_GENERATORS[args.lang].generate_name_map(args.varname, database, args.frommapname, args.tomapname)
|
||||
|
||||
def name_table(args):
|
||||
database = Database()
|
||||
database.load(args.keymaps)
|
||||
|
||||
|
||||
cliargs = ["keymap-gen", "--lang=%s" % args.lang]
|
||||
if args.varname is not None:
|
||||
cliargs.append("--varname=%s" % args.varname)
|
||||
cliargs.extend(["name-table", "keymaps.csv", args.mapname])
|
||||
SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
|
||||
|
||||
SRC_GENERATORS[args.lang].generate_name_table(args.varname, database, args.mapname)
|
||||
|
||||
def code_docs(args):
|
||||
database = Database()
|
||||
database.load(args.keymaps)
|
||||
|
||||
|
||||
cliargs = ["keymap-gen", "--lang=%s" % args.lang]
|
||||
if args.varname is not None:
|
||||
cliargs.append("--varname=%s" % args.varname)
|
||||
cliargs.extend(["code-docs", "keymaps.csv", args.mapname])
|
||||
DOC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
|
||||
|
||||
DOC_GENERATORS[args.lang].generate_code_docs(args.varname, database, args.mapname)
|
||||
|
||||
def name_docs(args):
|
||||
database = Database()
|
||||
database.load(args.keymaps)
|
||||
|
||||
|
||||
cliargs = ["keymap-gen", "--lang=%s" % args.lang]
|
||||
if args.varname is not None:
|
||||
cliargs.append("--varname=%s" % args.varname)
|
||||
cliargs.extend(["name-docs", "keymaps.csv", args.mapname])
|
||||
DOC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
|
||||
|
||||
DOC_GENERATORS[args.lang].generate_name_docs(args.varname, database, args.mapname)
|
||||
|
||||
def usage():
|
||||
print ("Please select a command:")
|
||||
print (" 'code-map', 'code-table', 'name-map', 'name-table', 'docs'")
|
||||
sys.exit(1)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument("--lang", default="stdc",
|
||||
help="Output language, (src=%s, doc=%s)" % (
|
||||
",".join(SRC_GENERATORS.keys()),
|
||||
",".join(DOC_GENERATORS.keys())))
|
||||
parser.add_argument("--varname", default=None,
|
||||
help="Data variable name")
|
||||
|
||||
subparsers = parser.add_subparsers(help="sub-command help")
|
||||
|
||||
codemapparser = subparsers.add_parser("code-map", help="Generate a mapping between code tables")
|
||||
codemapparser.add_argument("keymaps", help="Path to keymap CSV data file")
|
||||
codemapparser.add_argument("frommapname", help="Source code table name")
|
||||
codemapparser.add_argument("tomapname", help="Target code table name")
|
||||
codemapparser.set_defaults(func=code_map)
|
||||
|
||||
codetableparser = subparsers.add_parser("code-table", help="Generate a flat code table")
|
||||
codetableparser.add_argument("keymaps", help="Path to keymap CSV data file")
|
||||
codetableparser.add_argument("mapname", help="Code table name")
|
||||
codetableparser.set_defaults(func=code_table)
|
||||
|
||||
namemapparser = subparsers.add_parser("name-map", help="Generate a mapping to names")
|
||||
namemapparser.add_argument("keymaps", help="Path to keymap CSV data file")
|
||||
namemapparser.add_argument("frommapname", help="Source code table name")
|
||||
namemapparser.add_argument("tomapname", help="Target name table name")
|
||||
namemapparser.set_defaults(func=name_map)
|
||||
|
||||
nametableparser = subparsers.add_parser("name-table", help="Generate a flat name table")
|
||||
nametableparser.add_argument("keymaps", help="Path to keymap CSV data file")
|
||||
nametableparser.add_argument("mapname", help="Name table name")
|
||||
nametableparser.set_defaults(func=name_table)
|
||||
|
||||
codedocsparser = subparsers.add_parser("code-docs", help="Generate code documentation")
|
||||
codedocsparser.add_argument("keymaps", help="Path to keymap CSV data file")
|
||||
codedocsparser.add_argument("mapname", help="Code table name")
|
||||
codedocsparser.set_defaults(func=code_docs)
|
||||
|
||||
namedocsparser = subparsers.add_parser("name-docs", help="Generate name documentation")
|
||||
namedocsparser.add_argument("keymaps", help="Path to keymap CSV data file")
|
||||
namedocsparser.add_argument("mapname", help="Name table name")
|
||||
namedocsparser.set_defaults(func=name_docs)
|
||||
|
||||
args = parser.parse_args()
|
||||
if hasattr(args, "func"):
|
||||
args.func(args)
|
||||
else:
|
||||
usage()
|
||||
|
||||
|
||||
main()
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user