diff options
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | block/qapi.c | 8 | ||||
-rw-r--r-- | block/raw-posix.c | 15 | ||||
-rwxr-xr-x | configure | 17 | ||||
-rw-r--r-- | hw/block/nand.c | 2 | ||||
-rw-r--r-- | hw/block/xen_disk.c | 8 | ||||
-rw-r--r-- | hw/ide/atapi.c | 8 | ||||
-rw-r--r-- | hw/misc/ivshmem.c | 9 | ||||
-rw-r--r-- | hw/xenpv/xen_domainbuild.c | 2 | ||||
-rw-r--r-- | include/hw/xen/xen_common.h | 16 | ||||
-rw-r--r-- | migration/block.c | 7 | ||||
-rw-r--r-- | migration/postcopy-ram.c | 10 | ||||
-rw-r--r-- | qemu-doc.texi | 10 | ||||
-rw-r--r-- | qga/commands-posix.c | 56 | ||||
-rw-r--r-- | qga/commands-win32.c | 20 | ||||
-rw-r--r-- | qga/guest-agent-core.h | 7 | ||||
-rw-r--r-- | qga/installer/qemu-ga.wxs | 18 | ||||
-rw-r--r-- | qga/qapi-schema.json | 4 | ||||
-rw-r--r-- | tests/Makefile | 3 | ||||
-rw-r--r-- | tests/ide-test.c | 32 | ||||
-rw-r--r-- | tests/ivshmem-test.c | 3 | ||||
-rwxr-xr-x | tests/qemu-iotests/119 | 2 | ||||
-rwxr-xr-x | tests/qemu-iotests/120 | 2 | ||||
-rw-r--r-- | tests/test-aio.c | 1 | ||||
-rw-r--r-- | tests/test-qga.c | 98 | ||||
-rw-r--r-- | ui/vnc.c | 5 |
26 files changed, 300 insertions, 68 deletions
@@ -440,10 +440,7 @@ endif install: all $(if $(BUILD_DOCS),install-doc) \ install-datadir install-localstatedir ifneq ($(TOOLS),) - $(call install-prog,$(filter-out qemu-ga,$(TOOLS)),$(DESTDIR)$(bindir)) -ifneq (,$(findstring qemu-ga,$(TOOLS))) - $(call install-prog,qemu-ga$(EXESUF),$(DESTDIR)$(bindir)) -endif + $(call install-prog,$(subst qemu-ga,qemu-ga$(EXESUF),$(TOOLS)),$(DESTDIR)$(bindir)) endif ifneq ($(CONFIG_MODULES),) $(INSTALL_DIR) "$(DESTDIR)$(qemu_moddir)" diff --git a/block/qapi.c b/block/qapi.c index d20262decb..267f147fe3 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -436,7 +436,9 @@ BlockInfoList *qmp_query_block(Error **errp) bdrv_query_info(blk, &info->value, &local_err); if (local_err) { error_propagate(errp, local_err); - goto err; + g_free(info); + qapi_free_BlockInfoList(head); + return NULL; } *p_next = info; @@ -444,10 +446,6 @@ BlockInfoList *qmp_query_block(Error **errp) } return head; - - err: - qapi_free_BlockInfoList(head); - return NULL; } BlockStatsList *qmp_query_blockstats(bool has_query_nodes, diff --git a/block/raw-posix.c b/block/raw-posix.c index aec9ec6bbb..d9162fd306 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -1976,8 +1976,8 @@ BlockDriver bdrv_file = { #if defined(__APPLE__) && defined(__MACH__) static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ); -static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ); - +static kern_return_t GetBSDPath(io_iterator_t mediaIterator, char *bsdPath, + CFIndex maxPathSize, int flags); kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ) { kern_return_t kernResult; @@ -2004,7 +2004,8 @@ kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ) return kernResult; } -kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ) +kern_return_t GetBSDPath(io_iterator_t mediaIterator, char *bsdPath, + CFIndex maxPathSize, int flags) { io_object_t nextMedia; kern_return_t kernResult = KERN_FAILURE; @@ -2017,7 +2018,9 @@ kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex ma if ( bsdPathAsCFString ) { size_t devPathLength; strcpy( bsdPath, _PATH_DEV ); - strcat( bsdPath, "r" ); + if (flags & BDRV_O_NOCACHE) { + strcat(bsdPath, "r"); + } devPathLength = strlen( bsdPath ); if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) { kernResult = KERN_SUCCESS; @@ -2129,8 +2132,8 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags, int fd; kernResult = FindEjectableCDMedia( &mediaIterator ); - kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) ); - + kernResult = GetBSDPath(mediaIterator, bsdPath, sizeof(bsdPath), + flags); if ( bsdPath[ 0 ] != '\0' ) { strcat(bsdPath,"s0"); /* some CDs don't have a partition 0 */ @@ -1946,6 +1946,23 @@ EOF elif cat > $TMPC <<EOF && #include <xenctrl.h> +#include <stdint.h> +int main(void) { + xc_interface *xc = NULL; + xen_domain_handle_t handle; + xc_domain_create(xc, 0, handle, 0, NULL, NULL); + return 0; +} +EOF + compile_prog "" "$xen_libs" + then + xen_ctrl_version=470 + xen=yes + + # Xen 4.6 + elif + cat > $TMPC <<EOF && +#include <xenctrl.h> #include <xenstore.h> #include <stdint.h> #include <xen/hvm/hvm_info_table.h> diff --git a/hw/block/nand.c b/hw/block/nand.c index a68266f887..f0e34139fe 100644 --- a/hw/block/nand.c +++ b/hw/block/nand.c @@ -712,7 +712,7 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s) memset(s->storage + (PAGE(addr) << OOB_SHIFT), 0xff, OOB_SIZE << s->erase_shift); i = SECTOR(addr); - page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift)); + page = SECTOR(addr + (1 << (ADDR_SHIFT + s->erase_shift))); for (; i < page; i ++) if (blk_write(s->blk, i, iobuf, 1) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, i); diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c index 02eda6efbc..814665034d 100644 --- a/hw/block/xen_disk.c +++ b/hw/block/xen_disk.c @@ -75,7 +75,6 @@ struct ioreq { off_t start; QEMUIOVector v; int presync; - int postsync; uint8_t mapped; /* grant mapping */ @@ -144,7 +143,6 @@ static void ioreq_reset(struct ioreq *ioreq) ioreq->status = 0; ioreq->start = 0; ioreq->presync = 0; - ioreq->postsync = 0; ioreq->mapped = 0; memset(ioreq->domids, 0, sizeof(ioreq->domids)); @@ -520,12 +518,6 @@ static void qemu_aio_complete(void *opaque, int ret) if (ioreq->aio_inflight > 0) { return; } - if (ioreq->postsync) { - ioreq->postsync = 0; - ioreq->aio_inflight++; - blk_aio_flush(ioreq->blkdev->blk, qemu_aio_complete, ioreq); - return; - } ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY; ioreq_unmap(ioreq); diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index 7b9f74c3b5..65f8dd457b 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -148,17 +148,18 @@ static void cd_read_sector_cb(void *opaque, int ret) { IDEState *s = opaque; - block_acct_done(blk_get_stats(s->blk), &s->acct); - #ifdef DEBUG_IDE_ATAPI printf("cd_read_sector_cb: lba=%d ret=%d\n", s->lba, ret); #endif if (ret < 0) { + block_acct_failed(blk_get_stats(s->blk), &s->acct); ide_atapi_io_error(s, ret); return; } + block_acct_done(blk_get_stats(s->blk), &s->acct); + if (s->cd_sector_size == 2352) { cd_data_to_raw(s->io_buffer, s->lba); } @@ -173,6 +174,7 @@ static void cd_read_sector_cb(void *opaque, int ret) static int cd_read_sector(IDEState *s) { if (s->cd_sector_size != 2048 && s->cd_sector_size != 2352) { + block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_READ); return -EINVAL; } @@ -441,7 +443,7 @@ eot: if (ret < 0) { block_acct_failed(blk_get_stats(s->blk), &s->acct); } else { - block_acct_done(blk_get_stats(s->blk), &s->acct); + block_acct_done(blk_get_stats(s->blk), &s->acct); } ide_set_inactive(s, false); } diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 83d7bd3e5f..f73f0c2b17 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -60,8 +60,6 @@ #define IVSHMEM(obj) \ OBJECT_CHECK(IVShmemState, (obj), TYPE_IVSHMEM) -#define IVSHMEM_MEMDEV_PROP "memdev" - typedef struct Peer { int nb_eventfds; EventNotifier *eventfds; @@ -857,8 +855,8 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp) PCI_BASE_ADDRESS_MEM_PREFETCH; if (!!s->server_chr + !!s->shmobj + !!s->hostmem != 1) { - error_setg(errp, "You must specify either a shmobj, a chardev" - " or a hostmem"); + error_setg(errp, + "You must specify either 'shm', 'chardev' or 'x-memdev'"); return; } @@ -939,6 +937,7 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp) memory_region_add_subregion(&s->bar, 0, mr); pci_register_bar(PCI_DEVICE(s), 2, attr, &s->bar); } else if (s->server_chr != NULL) { + /* FIXME do not rely on what chr drivers put into filename */ if (strncmp(s->server_chr->filename, "unix:", 5)) { error_setg(errp, "chardev is not a unix client socket"); return; @@ -1181,7 +1180,7 @@ static void ivshmem_init(Object *obj) { IVShmemState *s = IVSHMEM(obj); - object_property_add_link(obj, IVSHMEM_MEMDEV_PROP, TYPE_MEMORY_BACKEND, + object_property_add_link(obj, "x-memdev", TYPE_MEMORY_BACKEND, (Object **)&s->hostmem, ivshmem_check_memdev_is_busy, OBJ_PROP_LINK_UNREF_ON_RELEASE, diff --git a/hw/xenpv/xen_domainbuild.c b/hw/xenpv/xen_domainbuild.c index c0ab7537df..ac0e5ac9f0 100644 --- a/hw/xenpv/xen_domainbuild.c +++ b/hw/xenpv/xen_domainbuild.c @@ -234,7 +234,7 @@ int xen_domain_build_pv(const char *kernel, const char *ramdisk, int rc; memcpy(uuid, qemu_uuid, sizeof(uuid)); - rc = xc_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid); + rc = xen_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid); if (rc < 0) { fprintf(stderr, "xen: xc_domain_create() failed\n"); goto err; diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h index d7fa6a4d01..4ac0c6f443 100644 --- a/include/hw/xen/xen_common.h +++ b/include/hw/xen/xen_common.h @@ -439,4 +439,20 @@ static inline int xen_xc_domain_add_to_physmap(XenXC xch, uint32_t domid, } #endif +#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 470 +static inline int xen_domain_create(XenXC xc, uint32_t ssidref, + xen_domain_handle_t handle, uint32_t flags, + uint32_t *pdomid) +{ + return xc_domain_create(xc, ssidref, handle, flags, pdomid); +} +#else +static inline int xen_domain_create(XenXC xc, uint32_t ssidref, + xen_domain_handle_t handle, uint32_t flags, + uint32_t *pdomid) +{ + return xc_domain_create(xc, ssidref, handle, flags, pdomid, NULL); +} +#endif + #endif /* QEMU_HW_XEN_COMMON_H */ diff --git a/migration/block.c b/migration/block.c index 310e2b36dc..656f38f341 100644 --- a/migration/block.c +++ b/migration/block.c @@ -36,6 +36,8 @@ #define MAX_IS_ALLOCATED_SEARCH 65536 +#define MAX_INFLIGHT_IO 512 + //#define DEBUG_BLK_MIGRATION #ifdef DEBUG_BLK_MIGRATION @@ -665,7 +667,10 @@ static int block_save_iterate(QEMUFile *f, void *opaque) blk_mig_lock(); while ((block_mig_state.submitted + block_mig_state.read_done) * BLOCK_SIZE < - qemu_file_get_rate_limit(f)) { + qemu_file_get_rate_limit(f) && + (block_mig_state.submitted + + block_mig_state.read_done) < + MAX_INFLIGHT_IO) { blk_mig_unlock(); if (block_mig_state.bulk_completed == 0) { /* first finish the bulk phase */ diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 22d6b18e63..3946aa98aa 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -241,10 +241,7 @@ static int cleanup_range(const char *block_name, void *host_addr, * We turned off hugepage for the precopy stage with postcopy enabled * we can turn it back on now. */ - if (qemu_madvise(host_addr, length, QEMU_MADV_HUGEPAGE)) { - error_report("%s HUGEPAGE: %s", __func__, strerror(errno)); - return -1; - } + qemu_madvise(host_addr, length, QEMU_MADV_HUGEPAGE); /* * We can also turn off userfault now since we should have all the @@ -345,10 +342,7 @@ static int nhp_range(const char *block_name, void *host_addr, * do delete areas of the page, even if THP thinks a hugepage would * be a good idea, so force hugepages off. */ - if (qemu_madvise(host_addr, length, QEMU_MADV_NOHUGEPAGE)) { - error_report("%s: NOHUGEPAGE: %s", __func__, strerror(errno)); - return -1; - } + qemu_madvise(host_addr, length, QEMU_MADV_NOHUGEPAGE); return 0; } diff --git a/qemu-doc.texi b/qemu-doc.texi index 460ab716ac..ffc3e50abb 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1256,7 +1256,7 @@ zero-copy communication to the application level of the guests. The basic syntax is: @example -qemu-system-i386 -device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>] +qemu-system-i386 -device ivshmem,size=@var{size},shm=@var{shm-name} @end example If desired, interrupts can be sent between guest VMs accessing the same shared @@ -1267,12 +1267,12 @@ memory server is: @example # First start the ivshmem server once and for all -ivshmem-server -p <pidfile> -S <path> -m <shm name> -l <shm size> -n <vectors n> +ivshmem-server -p @var{pidfile} -S @var{path} -m @var{shm-name} -l @var{shm-size} -n @var{vectors} # Then start your qemu instances with matching arguments -qemu-system-i386 -device ivshmem,size=<shm size>,vectors=<vectors n>,chardev=<id> +qemu-system-i386 -device ivshmem,size=@var{shm-size},vectors=@var{vectors},chardev=@var{id} [,msi=on][,ioeventfd=on][,role=peer|master] - -chardev socket,path=<path>,id=<id> + -chardev socket,path=@var{path},id=@var{id} @end example When using the server, the guest will be assigned a VM ID (>=0) that allows guests @@ -1300,7 +1300,7 @@ a memory backend that has hugepage support: @example qemu-system-i386 -object memory-backend-file,size=1G,mem-path=/mnt/hugepages/my-shmem-file,id=mb1 - -device ivshmem,memdev=mb1 + -device ivshmem,x-memdev=mb1 @end example ivshmem-server also supports hugepages mount points with the diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 0ebd47336a..c2ff97021f 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -216,9 +216,16 @@ void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp) } } +typedef enum { + RW_STATE_NEW, + RW_STATE_READING, + RW_STATE_WRITING, +} RwState; + typedef struct GuestFileHandle { uint64_t id; FILE *fh; + RwState state; QTAILQ_ENTRY(GuestFileHandle) next; } GuestFileHandle; @@ -460,6 +467,17 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, } fh = gfh->fh; + + /* explicitly flush when switching from writing to reading */ + if (gfh->state == RW_STATE_WRITING) { + int ret = fflush(fh); + if (ret == EOF) { + error_setg_errno(errp, errno, "failed to flush file"); + return NULL; + } + gfh->state = RW_STATE_NEW; + } + buf = g_malloc0(count+1); read_count = fread(buf, 1, count, fh); if (ferror(fh)) { @@ -473,6 +491,7 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, if (read_count) { read_data->buf_b64 = g_base64_encode(buf, read_count); } + gfh->state = RW_STATE_READING; } g_free(buf); clearerr(fh); @@ -496,6 +515,16 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, } fh = gfh->fh; + + if (gfh->state == RW_STATE_READING) { + int ret = fseek(fh, 0, SEEK_CUR); + if (ret == -1) { + error_setg_errno(errp, errno, "failed to seek file"); + return NULL; + } + gfh->state = RW_STATE_NEW; + } + buf = g_base64_decode(buf_b64, &buf_len); if (!has_count) { @@ -515,6 +544,7 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, write_data = g_new0(GuestFileWrite, 1); write_data->count = write_count; write_data->eof = feof(fh); + gfh->state = RW_STATE_WRITING; } g_free(buf); clearerr(fh); @@ -523,25 +553,47 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, } struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, - int64_t whence, Error **errp) + int64_t whence_code, Error **errp) { GuestFileHandle *gfh = guest_file_handle_find(handle, errp); GuestFileSeek *seek_data = NULL; FILE *fh; int ret; + int whence; if (!gfh) { return NULL; } + /* We stupidly exposed 'whence':'int' in our qapi */ + switch (whence_code) { + case QGA_SEEK_SET: + whence = SEEK_SET; + break; + case QGA_SEEK_CUR: + whence = SEEK_CUR; + break; + case QGA_SEEK_END: + whence = SEEK_END; + break; + default: + error_setg(errp, "invalid whence code %"PRId64, whence_code); + return NULL; + } + fh = gfh->fh; ret = fseek(fh, offset, whence); if (ret == -1) { error_setg_errno(errp, errno, "failed to seek file"); + if (errno == ESPIPE) { + /* file is non-seekable, stdio shouldn't be buffering anyways */ + gfh->state = RW_STATE_NEW; + } } else { seek_data = g_new0(GuestFileSeek, 1); seek_data->position = ftell(fh); seek_data->eof = feof(fh); + gfh->state = RW_STATE_NEW; } clearerr(fh); @@ -562,6 +614,8 @@ void qmp_guest_file_flush(int64_t handle, Error **errp) ret = fflush(fh); if (ret == EOF) { error_setg_errno(errp, errno, "failed to flush file"); + } else { + gfh->state = RW_STATE_NEW; } } diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 41f6dd9fed..0654fe4fe7 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -382,7 +382,7 @@ done: } GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, - int64_t whence, Error **errp) + int64_t whence_code, Error **errp) { GuestFileHandle *gfh; GuestFileSeek *seek_data; @@ -390,11 +390,29 @@ GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, LARGE_INTEGER new_pos, off_pos; off_pos.QuadPart = offset; BOOL res; + int whence; + gfh = guest_file_handle_find(handle, errp); if (!gfh) { return NULL; } + /* We stupidly exposed 'whence':'int' in our qapi */ + switch (whence_code) { + case QGA_SEEK_SET: + whence = SEEK_SET; + break; + case QGA_SEEK_CUR: + whence = SEEK_CUR; + break; + case QGA_SEEK_END: + whence = SEEK_END; + break; + default: + error_setg(errp, "invalid whence code %"PRId64, whence_code); + return NULL; + } + fh = gfh->fh; res = SetFilePointerEx(fh, off_pos, &new_pos, whence); if (!res) { diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h index e92c6abafb..238dc6b08d 100644 --- a/qga/guest-agent-core.h +++ b/qga/guest-agent-core.h @@ -15,6 +15,13 @@ #define QGA_READ_COUNT_DEFAULT 4096 +/* Mapping of whence codes used by guest-file-seek. */ +enum { + QGA_SEEK_SET = 0, + QGA_SEEK_CUR = 1, + QGA_SEEK_END = 2, +}; + typedef struct GAState GAState; typedef struct GACommandState GACommandState; extern GAState *ga_state; diff --git a/qga/installer/qemu-ga.wxs b/qga/installer/qemu-ga.wxs index 6804f0279f..9473875723 100644 --- a/qga/installer/qemu-ga.wxs +++ b/qga/installer/qemu-ga.wxs @@ -91,6 +91,22 @@ <File Id="qga_vss.tlb" Name="qga-vss.tlb" Source="$(env.BUILD_DIR)/qga/vss-win32/qga-vss.tlb" KeyPath="yes" DiskId="1"/> </Component> <?endif?> + <?if $(var.Arch) = "32"?> + <Component Id="gspawn-helper-console" Guid="{446185B3-87BE-43D2-96B8-0FEFD9E8696D}"> + <File Id="gspawn-win32-helper-console.exe" Name="gspawn-win32-helper-console.exe" Source="$(var.Mingw_bin)/gspawn-win32-helper-console.exe" KeyPath="yes" DiskId="1"/> + </Component> + <Component Id="gspawn-helper" Guid="{CD67A5A3-2DB1-4DA1-A67A-8D71E797B466}"> + <File Id="gspawn-win32-helper.exe" Name="gspawn-win32-helper.exe" Source="$(var.Mingw_bin)/gspawn-win32-helper.exe" KeyPath="yes" DiskId="1"/> + </Component> + <?endif?> + <?if $(var.Arch) = "64"?> + <Component Id="gspawn-helper-console" Guid="{9E615A9F-349A-4992-A5C2-C10BAD173660}"> + <File Id="gspawn-win64-helper-console.exe" Name="gspawn-win64-helper-console.exe" Source="$(var.Mingw_bin)/gspawn-win64-helper-console.exe" KeyPath="yes" DiskId="1"/> + </Component> + <Component Id="gspawn-helper" Guid="{D201AD22-1846-4E4F-B6E1-C7A908ED2457}"> + <File Id="gspawn-win64-helper.exe" Name="gspawn-win64-helper.exe" Source="$(var.Mingw_bin)/gspawn-win64-helper.exe" KeyPath="yes" DiskId="1"/> + </Component> + <?endif?> <Component Id="iconv" Guid="{35EE3558-D34B-4F0A-B8BD-430FF0775246}"> <File Id="iconv.dll" Name="iconv.dll" Source="$(var.Mingw_bin)/iconv.dll" KeyPath="yes" DiskId="1"/> </Component> @@ -148,6 +164,8 @@ <ComponentRef Id="qga_vss_dll" /> <ComponentRef Id="qga_vss_tlb" /> <?endif?> + <ComponentRef Id="gspawn-helper-console" /> + <ComponentRef Id="gspawn-helper" /> <ComponentRef Id="iconv" /> <ComponentRef Id="libgcc_arch_lib" /> <ComponentRef Id="libglib" /> diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index 78362e071d..01c9ee48d8 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -318,13 +318,13 @@ # # Seek to a position in the file, as with fseek(), and return the # current file position afterward. Also encapsulates ftell()'s -# functionality, just Set offset=0, whence=SEEK_CUR. +# functionality, with offset=0 and whence=1. # # @handle: filehandle returned by guest-file-open # # @offset: bytes to skip over in the file stream # -# @whence: SEEK_SET, SEEK_CUR, or SEEK_END, as with fseek() +# @whence: 0 for SEEK_SET, 1 for SEEK_CUR, or 2 for SEEK_END # # Returns: @GuestFileSeek on success. # diff --git a/tests/Makefile b/tests/Makefile index b9379841d8..0ef00a1111 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -415,8 +415,7 @@ tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ migration/qemu-file-unix.o qjson.o \ $(test-qom-obj-y) tests/test-timed-average$(EXESUF): tests/test-timed-average.o qemu-timer.o \ - libqemuutil.a stubs/clock-warp.o stubs/cpu-get-icount.o \ - stubs/notify-event.o stubs/replay.o + $(test-util-obj-y) tests/test-qapi-types.c tests/test-qapi-types.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) diff --git a/tests/ide-test.c b/tests/ide-test.c index fc1ce52f58..c3aacd2a0f 100644 --- a/tests/ide-test.c +++ b/tests/ide-test.c @@ -642,15 +642,19 @@ static void nsleep(int64_t nsecs) static uint8_t ide_wait_clear(uint8_t flag) { - int i; uint8_t data; + time_t st; /* Wait with a 5 second timeout */ - for (i = 0; i <= 12500000; i++) { + time(&st); + while (true) { data = inb(IDE_BASE + reg_status); if (!(data & flag)) { return data; } + if (difftime(time(NULL), st) > 5.0) { + break; + } nsleep(400); } g_assert_not_reached(); @@ -658,14 +662,18 @@ static uint8_t ide_wait_clear(uint8_t flag) static void ide_wait_intr(int irq) { - int i; + time_t st; bool intr; - for (i = 0; i <= 12500000; i++) { + time(&st); + while (true) { intr = get_irq(irq); if (intr) { return; } + if (difftime(time(NULL), st) > 5.0) { + break; + } nsleep(400); } @@ -709,9 +717,6 @@ static void cdrom_pio_impl(int nblocks) /* SCSI CDB (READ10) -- read n*2048 bytes from block 0 */ send_scsi_cdb_read10(0, nblocks); - /* HP3: INTRQ_Wait */ - ide_wait_intr(IDE_PRIMARY_IRQ); - /* Read data back: occurs in bursts of 'BYTE_COUNT_LIMIT' bytes. * If BYTE_COUNT_LIMIT is odd, we transfer BYTE_COUNT_LIMIT - 1 bytes. * We allow an odd limit only when the remaining transfer size is @@ -723,16 +728,25 @@ static void cdrom_pio_impl(int nblocks) for (i = 0; i < DIV_ROUND_UP(rxsize, limit); i++) { size_t offset = i * (limit / 2); size_t rem = (rxsize / 2) - offset; - /* HP2: Check_Status_B */ + + /* HP3: INTRQ_Wait */ + ide_wait_intr(IDE_PRIMARY_IRQ); + + /* HP2: Check_Status_B (and clear IRQ) */ data = ide_wait_clear(BSY); assert_bit_set(data, DRQ | DRDY); assert_bit_clear(data, ERR | DF | BSY); + /* HP4: Transfer_Data */ for (j = 0; j < MIN((limit / 2), rem); j++) { rx[offset + j] = le16_to_cpu(inw(IDE_BASE + reg_data)); } - ide_wait_intr(IDE_PRIMARY_IRQ); } + + /* Check for final completion IRQ */ + ide_wait_intr(IDE_PRIMARY_IRQ); + + /* Sanity check final state */ data = ide_wait_clear(DRQ); assert_bit_set(data, DRDY); assert_bit_clear(data, DRQ | ERR | DF | BSY); diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c index f1793ba6fb..03c7b962a3 100644 --- a/tests/ivshmem-test.c +++ b/tests/ivshmem-test.c @@ -40,6 +40,7 @@ static QPCIDevice *get_device(void) QPCIBus *pcibus; pcibus = qpci_init_pc(); + dev = NULL; qpci_device_foreach(pcibus, 0x1af4, 0x1110, save_fn, &dev); g_assert(dev != NULL); @@ -392,7 +393,7 @@ static void test_ivshmem_memdev(void) /* just for the sake of checking memory-backend property */ setup_vm_cmd(&state, "-object memory-backend-ram,size=1M,id=mb1" - " -device ivshmem,memdev=mb1", false); + " -device ivshmem,x-memdev=mb1", false); qtest_quit(state.qtest); } diff --git a/tests/qemu-iotests/119 b/tests/qemu-iotests/119 index 9a11f1b921..cc6ec07705 100755 --- a/tests/qemu-iotests/119 +++ b/tests/qemu-iotests/119 @@ -49,7 +49,7 @@ echo "{'execute': 'qmp_capabilities'} {'execute': 'human-monitor-command', 'arguments': {'command-line': 'qemu-io drv \"read -P 0 0 64k\"'}} {'execute': 'quit'}" \ - | $QEMU -drive id=drv,if=none,file="$TEST_IMG",driver=nbd \ + | $QEMU -nographic -drive id=drv,if=none,file="$TEST_IMG",driver=nbd \ -qmp stdio -nodefaults \ | _filter_qmp | _filter_qemu_io diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120 index 9f13078764..d899a3f527 100755 --- a/tests/qemu-iotests/120 +++ b/tests/qemu-iotests/120 @@ -49,7 +49,7 @@ echo "{'execute': 'qmp_capabilities'} {'execute': 'human-monitor-command', 'arguments': {'command-line': 'qemu-io drv \"write -P 42 0 64k\"'}} {'execute': 'quit'}" \ - | $QEMU -qmp stdio -nodefaults \ + | $QEMU -qmp stdio -nographic -nodefaults \ -drive id=drv,if=none,file="$TEST_IMG",driver=raw,file.driver=$IMGFMT \ | _filter_qmp | _filter_qemu_io $QEMU_IO -c 'read -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io diff --git a/tests/test-aio.c b/tests/test-aio.c index 1623803e8c..e188d8c13d 100644 --- a/tests/test-aio.c +++ b/tests/test-aio.c @@ -393,6 +393,7 @@ static void test_aio_external_client(void) aio_enable_external(ctx); } assert(aio_poll(ctx, false)); + set_event_notifier(ctx, &data.e, NULL); event_notifier_cleanup(&data.e); } } diff --git a/tests/test-qga.c b/tests/test-qga.c index 64738465c5..e6a84d17f0 100644 --- a/tests/test-qga.c +++ b/tests/test-qga.c @@ -13,6 +13,7 @@ #include "libqtest.h" #include "config-host.h" +#include "qga/guest-agent-core.h" typedef struct { char *test_dir; @@ -352,10 +353,10 @@ static void test_qga_network_get_interfaces(gconstpointer fix) static void test_qga_file_ops(gconstpointer fix) { const TestFixture *fixture = fix; - const guchar helloworld[] = "Hello World!\n"; + const unsigned char helloworld[] = "Hello World!\n"; const char *b64; gchar *cmd, *path, *enc; - guchar *dec; + unsigned char *dec; QDict *ret, *val; int64_t id, eof; gsize count; @@ -457,7 +458,7 @@ static void test_qga_file_ops(gconstpointer fix) cmd = g_strdup_printf("{'execute': 'guest-file-seek'," " 'arguments': { 'handle': %" PRId64 ", " " 'offset': %d, 'whence': %d } }", - id, 6, SEEK_SET); + id, 6, QGA_SEEK_SET); ret = qmp_fd(fixture->fd, cmd); qmp_assert_no_error(ret); val = qdict_get_qdict(ret, "return"); @@ -496,6 +497,96 @@ static void test_qga_file_ops(gconstpointer fix) g_free(cmd); } +static void test_qga_file_write_read(gconstpointer fix) +{ + const TestFixture *fixture = fix; + const unsigned char helloworld[] = "Hello World!\n"; + const char *b64; + gchar *cmd, *enc; + QDict *ret, *val; + int64_t id, eof; + gsize count; + + /* open */ + ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open'," + " 'arguments': { 'path': 'foo', 'mode': 'w+' } }"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + id = qdict_get_int(ret, "return"); + QDECREF(ret); + + enc = g_base64_encode(helloworld, sizeof(helloworld)); + /* write */ + cmd = g_strdup_printf("{'execute': 'guest-file-write'," + " 'arguments': { 'handle': %" PRId64 "," + " 'buf-b64': '%s' } }", id, enc); + ret = qmp_fd(fixture->fd, cmd); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "count"); + eof = qdict_get_bool(val, "eof"); + g_assert_cmpint(count, ==, sizeof(helloworld)); + g_assert_cmpint(eof, ==, 0); + QDECREF(ret); + g_free(cmd); + + /* read (check implicit flush) */ + cmd = g_strdup_printf("{'execute': 'guest-file-read'," + " 'arguments': { 'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "count"); + eof = qdict_get_bool(val, "eof"); + b64 = qdict_get_str(val, "buf-b64"); + g_assert_cmpint(count, ==, 0); + g_assert(eof); + g_assert_cmpstr(b64, ==, ""); + QDECREF(ret); + g_free(cmd); + + /* seek to 0 */ + cmd = g_strdup_printf("{'execute': 'guest-file-seek'," + " 'arguments': { 'handle': %" PRId64 ", " + " 'offset': %d, 'whence': %d } }", + id, 0, QGA_SEEK_SET); + ret = qmp_fd(fixture->fd, cmd); + qmp_assert_no_error(ret); + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "position"); + eof = qdict_get_bool(val, "eof"); + g_assert_cmpint(count, ==, 0); + g_assert(!eof); + QDECREF(ret); + g_free(cmd); + + /* read */ + cmd = g_strdup_printf("{'execute': 'guest-file-read'," + " 'arguments': { 'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "count"); + eof = qdict_get_bool(val, "eof"); + b64 = qdict_get_str(val, "buf-b64"); + g_assert_cmpint(count, ==, sizeof(helloworld)); + g_assert(eof); + g_assert_cmpstr(b64, ==, enc); + QDECREF(ret); + g_free(cmd); + g_free(enc); + + /* close */ + cmd = g_strdup_printf("{'execute': 'guest-file-close'," + " 'arguments': {'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + QDECREF(ret); + g_free(cmd); +} + static void test_qga_get_time(gconstpointer fix) { const TestFixture *fixture = fix; @@ -762,6 +853,7 @@ int main(int argc, char **argv) g_test_add_data_func("/qga/get-memory-blocks", &fix, test_qga_get_memory_blocks); g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops); + g_test_add_data_func("/qga/file-write-read", &fix, test_qga_file_write_read); g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time); g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd); g_test_add_data_func("/qga/fsfreeze-status", &fix, @@ -931,6 +931,11 @@ static void vnc_dpy_copy(DisplayChangeListener *dcl, int i, x, y, pitch, inc, w_lim, s; int cmp_bytes; + if (!vd->server) { + /* no client connected */ + return; + } + vnc_refresh_server_surface(vd); QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) { if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) { |