diff options
author | Avi Kivity <avi@redhat.com> | 2012-05-22 20:05:03 +0300 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2012-05-22 20:05:03 +0300 |
commit | 18a188f66237e7b38fc8133d3862e5904c0e7ffb (patch) | |
tree | 8a9761d844dc6669efed0ab52f6fe775ad3fd5ce | |
parent | 3fd9fedb9fae4517d93d76e93a2924559cacf2f6 (diff) | |
parent | c48b0c80fca9858eb2f9343f1c0a04427f604941 (diff) |
Merge remote-tracking branch 'upstream' into nextqemu-kvm-1.1-rc3
* upstream: (30 commits)
Update version for 1.1.0-rc3
xen: Fix PV-on-HVM
qdev: Fix memory leak
virtio: check virtio_load return code
virtio-blk: always enable VIRTIO_BLK_F_SCSI
virtio-blk: define VirtIOBlkConf
virtio-blk: blockdev_mark_auto_del is transport-independent
virtio-blk: report non-zero status when failing SG_IO requests
use an uint64_t for the max_sz parameter in load_image_targphys
tests: Add rtc-test (fix test regression)
tests: Fix linker failure for fdc-test
mips: Fix BC1ANY[24]F instructions
linux-user: Fix stale tbs after mmap
virtio-pci: add missing 'static'
sparc64: fix initrd loading
audio: split IN_T into two separate constants
target-microblaze: impelemented swapx instructions
qemu-ga: align versioning with QEMU_VERSION
qemu-ga: fix segv after failure to open log file
qemu-ga: guest-shutdown: use only async-signal-safe functions
...
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | audio/mixeng.c | 36 | ||||
-rw-r--r-- | audio/mixeng_template.h | 4 | ||||
-rw-r--r-- | exec-all.h | 2 | ||||
-rw-r--r-- | exec.c | 17 | ||||
-rw-r--r-- | hw/loader.c | 2 | ||||
-rw-r--r-- | hw/loader.h | 3 | ||||
-rw-r--r-- | hw/qdev-properties.c | 6 | ||||
-rw-r--r-- | hw/s390-virtio-bus.c | 10 | ||||
-rw-r--r-- | hw/s390-virtio-bus.h | 4 | ||||
-rw-r--r-- | hw/sun4u.c | 56 | ||||
-rw-r--r-- | hw/virtio-balloon.c | 6 | ||||
-rw-r--r-- | hw/virtio-blk.c | 87 | ||||
-rw-r--r-- | hw/virtio-blk.h | 14 | ||||
-rw-r--r-- | hw/virtio-net.c | 6 | ||||
-rw-r--r-- | hw/virtio-pci.c | 13 | ||||
-rw-r--r-- | hw/virtio-pci.h | 4 | ||||
-rw-r--r-- | hw/virtio-scsi.c | 7 | ||||
-rw-r--r-- | hw/virtio-serial-bus.c | 6 | ||||
-rw-r--r-- | hw/virtio.h | 4 | ||||
-rw-r--r-- | hw/xen_platform.c | 5 | ||||
-rw-r--r-- | linux-user/mmap.c | 6 | ||||
-rw-r--r-- | qapi-schema-guest.json | 59 | ||||
-rw-r--r-- | qapi/qmp-core.h | 10 | ||||
-rw-r--r-- | qapi/qmp-dispatch.c | 8 | ||||
-rw-r--r-- | qapi/qmp-registry.c | 4 | ||||
-rw-r--r-- | qemu-ga.c | 49 | ||||
-rw-r--r-- | qga/commands-posix.c | 185 | ||||
-rw-r--r-- | qga/commands.c | 2 | ||||
-rw-r--r-- | qga/guest-agent-core.h | 5 | ||||
-rw-r--r-- | scripts/qapi-commands.py | 14 | ||||
-rw-r--r-- | target-microblaze/translate.c | 12 | ||||
-rw-r--r-- | target-mips/translate.c | 8 | ||||
-rw-r--r-- | tests/Makefile | 4 |
34 files changed, 380 insertions, 280 deletions
@@ -1 +1 @@ -1.0.92 +1.0.93 diff --git a/audio/mixeng.c b/audio/mixeng.c index 5446be674..02a9d9fb9 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -33,7 +33,8 @@ #define ENDIAN_CONVERT(v) (v) /* Signed 8 bit */ -#define IN_T int8_t +#define BSIZE 8 +#define ITYPE int #define IN_MIN SCHAR_MIN #define IN_MAX SCHAR_MAX #define SIGNED @@ -42,25 +43,29 @@ #undef SIGNED #undef IN_MAX #undef IN_MIN -#undef IN_T +#undef BSIZE +#undef ITYPE #undef SHIFT /* Unsigned 8 bit */ -#define IN_T uint8_t +#define BSIZE 8 +#define ITYPE uint #define IN_MIN 0 #define IN_MAX UCHAR_MAX #define SHIFT 8 #include "mixeng_template.h" #undef IN_MAX #undef IN_MIN -#undef IN_T +#undef BSIZE +#undef ITYPE #undef SHIFT #undef ENDIAN_CONVERT #undef ENDIAN_CONVERSION /* Signed 16 bit */ -#define IN_T int16_t +#define BSIZE 16 +#define ITYPE int #define IN_MIN SHRT_MIN #define IN_MAX SHRT_MAX #define SIGNED @@ -78,11 +83,13 @@ #undef SIGNED #undef IN_MAX #undef IN_MIN -#undef IN_T +#undef BSIZE +#undef ITYPE #undef SHIFT /* Unsigned 16 bit */ -#define IN_T uint16_t +#define BSIZE 16 +#define ITYPE uint #define IN_MIN 0 #define IN_MAX USHRT_MAX #define SHIFT 16 @@ -98,11 +105,13 @@ #undef ENDIAN_CONVERSION #undef IN_MAX #undef IN_MIN -#undef IN_T +#undef BSIZE +#undef ITYPE #undef SHIFT /* Signed 32 bit */ -#define IN_T int32_t +#define BSIZE 32 +#define ITYPE int #define IN_MIN INT32_MIN #define IN_MAX INT32_MAX #define SIGNED @@ -120,11 +129,13 @@ #undef SIGNED #undef IN_MAX #undef IN_MIN -#undef IN_T +#undef BSIZE +#undef ITYPE #undef SHIFT /* Unsigned 32 bit */ -#define IN_T uint32_t +#define BSIZE 32 +#define ITYPE uint #define IN_MIN 0 #define IN_MAX UINT32_MAX #define SHIFT 32 @@ -140,7 +151,8 @@ #undef ENDIAN_CONVERSION #undef IN_MAX #undef IN_MIN -#undef IN_T +#undef BSIZE +#undef ITYPE #undef SHIFT t_sample *mixeng_conv[2][2][2][3] = { diff --git a/audio/mixeng_template.h b/audio/mixeng_template.h index e644c231a..30849a62a 100644 --- a/audio/mixeng_template.h +++ b/audio/mixeng_template.h @@ -31,7 +31,8 @@ #define HALF (IN_MAX >> 1) #endif -#define ET glue (ENDIAN_CONVERSION, glue (_, IN_T)) +#define ET glue (ENDIAN_CONVERSION, glue (glue (glue (_, ITYPE), BSIZE), _t)) +#define IN_T glue (glue (ITYPE, BSIZE), _t) #ifdef FLOAT_MIXENG static mixeng_real inline glue (conv_, ET) (IN_T v) @@ -150,3 +151,4 @@ static void glue (glue (clip_, ET), _from_mono) #undef ET #undef HALF +#undef IN_T diff --git a/exec-all.h b/exec-all.h index c1b7e1f26..9bda7f735 100644 --- a/exec-all.h +++ b/exec-all.h @@ -96,6 +96,8 @@ void QEMU_NORETURN cpu_loop_exit(CPUArchState *env1); int page_unprotect(target_ulong address, uintptr_t pc, void *puc); void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, int is_cpu_write_access); +void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end, + int is_cpu_write_access); #if !defined(CONFIG_USER_ONLY) /* cputlb.c */ void tlb_flush_page(CPUArchState *env, target_ulong addr); @@ -1075,6 +1075,23 @@ TranslationBlock *tb_gen_code(CPUArchState *env, return tb; } +/* + * invalidate all TBs which intersect with the target physical pages + * starting in range [start;end[. NOTE: start and end may refer to + * different physical pages. 'is_cpu_write_access' should be true if called + * from a real cpu write access: the virtual CPU will exit the current + * TB if code is modified inside this TB. + */ +void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end, + int is_cpu_write_access) +{ + while (start < end) { + tb_invalidate_phys_page_range(start, end, is_cpu_write_access); + start &= TARGET_PAGE_MASK; + start += TARGET_PAGE_SIZE; + } +} + /* invalidate all TBs which intersect with the target physical page starting in range [start;end[. NOTE: start and end must refer to the same physical page. 'is_cpu_write_access' should be true if called diff --git a/hw/loader.c b/hw/loader.c index 415cdce53..7d64113e7 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -103,7 +103,7 @@ ssize_t read_targphys(const char *name, /* return the size or -1 if error */ int load_image_targphys(const char *filename, - target_phys_addr_t addr, int max_sz) + target_phys_addr_t addr, uint64_t max_sz) { int size; diff --git a/hw/loader.h b/hw/loader.h index fbcaba9f0..6da291e31 100644 --- a/hw/loader.h +++ b/hw/loader.h @@ -4,7 +4,8 @@ /* loader.c */ int get_image_size(const char *filename); int load_image(const char *filename, uint8_t *addr); /* deprecated */ -int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz); +int load_image_targphys(const char *filename, target_phys_addr_t, + uint64_t max_sz); int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, int big_endian, int elf_machine, diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index c5545dcd3..b7b5597c6 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -753,10 +753,12 @@ static void set_mac(Object *obj, Visitor *v, void *opaque, } mac->a[i] = strtol(str+pos, &p, 16); } + g_free(str); return; inval: error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); + g_free(str); } PropertyInfo qdev_prop_macaddr = { @@ -825,7 +827,7 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, uint32_t *ptr = qdev_get_prop_ptr(dev, prop); unsigned int slot, fn, n; Error *local_err = NULL; - char *str = (char *)""; + char *str; if (dev->state != DEV_STATE_CREATED) { error_set(errp, QERR_PERMISSION_DENIED); @@ -848,10 +850,12 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, goto invalid; } *ptr = slot << 3 | fn; + g_free(str); return; invalid: error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); + g_free(str); } static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 63ccd5c35..1d38a8f5c 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -163,8 +163,7 @@ static int s390_virtio_blk_init(VirtIOS390Device *dev) { VirtIODevice *vdev; - vdev = virtio_blk_init((DeviceState *)dev, &dev->block, - &dev->block_serial); + vdev = virtio_blk_init((DeviceState *)dev, &dev->blk); if (!vdev) { return -1; } @@ -400,8 +399,11 @@ static TypeInfo s390_virtio_net = { }; static Property s390_virtio_blk_properties[] = { - DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block), - DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial), + DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, blk.conf), + DEFINE_PROP_STRING("serial", VirtIOS390Device, blk.serial), +#ifdef __linux__ + DEFINE_PROP_BIT("scsi", VirtIOS390Device, blk.scsi, 0, true), +#endif DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h index 49e6c462d..4b99d0229 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390-virtio-bus.h @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "virtio-blk.h" #include "virtio-net.h" #include "virtio-serial.h" #include "virtio-scsi.h" @@ -64,8 +65,7 @@ struct VirtIOS390Device { ram_addr_t feat_offs; uint8_t feat_len; VirtIODevice *vdev; - BlockConf block; - char *block_serial; + VirtIOBlkConf blk; NICConf nic; uint32_t host_features; virtio_serial_conf serial; diff --git a/hw/sun4u.c b/hw/sun4u.c index fe3313890..517bdb818 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -67,7 +67,6 @@ #define KERNEL_LOAD_ADDR 0x00404000 #define CMDLINE_ADDR 0x003ff000 -#define INITRD_LOAD_ADDR 0x00300000 #define PROM_SIZE_MAX (4 * 1024 * 1024) #define PROM_VADDR 0x000ffd00000ULL #define APB_SPECIAL_BASE 0x1fe00000000ULL @@ -181,14 +180,18 @@ static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size, return 0; } -static unsigned long sun4u_load_kernel(const char *kernel_filename, - const char *initrd_filename, - ram_addr_t RAM_size, long *initrd_size) + +static uint64_t sun4u_load_kernel(const char *kernel_filename, + const char *initrd_filename, + ram_addr_t RAM_size, uint64_t *initrd_size, + uint64_t *initrd_addr, uint64_t *kernel_addr, + uint64_t *kernel_entry) { int linux_boot; unsigned int i; long kernel_size; uint8_t *ptr; + uint64_t kernel_top; linux_boot = (kernel_filename != NULL); @@ -201,29 +204,34 @@ static unsigned long sun4u_load_kernel(const char *kernel_filename, #else bswap_needed = 0; #endif - kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, - NULL, NULL, 1, ELF_MACHINE, 0); - if (kernel_size < 0) + kernel_size = load_elf(kernel_filename, NULL, NULL, kernel_entry, + kernel_addr, &kernel_top, 1, ELF_MACHINE, 0); + if (kernel_size < 0) { + *kernel_addr = KERNEL_LOAD_ADDR; + *kernel_entry = KERNEL_LOAD_ADDR; kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR, RAM_size - KERNEL_LOAD_ADDR, bswap_needed, TARGET_PAGE_SIZE); - if (kernel_size < 0) + } + if (kernel_size < 0) { kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR, RAM_size - KERNEL_LOAD_ADDR); + } if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } - - /* load initrd */ + /* load initrd above kernel */ *initrd_size = 0; if (initrd_filename) { + *initrd_addr = TARGET_PAGE_ALIGN(kernel_top); + *initrd_size = load_image_targphys(initrd_filename, - INITRD_LOAD_ADDR, - RAM_size - INITRD_LOAD_ADDR); - if (*initrd_size < 0) { + *initrd_addr, + RAM_size - *initrd_addr); + if ((int)*initrd_size < 0) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); @@ -231,9 +239,9 @@ static unsigned long sun4u_load_kernel(const char *kernel_filename, } if (*initrd_size > 0) { for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { - ptr = rom_ptr(KERNEL_LOAD_ADDR + i); + ptr = rom_ptr(*kernel_addr + i); if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */ - stl_p(ptr + 24, INITRD_LOAD_ADDR + KERNEL_LOAD_ADDR - 0x4000); + stl_p(ptr + 24, *initrd_addr + *kernel_addr); stl_p(ptr + 28, *initrd_size); break; } @@ -788,7 +796,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, CPUSPARCState *env; M48t59State *nvram; unsigned int i; - long initrd_size, kernel_size; + uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry; PCIBus *pci_bus, *pci_bus2, *pci_bus3; ISABus *isa_bus; qemu_irq *ivec_irqs, *pbm_irqs; @@ -845,13 +853,15 @@ static void sun4uv_init(MemoryRegion *address_space_mem, nvram = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59); initrd_size = 0; + initrd_addr = 0; kernel_size = sun4u_load_kernel(kernel_filename, initrd_filename, - ram_size, &initrd_size); + ram_size, &initrd_size, &initrd_addr, + &kernel_addr, &kernel_entry); sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", RAM_size, boot_devices, - KERNEL_LOAD_ADDR, kernel_size, + kernel_addr, kernel_size, kernel_cmdline, - INITRD_LOAD_ADDR, initrd_size, + initrd_addr, initrd_size, /* XXX: need an option to load a NVRAM image */ 0, graphic_width, graphic_height, graphic_depth, @@ -861,8 +871,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem, fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); + fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry); + fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); if (kernel_cmdline) { fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline) + 1); @@ -872,8 +882,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem, } else { fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0); } - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR); - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); + fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); + fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_devices[0]); fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width); diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index ce9d2c975..075ed87e3 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -211,11 +211,15 @@ static void virtio_balloon_save(QEMUFile *f, void *opaque) static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id) { VirtIOBalloon *s = opaque; + int ret; if (version_id != 1) return -EINVAL; - virtio_load(&s->vdev, f); + ret = virtio_load(&s->vdev, f); + if (ret) { + return ret; + } s->num_pages = qemu_get_be32(f); s->actual = qemu_get_be32(f); diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 49990f8ef..f9e1896ea 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -29,7 +29,7 @@ typedef struct VirtIOBlock void *rq; QEMUBH *bh; BlockConf *conf; - char *serial; + VirtIOBlkConf *blk; unsigned short sector_mask; DeviceState *qdev; } VirtIOBlock; @@ -145,20 +145,12 @@ static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s) return req; } -#ifdef __linux__ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) { - struct sg_io_hdr hdr; int ret; - int status; + int status = VIRTIO_BLK_S_OK; int i; - if ((req->dev->vdev.guest_features & (1 << VIRTIO_BLK_F_SCSI)) == 0) { - virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP); - g_free(req); - return; - } - /* * We require at least one output segment each for the virtio_blk_outhdr * and the SCSI command block. @@ -173,20 +165,26 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) } /* - * No support for bidirection commands yet. + * The scsi inhdr is placed in the second-to-last input segment, just + * before the regular inhdr. */ - if (req->elem.out_num > 2 && req->elem.in_num > 3) { - virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP); - g_free(req); - return; + req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base; + + if (!req->dev->blk->scsi) { + status = VIRTIO_BLK_S_UNSUPP; + goto fail; } /* - * The scsi inhdr is placed in the second-to-last input segment, just - * before the regular inhdr. + * No support for bidirection commands yet. */ - req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base; + if (req->elem.out_num > 2 && req->elem.in_num > 3) { + status = VIRTIO_BLK_S_UNSUPP; + goto fail; + } +#ifdef __linux__ + struct sg_io_hdr hdr; memset(&hdr, 0, sizeof(struct sg_io_hdr)); hdr.interface_id = 'S'; hdr.cmd_len = req->elem.out_sg[1].iov_len; @@ -230,12 +228,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) ret = bdrv_ioctl(req->dev->bs, SG_IO, &hdr); if (ret) { status = VIRTIO_BLK_S_UNSUPP; - hdr.status = ret; - hdr.resid = hdr.dxfer_len; - } else if (hdr.status) { - status = VIRTIO_BLK_S_IOERR; - } else { - status = VIRTIO_BLK_S_OK; + goto fail; } /* @@ -258,14 +251,16 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) virtio_blk_req_complete(req, status); g_free(req); -} #else -static void virtio_blk_handle_scsi(VirtIOBlockReq *req) -{ - virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP); + abort(); +#endif + +fail: + /* Just put anything nonzero so that the ioctl fails in the guest. */ + stl_p(&req->scsi->errors, 255); + virtio_blk_req_complete(req, status); g_free(req); } -#endif /* __linux__ */ typedef struct MultiReqBuffer { BlockRequest blkreq[32]; @@ -394,7 +389,7 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req, * terminated by '\0' only when shorter than buffer. */ strncpy(req->elem.in_sg[0].iov_base, - s->serial ? s->serial : "", + s->blk->serial ? s->blk->serial : "", MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES)); virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); g_free(req); @@ -509,6 +504,7 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features) features |= (1 << VIRTIO_BLK_F_GEOMETRY); features |= (1 << VIRTIO_BLK_F_TOPOLOGY); features |= (1 << VIRTIO_BLK_F_BLK_SIZE); + features |= (1 << VIRTIO_BLK_F_SCSI); if (bdrv_enable_write_cache(s->bs)) features |= (1 << VIRTIO_BLK_F_WCACHE); @@ -537,11 +533,16 @@ static void virtio_blk_save(QEMUFile *f, void *opaque) static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) { VirtIOBlock *s = opaque; + int ret; if (version_id != 2) return -EINVAL; - virtio_load(&s->vdev, f); + ret = virtio_load(&s->vdev, f); + if (ret) { + return ret; + } + while (qemu_get_sbyte(f)) { VirtIOBlockReq *req = virtio_blk_alloc_request(s); qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem)); @@ -568,28 +569,27 @@ static const BlockDevOps virtio_block_ops = { .resize_cb = virtio_blk_resize, }; -VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, - char **serial) +VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk) { VirtIOBlock *s; int cylinders, heads, secs; static int virtio_blk_id; DriveInfo *dinfo; - if (!conf->bs) { + if (!blk->conf.bs) { error_report("drive property not set"); return NULL; } - if (!bdrv_is_inserted(conf->bs)) { + if (!bdrv_is_inserted(blk->conf.bs)) { error_report("Device needs media, but drive is empty"); return NULL; } - if (!*serial) { + if (!blk->serial) { /* try to fall back to value set with legacy -drive serial=... */ - dinfo = drive_get_by_blockdev(conf->bs); + dinfo = drive_get_by_blockdev(blk->conf.bs); if (*dinfo->serial) { - *serial = strdup(dinfo->serial); + blk->serial = strdup(dinfo->serial); } } @@ -600,9 +600,9 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, s->vdev.get_config = virtio_blk_update_config; s->vdev.get_features = virtio_blk_get_features; s->vdev.reset = virtio_blk_reset; - s->bs = conf->bs; - s->conf = conf; - s->serial = *serial; + s->bs = blk->conf.bs; + s->conf = &blk->conf; + s->blk = blk; s->rq = NULL; s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1; bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs); @@ -614,10 +614,10 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, register_savevm(dev, "virtio-blk", virtio_blk_id++, 2, virtio_blk_save, virtio_blk_load, s); bdrv_set_dev_ops(s->bs, &virtio_block_ops, s); - bdrv_set_buffer_alignment(s->bs, conf->logical_block_size); + bdrv_set_buffer_alignment(s->bs, s->conf->logical_block_size); bdrv_iostatus_enable(s->bs); - add_boot_device_path(conf->bootindex, dev, "/disk@0,0"); + add_boot_device_path(s->conf->bootindex, dev, "/disk@0,0"); return &s->vdev; } @@ -626,5 +626,6 @@ void virtio_blk_exit(VirtIODevice *vdev) { VirtIOBlock *s = to_virtio_blk(vdev); unregister_savevm(s->qdev, "virtio-blk", s); + blockdev_mark_auto_del(s->bs); virtio_cleanup(vdev); } diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h index 244dce45a..d7850012b 100644 --- a/hw/virtio-blk.h +++ b/hw/virtio-blk.h @@ -97,12 +97,14 @@ struct virtio_scsi_inhdr uint32_t residual; }; -#ifdef __linux__ -#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \ - DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \ - DEFINE_PROP_BIT("scsi", _state, _field, VIRTIO_BLK_F_SCSI, true) -#else +struct VirtIOBlkConf +{ + BlockConf conf; + char *serial; + uint32_t scsi; +}; + #define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \ DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) -#endif + #endif diff --git a/hw/virtio-net.c b/hw/virtio-net.c index bc5e3a83d..3f190d417 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -891,11 +891,15 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) { VirtIONet *n = opaque; int i; + int ret; if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) return -EINVAL; - virtio_load(&n->vdev, f); + ret = virtio_load(&n->vdev, f); + if (ret) { + return ret; + } qemu_get_buffer(f, n->mac, ETH_ALEN); n->tx_waiting = qemu_get_be32(f); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 5eedabdaa..a0c2ca74b 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -491,7 +491,7 @@ static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val) virtio_config_writel(proxy->vdev, addr, val); } -const MemoryRegionPortio virtio_portio[] = { +static const MemoryRegionPortio virtio_portio[] = { { 0, 0x10000, 1, .write = virtio_pci_config_writeb, }, { 0, 0x10000, 2, .write = virtio_pci_config_writew, }, { 0, 0x10000, 4, .write = virtio_pci_config_writel, }, @@ -773,8 +773,7 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev) proxy->class_code != PCI_CLASS_STORAGE_OTHER) proxy->class_code = PCI_CLASS_STORAGE_SCSI; - vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block, - &proxy->block_serial); + vdev = virtio_blk_init(&pci_dev->qdev, &proxy->blk); if (!vdev) { return -1; } @@ -802,7 +801,6 @@ static int virtio_blk_exit_pci(PCIDevice *pci_dev) virtio_pci_stop_ioeventfd(proxy); virtio_blk_exit(proxy->vdev); - blockdev_mark_auto_del(proxy->block.bs); return virtio_exit_pci(pci_dev); } @@ -890,8 +888,11 @@ static int virtio_balloon_exit_pci(PCIDevice *pci_dev) static Property virtio_blk_properties[] = { DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block), - DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial), + DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, blk.conf), + DEFINE_PROP_STRING("serial", VirtIOPCIProxy, blk.serial), +#ifdef __linux__ + DEFINE_PROP_BIT("scsi", VirtIOPCIProxy, blk.scsi, 0, true), +#endif DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features), diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index e5604282e..889e59e42 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -15,6 +15,7 @@ #ifndef QEMU_VIRTIO_PCI_H #define QEMU_VIRTIO_PCI_H +#include "virtio-blk.h" #include "virtio-net.h" #include "virtio-serial.h" #include "virtio-scsi.h" @@ -32,8 +33,7 @@ typedef struct { uint32_t flags; uint32_t class_code; uint32_t nvectors; - BlockConf block; - char *block_serial; + VirtIOBlkConf blk; NICConf nic; uint32_t host_features; #ifdef CONFIG_LINUX diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index e8328f465..5e39ce93c 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -564,7 +564,12 @@ static void virtio_scsi_save(QEMUFile *f, void *opaque) static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id) { VirtIOSCSI *s = opaque; - virtio_load(&s->vdev, f); + int ret; + + ret = virtio_load(&s->vdev, f); + if (ret) { + return ret; + } return 0; } diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index ffbdfc2de..72287d10c 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -637,13 +637,17 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) VirtIOSerialPort *port; uint32_t max_nr_ports, nr_active_ports, ports_map; unsigned int i; + int ret; if (version_id > 3) { return -EINVAL; } /* The virtio device */ - virtio_load(&s->vdev, f); + ret = virtio_load(&s->vdev, f); + if (ret) { + return ret; + } if (version_id < 2) { return 0; diff --git a/hw/virtio.h b/hw/virtio.h index 0aef7d1bc..85aabe53d 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -191,8 +191,8 @@ void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, void *opaque); /* Base devices. */ -VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, - char **serial); +typedef struct VirtIOBlkConf VirtIOBlkConf; +VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk); struct virtio_net_conf; VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, struct virtio_net_conf *net); diff --git a/hw/xen_platform.c b/hw/xen_platform.c index a9c52a6e3..0214f370b 100644 --- a/hw/xen_platform.c +++ b/hw/xen_platform.c @@ -87,7 +87,10 @@ static void unplug_nic(PCIBus *b, PCIDevice *d) { if (pci_get_word(d->config + PCI_CLASS_DEVICE) == PCI_CLASS_NETWORK_ETHERNET) { - qdev_unplug(&(d->qdev), NULL); + /* Until qdev_free includes a call to object_unparent, we call it here + */ + object_unparent(&d->qdev.parent_obj); + qdev_free(&d->qdev); } } diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 7125d1cd4..d9468fea9 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -573,6 +573,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, page_dump(stdout); printf("\n"); #endif + tb_invalidate_phys_range(start, start + len, 0); mmap_unlock(); return start; fail: @@ -675,8 +676,10 @@ int target_munmap(abi_ulong start, abi_ulong len) } } - if (ret == 0) + if (ret == 0) { page_set_flags(start, start + len, 0); + tb_invalidate_phys_range(start, start + len, 0); + } mmap_unlock(); return ret; } @@ -754,6 +757,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, page_set_flags(old_addr, old_addr + old_size, 0); page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); } + tb_invalidate_phys_range(new_addr, new_addr + new_size, 0); mmap_unlock(); return new_addr; } diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json index 692b57067..d4055d262 100644 --- a/qapi-schema-guest.json +++ b/qapi-schema-guest.json @@ -126,16 +126,19 @@ # @guest-shutdown: # # Initiate guest-activated shutdown. Note: this is an asynchronous -# shutdown request, with no guaruntee of successful shutdown. Errors -# will be logged to guest's syslog. +# shutdown request, with no guarantee of successful shutdown. # # @mode: #optional "halt", "powerdown" (default), or "reboot" # -# Returns: Nothing on success +# This command does NOT return a response on success. Success condition +# is indicated by the VM exiting with a zero exit status or, when +# running with --no-shutdown, by issuing the query-status QMP command +# to confirm the VM status is "shutdown". # # Since: 0.15.0 ## -{ 'command': 'guest-shutdown', 'data': { '*mode': 'str' } } +{ 'command': 'guest-shutdown', 'data': { '*mode': 'str' }, + 'success-response': 'no' } ## # @guest-file-open: @@ -359,17 +362,21 @@ # For the best results it's strongly recommended to have the pm-utils # package installed in the guest. # -# Returns: nothing on success +# This command does NOT return a response on success. There is a high chance +# the command succeeded if the VM exits with a zero exit status or, when +# running with --no-shutdown, by issuing the query-status QMP command to +# to confirm the VM status is "shutdown". However, the VM could also exit +# (or set its status to "shutdown") due to other reasons. +# +# The following errors may be returned: # If suspend to disk is not supported, Unsupported # -# Notes: o This is an asynchronous request. There's no guarantee a response -# will be sent -# o It's strongly recommended to issue the guest-sync command before -# sending commands when the guest resumes +# Notes: It's strongly recommended to issue the guest-sync command before +# sending commands when the guest resumes # # Since: 1.1 ## -{ 'command': 'guest-suspend-disk' } +{ 'command': 'guest-suspend-disk', 'success-response': 'no' } ## # @guest-suspend-ram @@ -387,17 +394,21 @@ # command. Thus, it's *required* to query QEMU for the presence of the # 'system_wakeup' command before issuing guest-suspend-ram. # -# Returns: nothing on success +# This command does NOT return a response on success. There are two options +# to check for success: +# 1. Wait for the SUSPEND QMP event from QEMU +# 2. Issue the query-status QMP command to confirm the VM status is +# "suspended" +# +# The following errors may be returned: # If suspend to ram is not supported, Unsupported # -# Notes: o This is an asynchronous request. There's no guarantee a response -# will be sent -# o It's strongly recommended to issue the guest-sync command before -# sending commands when the guest resumes +# Notes: It's strongly recommended to issue the guest-sync command before +# sending commands when the guest resumes # # Since: 1.1 ## -{ 'command': 'guest-suspend-ram' } +{ 'command': 'guest-suspend-ram', 'success-response': 'no' } ## # @guest-suspend-hybrid @@ -410,17 +421,21 @@ # command. Thus, it's *required* to query QEMU for the presence of the # 'system_wakeup' command before issuing guest-suspend-hybrid. # -# Returns: nothing on success +# This command does NOT return a response on success. There are two options +# to check for success: +# 1. Wait for the SUSPEND QMP event from QEMU +# 2. Issue the query-status QMP command to confirm the VM status is +# "suspended" +# +# The following errors may be returned: # If hybrid suspend is not supported, Unsupported # -# Notes: o This is an asynchronous request. There's no guarantee a response -# will be sent -# o It's strongly recommended to issue the guest-sync command before -# sending commands when the guest resumes +# Notes: It's strongly recommended to issue the guest-sync command before +# sending commands when the guest resumes # # Since: 1.1 ## -{ 'command': 'guest-suspend-hybrid' } +{ 'command': 'guest-suspend-hybrid', 'success-response': 'no' } ## # @GuestIpAddressType: diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h index 431ddbb33..b0f64ba1e 100644 --- a/qapi/qmp-core.h +++ b/qapi/qmp-core.h @@ -25,16 +25,24 @@ typedef enum QmpCommandType QCT_NORMAL, } QmpCommandType; +typedef enum QmpCommandOptions +{ + QCO_NO_OPTIONS = 0x0, + QCO_NO_SUCCESS_RESP = 0x1, +} QmpCommandOptions; + typedef struct QmpCommand { const char *name; QmpCommandType type; QmpCommandFunc *fn; + QmpCommandOptions options; QTAILQ_ENTRY(QmpCommand) node; bool enabled; } QmpCommand; -void qmp_register_command(const char *name, QmpCommandFunc *fn); +void qmp_register_command(const char *name, QmpCommandFunc *fn, + QmpCommandOptions options); QmpCommand *qmp_find_command(const char *name); QObject *qmp_dispatch(QObject *request); void qmp_disable_command(const char *name); diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 43f640a95..122c1a29b 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -94,8 +94,12 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp) switch (cmd->type) { case QCT_NORMAL: cmd->fn(args, &ret, errp); - if (!error_is_set(errp) && ret == NULL) { - ret = QOBJECT(qdict_new()); + if (!error_is_set(errp)) { + if (cmd->options & QCO_NO_SUCCESS_RESP) { + g_assert(!ret); + } else if (!ret) { + ret = QOBJECT(qdict_new()); + } } break; } diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c index 43d5cdeb6..541461337 100644 --- a/qapi/qmp-registry.c +++ b/qapi/qmp-registry.c @@ -17,7 +17,8 @@ static QTAILQ_HEAD(QmpCommandList, QmpCommand) qmp_commands = QTAILQ_HEAD_INITIALIZER(qmp_commands); -void qmp_register_command(const char *name, QmpCommandFunc *fn) +void qmp_register_command(const char *name, QmpCommandFunc *fn, + QmpCommandOptions options) { QmpCommand *cmd = g_malloc0(sizeof(*cmd)); @@ -25,6 +26,7 @@ void qmp_register_command(const char *name, QmpCommandFunc *fn) cmd->type = QCT_NORMAL; cmd->fn = fn; cmd->enabled = true; + cmd->options = options; QTAILQ_INSERT_TAIL(&qmp_commands, cmd, node); } @@ -104,16 +104,9 @@ static void quit_handler(int sig) } #ifndef _WIN32 -/* reap _all_ terminated children */ -static void child_handler(int sig) -{ - int status; - while (waitpid(-1, &status, WNOHANG) > 0) /* NOTHING */; -} - static gboolean register_signal_handlers(void) { - struct sigaction sigact, sigact_chld; + struct sigaction sigact; int ret; memset(&sigact, 0, sizeof(struct sigaction)); @@ -130,15 +123,24 @@ static gboolean register_signal_handlers(void) return false; } - memset(&sigact_chld, 0, sizeof(struct sigaction)); - sigact_chld.sa_handler = child_handler; - sigact_chld.sa_flags = SA_NOCLDSTOP; - ret = sigaction(SIGCHLD, &sigact_chld, NULL); - if (ret == -1) { - g_error("error configuring signal handler: %s", strerror(errno)); + return true; +} + +/* TODO: use this in place of all post-fork() fclose(std*) callers */ +void reopen_fd_to_null(int fd) +{ + int nullfd; + + nullfd = open("/dev/null", O_RDWR); + if (nullfd < 0) { + return; } - return true; + dup2(nullfd, fd); + + if (nullfd != fd) { + close(nullfd); + } } #endif @@ -167,7 +169,7 @@ static void usage(const char *cmd) " -h, --help display this help and exit\n" "\n" "Report bugs to <mdroth@linux.vnet.ibm.com>\n" - , cmd, QGA_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT, + , cmd, QEMU_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT, QGA_STATEDIR_DEFAULT); } @@ -428,9 +430,9 @@ static void become_daemon(const char *pidfile) goto fail; } - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); + reopen_fd_to_null(STDIN_FILENO); + reopen_fd_to_null(STDOUT_FILENO); + reopen_fd_to_null(STDERR_FILENO); return; fail: @@ -488,8 +490,6 @@ static void process_command(GAState *s, QDict *req) g_warning("error sending response: %s", strerror(ret)); } qobject_decref(rsp); - } else { - g_warning("error getting response"); } } @@ -729,7 +729,7 @@ int main(int argc, char **argv) log_level = G_LOG_LEVEL_MASK; break; case 'V': - printf("QEMU Guest Agent %s\n", QGA_VERSION); + printf("QEMU Guest Agent %s\n", QEMU_VERSION); return 0; case 'd': daemonize = 1; @@ -836,12 +836,13 @@ int main(int argc, char **argv) become_daemon(pid_filepath); } if (log_filepath) { - s->log_file = fopen(log_filepath, "a"); - if (!s->log_file) { + FILE *log_file = fopen(log_filepath, "a"); + if (!log_file) { g_critical("unable to open specified log file: %s", strerror(errno)); goto out_bad; } + s->log_file = log_file; } } diff --git a/qga/commands-posix.c b/qga/commands-posix.c index e448431c6..7664be10a 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -34,29 +34,11 @@ #endif #endif -#if defined(__linux__) -/* TODO: use this in place of all post-fork() fclose(std*) callers */ -static void reopen_fd_to_null(int fd) -{ - int nullfd; - - nullfd = open("/dev/null", O_RDWR); - if (nullfd < 0) { - return; - } - - dup2(nullfd, fd); - - if (nullfd != fd) { - close(nullfd); - } -} -#endif /* defined(__linux__) */ - void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) { - int ret; const char *shutdown_flag; + pid_t rpid, pid; + int status; slog("guest-shutdown called, mode: %s", mode); if (!has_mode || strcmp(mode, "powerdown") == 0) { @@ -71,23 +53,30 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) return; } - ret = fork(); - if (ret == 0) { + pid = fork(); + if (pid == 0) { /* child, start the shutdown */ setsid(); - fclose(stdin); - fclose(stdout); - fclose(stderr); - - ret = execl("/sbin/shutdown", "shutdown", shutdown_flag, "+0", - "hypervisor initiated shutdown", (char*)NULL); - if (ret) { - slog("guest-shutdown failed: %s", strerror(errno)); - } - exit(!!ret); - } else if (ret < 0) { - error_set(err, QERR_UNDEFINED_ERROR); + reopen_fd_to_null(0); + reopen_fd_to_null(1); + reopen_fd_to_null(2); + + execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0", + "hypervisor initiated shutdown", (char*)NULL, environ); + _exit(EXIT_FAILURE); + } else if (pid < 0) { + goto exit_err; + } + + do { + rpid = waitpid(pid, &status, 0); + } while (rpid == -1 && errno == EINTR); + if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) { + return; } + +exit_err: + error_set(err, QERR_UNDEFINED_ERROR); } typedef struct GuestFileHandle { @@ -531,117 +520,88 @@ static void guest_fsfreeze_cleanup(void) #define SUSPEND_SUPPORTED 0 #define SUSPEND_NOT_SUPPORTED 1 -/** - * This function forks twice and the information about the mode support - * status is passed to the qemu-ga process via a pipe. - * - * This approach allows us to keep the way we reap terminated children - * in qemu-ga quite simple. - */ static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg, const char *sysfile_str, Error **err) { - pid_t pid; - ssize_t ret; char *pmutils_path; - int status, pipefds[2]; - - if (pipe(pipefds) < 0) { - error_set(err, QERR_UNDEFINED_ERROR); - return; - } + pid_t pid, rpid; + int status; pmutils_path = g_find_program_in_path(pmutils_bin); pid = fork(); if (!pid) { - struct sigaction act; - - memset(&act, 0, sizeof(act)); - act.sa_handler = SIG_DFL; - sigaction(SIGCHLD, &act, NULL); + char buf[32]; /* hopefully big enough */ + ssize_t ret; + int fd; setsid(); - close(pipefds[0]); reopen_fd_to_null(0); reopen_fd_to_null(1); reopen_fd_to_null(2); - pid = fork(); - if (!pid) { - int fd; - char buf[32]; /* hopefully big enough */ - - if (pmutils_path) { - execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ); - } - - /* - * If we get here either pm-utils is not installed or execle() has - * failed. Let's try the manual method if the caller wants it. - */ - - if (!sysfile_str) { - _exit(SUSPEND_NOT_SUPPORTED); - } - - fd = open(LINUX_SYS_STATE_FILE, O_RDONLY); - if (fd < 0) { - _exit(SUSPEND_NOT_SUPPORTED); - } + if (pmutils_path) { + execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ); + } - ret = read(fd, buf, sizeof(buf)-1); - if (ret <= 0) { - _exit(SUSPEND_NOT_SUPPORTED); - } - buf[ret] = '\0'; + /* + * If we get here either pm-utils is not installed or execle() has + * failed. Let's try the manual method if the caller wants it. + */ - if (strstr(buf, sysfile_str)) { - _exit(SUSPEND_SUPPORTED); - } + if (!sysfile_str) { + _exit(SUSPEND_NOT_SUPPORTED); + } + fd = open(LINUX_SYS_STATE_FILE, O_RDONLY); + if (fd < 0) { _exit(SUSPEND_NOT_SUPPORTED); } - if (pid > 0) { - wait(&status); - } else { - status = SUSPEND_NOT_SUPPORTED; + ret = read(fd, buf, sizeof(buf)-1); + if (ret <= 0) { + _exit(SUSPEND_NOT_SUPPORTED); } + buf[ret] = '\0'; - ret = write(pipefds[1], &status, sizeof(status)); - if (ret != sizeof(status)) { - _exit(EXIT_FAILURE); + if (strstr(buf, sysfile_str)) { + _exit(SUSPEND_SUPPORTED); } - _exit(EXIT_SUCCESS); + _exit(SUSPEND_NOT_SUPPORTED); } - close(pipefds[1]); g_free(pmutils_path); if (pid < 0) { - error_set(err, QERR_UNDEFINED_ERROR); - goto out; - } - - ret = read(pipefds[0], &status, sizeof(status)); - if (ret == sizeof(status) && WIFEXITED(status) && - WEXITSTATUS(status) == SUSPEND_SUPPORTED) { - goto out; + goto undef_err; + } + + do { + rpid = waitpid(pid, &status, 0); + } while (rpid == -1 && errno == EINTR); + if (rpid == pid && WIFEXITED(status)) { + switch (WEXITSTATUS(status)) { + case SUSPEND_SUPPORTED: + return; + case SUSPEND_NOT_SUPPORTED: + error_set(err, QERR_UNSUPPORTED); + return; + default: + goto undef_err; + } } - error_set(err, QERR_UNSUPPORTED); - -out: - close(pipefds[0]); +undef_err: + error_set(err, QERR_UNDEFINED_ERROR); } static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, Error **err) { - pid_t pid; char *pmutils_path; + pid_t rpid, pid; + int status; pmutils_path = g_find_program_in_path(pmutils_bin); @@ -683,9 +643,18 @@ static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, g_free(pmutils_path); if (pid < 0) { - error_set(err, QERR_UNDEFINED_ERROR); + goto exit_err; + } + + do { + rpid = waitpid(pid, &status, 0); + } while (rpid == -1 && errno == EINTR); + if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) { return; } + +exit_err: + error_set(err, QERR_UNDEFINED_ERROR); } void qmp_guest_suspend_disk(Error **err) diff --git a/qga/commands.c b/qga/commands.c index 5bcceaae3..46b0b083b 100644 --- a/qga/commands.c +++ b/qga/commands.c @@ -52,7 +52,7 @@ struct GuestAgentInfo *qmp_guest_info(Error **err) GuestAgentCommandInfoList *cmd_info_list; char **cmd_list_head, **cmd_list; - info->version = g_strdup(QGA_VERSION); + info->version = g_strdup(QEMU_VERSION); cmd_list_head = cmd_list = qmp_get_command_list(); if (*cmd_list_head == NULL) { diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h index bbb8b9b12..49a7abee9 100644 --- a/qga/guest-agent-core.h +++ b/qga/guest-agent-core.h @@ -13,7 +13,6 @@ #include "qapi/qmp-core.h" #include "qemu-common.h" -#define QGA_VERSION "1.0" #define QGA_READ_COUNT_DEFAULT 4096 typedef struct GAState GAState; @@ -35,3 +34,7 @@ void ga_set_response_delimited(GAState *s); bool ga_is_frozen(GAState *s); void ga_set_frozen(GAState *s); void ga_unset_frozen(GAState *s); + +#ifndef _WIN32 +void reopen_fd_to_null(int fd); +#endif diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 0b4f0a0fe..9eed40e18 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -291,14 +291,24 @@ out: return ret +def option_value_matches(opt, val, cmd): + if opt in cmd and cmd[opt] == val: + return True + return False + def gen_registry(commands): registry="" push_indent() for cmd in commands: + options = 'QCO_NO_OPTIONS' + if option_value_matches('success-response', 'no', cmd): + options = 'QCO_NO_SUCCESS_RESP' + registry += mcgen(''' -qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s); +qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s); ''', - name=cmd['command'], c_name=c_fun(cmd['command'])) + name=cmd['command'], c_name=c_fun(cmd['command']), + opts=options) pop_indent() ret = mcgen(''' static void qmp_init_marshal(void) diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 742b3957c..a362938e4 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -743,7 +743,7 @@ static void dec_bit(DisasContext *dc) unsigned int op; int mem_index = cpu_mmu_index(dc->env); - op = dc->ir & ((1 << 8) - 1); + op = dc->ir & ((1 << 9) - 1); switch (op) { case 0x21: /* src. */ @@ -825,6 +825,16 @@ static void dec_bit(DisasContext *dc) gen_helper_clz(cpu_R[dc->rd], cpu_R[dc->ra]); } break; + case 0x1e0: + /* swapb */ + LOG_DIS("swapb r%d r%d\n", dc->rd, dc->ra); + tcg_gen_bswap32_i32(cpu_R[dc->rd], cpu_R[dc->ra]); + break; + case 0x1e1: + /*swaph */ + LOG_DIS("swaph r%d r%d\n", dc->rd, dc->ra); + tcg_gen_rotri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 16); + break; default: cpu_abort(dc->env, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n", dc->pc, op, dc->rd, dc->ra, dc->rb); diff --git a/target-mips/translate.c b/target-mips/translate.c index f5297b039..0c563eedf 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -6099,7 +6099,7 @@ static void gen_compute_branch1 (CPUMIPSState *env, DisasContext *ctx, uint32_t TCGv_i32 t1 = tcg_temp_new_i32(); tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc)); tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1)); - tcg_gen_nor_i32(t0, t0, t1); + tcg_gen_nand_i32(t0, t0, t1); tcg_temp_free_i32(t1); tcg_gen_andi_i32(t0, t0, 1); tcg_gen_extu_i32_tl(bcond, t0); @@ -6123,11 +6123,11 @@ static void gen_compute_branch1 (CPUMIPSState *env, DisasContext *ctx, uint32_t TCGv_i32 t1 = tcg_temp_new_i32(); tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc)); tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1)); - tcg_gen_or_i32(t0, t0, t1); + tcg_gen_and_i32(t0, t0, t1); tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+2)); - tcg_gen_or_i32(t0, t0, t1); + tcg_gen_and_i32(t0, t0, t1); tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+3)); - tcg_gen_nor_i32(t0, t0, t1); + tcg_gen_nand_i32(t0, t0, t1); tcg_temp_free_i32(t1); tcg_gen_andi_i32(t0, t0, 1); tcg_gen_extu_i32_tl(bcond, t0); diff --git a/tests/Makefile b/tests/Makefile index 20e4da9fb..ab7f66700 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -18,8 +18,8 @@ check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh # All QTests for now are POSIX-only, but the dependencies are # really in libqtest, not in the testcases themselves. -check-qtest-i386-y = tests/rtc-test$(EXESUF) check-qtest-i386-y = tests/fdc-test$(EXESUF) +check-qtest-i386-y += tests/rtc-test$(EXESUF) check-qtest-x86_64-y = $(check-qtest-i386-y) check-qtest-sparc-y = tests/m48t59-test$(EXESUF) check-qtest-sparc64-y = tests/m48t59-test$(EXESUF) @@ -68,7 +68,7 @@ tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marsh tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y) tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y) -tests/fdc-test$(EXESUF): tests/fdc-test.o tests/libqtest.o +tests/fdc-test$(EXESUF): tests/fdc-test.o tests/libqtest.o $(trace-obj-y) # QTest rules |