diff options
-rw-r--r-- | block.c | 49 | ||||
-rw-r--r-- | block/qcow2-refcount.c | 25 | ||||
-rw-r--r-- | blockdev.c | 1 | ||||
-rw-r--r-- | hw/arm/xilinx_zynq.c | 3 | ||||
-rw-r--r-- | hw/microblaze/petalogix_ml605_mmu.c | 3 | ||||
-rw-r--r-- | hw/pci/pci-hotplug.c | 2 | ||||
-rw-r--r-- | hw/scsi-bus.c | 8 | ||||
-rw-r--r-- | hw/scsi.h | 3 | ||||
-rw-r--r-- | hw/usb/dev-storage.c | 2 | ||||
-rw-r--r-- | hw/xen_backend.c | 15 | ||||
-rw-r--r-- | hw/xen_backend.h | 2 | ||||
-rw-r--r-- | hw/xen_disk.c | 76 | ||||
-rw-r--r-- | include/block/block_int.h | 3 | ||||
-rw-r--r-- | include/qapi/qmp/qstring.h | 1 | ||||
-rw-r--r-- | linux-user/strace.c | 2 | ||||
-rw-r--r-- | main-loop.c | 25 | ||||
-rw-r--r-- | monitor.c | 60 | ||||
-rw-r--r-- | qemu-char.c | 126 | ||||
-rw-r--r-- | qobject/qstring.c | 8 | ||||
-rw-r--r-- | target-s390x/translate.c | 1 | ||||
-rw-r--r-- | tests/test-visitor-serialization.c | 12 |
21 files changed, 207 insertions, 220 deletions
@@ -140,8 +140,6 @@ void bdrv_io_limits_disable(BlockDriverState *bs) bs->slice_start = 0; bs->slice_end = 0; - bs->slice_time = 0; - memset(&bs->io_base, 0, sizeof(bs->io_base)); } static void bdrv_block_timer(void *opaque) @@ -1433,11 +1431,10 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest, bs_dest->enable_write_cache = bs_src->enable_write_cache; /* i/o timing parameters */ - bs_dest->slice_time = bs_src->slice_time; bs_dest->slice_start = bs_src->slice_start; bs_dest->slice_end = bs_src->slice_end; + bs_dest->slice_submitted = bs_src->slice_submitted; bs_dest->io_limits = bs_src->io_limits; - bs_dest->io_base = bs_src->io_base; bs_dest->throttled_reqs = bs_src->throttled_reqs; bs_dest->block_timer = bs_src->block_timer; bs_dest->io_limits_enabled = bs_src->io_limits_enabled; @@ -3750,6 +3747,7 @@ static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors, bool is_write, double elapsed_time, uint64_t *wait) { uint64_t bps_limit = 0; + uint64_t extension; double bytes_limit, bytes_base, bytes_res; double slice_time, wait_time; @@ -3768,9 +3766,9 @@ static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors, slice_time = bs->slice_end - bs->slice_start; slice_time /= (NANOSECONDS_PER_SECOND); bytes_limit = bps_limit * slice_time; - bytes_base = bs->nr_bytes[is_write] - bs->io_base.bytes[is_write]; + bytes_base = bs->slice_submitted.bytes[is_write]; if (bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL]) { - bytes_base += bs->nr_bytes[!is_write] - bs->io_base.bytes[!is_write]; + bytes_base += bs->slice_submitted.bytes[!is_write]; } /* bytes_base: the bytes of data which have been read/written; and @@ -3797,10 +3795,12 @@ static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors, * info can be kept until the timer fire, so it is increased and tuned * based on the result of experiment. */ - bs->slice_time = wait_time * BLOCK_IO_SLICE_TIME * 10; - bs->slice_end += bs->slice_time - 3 * BLOCK_IO_SLICE_TIME; + extension = wait_time * NANOSECONDS_PER_SECOND; + extension = DIV_ROUND_UP(extension, BLOCK_IO_SLICE_TIME) * + BLOCK_IO_SLICE_TIME; + bs->slice_end += extension; if (wait) { - *wait = wait_time * BLOCK_IO_SLICE_TIME * 10; + *wait = wait_time * NANOSECONDS_PER_SECOND; } return true; @@ -3828,9 +3828,9 @@ static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write, slice_time = bs->slice_end - bs->slice_start; slice_time /= (NANOSECONDS_PER_SECOND); ios_limit = iops_limit * slice_time; - ios_base = bs->nr_ops[is_write] - bs->io_base.ios[is_write]; + ios_base = bs->slice_submitted.ios[is_write]; if (bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL]) { - ios_base += bs->nr_ops[!is_write] - bs->io_base.ios[!is_write]; + ios_base += bs->slice_submitted.ios[!is_write]; } if (ios_base + 1 <= ios_limit) { @@ -3841,7 +3841,7 @@ static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write, return false; } - /* Calc approx time to dispatch */ + /* Calc approx time to dispatch, in seconds */ wait_time = (ios_base + 1) / iops_limit; if (wait_time > elapsed_time) { wait_time = wait_time - elapsed_time; @@ -3849,10 +3849,10 @@ static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write, wait_time = 0; } - bs->slice_time = wait_time * BLOCK_IO_SLICE_TIME * 10; - bs->slice_end += bs->slice_time - 3 * BLOCK_IO_SLICE_TIME; + /* Exceeded current slice, extend it by another slice time */ + bs->slice_end += BLOCK_IO_SLICE_TIME; if (wait) { - *wait = wait_time * BLOCK_IO_SLICE_TIME * 10; + *wait = wait_time * NANOSECONDS_PER_SECOND; } return true; @@ -3867,19 +3867,10 @@ static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors, int bps_ret, iops_ret; now = qemu_get_clock_ns(vm_clock); - if ((bs->slice_start < now) - && (bs->slice_end > now)) { - bs->slice_end = now + bs->slice_time; - } else { - bs->slice_time = 5 * BLOCK_IO_SLICE_TIME; + if (now > bs->slice_end) { bs->slice_start = now; - bs->slice_end = now + bs->slice_time; - - bs->io_base.bytes[is_write] = bs->nr_bytes[is_write]; - bs->io_base.bytes[!is_write] = bs->nr_bytes[!is_write]; - - bs->io_base.ios[is_write] = bs->nr_ops[is_write]; - bs->io_base.ios[!is_write] = bs->nr_ops[!is_write]; + bs->slice_end = now + BLOCK_IO_SLICE_TIME; + memset(&bs->slice_submitted, 0, sizeof(bs->slice_submitted)); } elapsed_time = now - bs->slice_start; @@ -3907,6 +3898,10 @@ static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors, *wait = 0; } + bs->slice_submitted.bytes[is_write] += (int64_t)nb_sectors * + BDRV_SECTOR_SIZE; + bs->slice_submitted.ios[is_write]++; + return false; } diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index c38e970bf2..b32738f8d9 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -747,10 +747,9 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, if (l1_table_offset != s->l1_table_offset) { l1_table = g_malloc0(align_offset(l1_size2, 512)); l1_allocated = 1; - if (bdrv_pread(bs->file, l1_table_offset, - l1_table, l1_size2) != l1_size2) - { - ret = -EIO; + + ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2); + if (ret < 0) { goto fail; } @@ -802,7 +801,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, } if (refcount < 0) { - ret = -EIO; + ret = refcount; goto fail; } } @@ -833,7 +832,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, refcount = get_refcount(bs, l2_offset >> s->cluster_bits); } if (refcount < 0) { - ret = -EIO; + ret = refcount; goto fail; } else if (refcount == 1) { l2_offset |= QCOW_OFLAG_COPIED; @@ -852,14 +851,16 @@ fail: } /* Update L1 only if it isn't deleted anyway (addend = -1) */ - if (addend >= 0 && l1_modified) { - for(i = 0; i < l1_size; i++) + if (ret == 0 && addend >= 0 && l1_modified) { + for (i = 0; i < l1_size; i++) { cpu_to_be64s(&l1_table[i]); - if (bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table, - l1_size2) < 0) - goto fail; - for(i = 0; i < l1_size; i++) + } + + ret = bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table, l1_size2); + + for (i = 0; i < l1_size; i++) { be64_to_cpus(&l1_table[i]); + } } if (l1_allocated) g_free(l1_table); diff --git a/blockdev.c b/blockdev.c index 8cdc9ce16a..6dc999d802 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1069,7 +1069,6 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd, } bs->io_limits = io_limits; - bs->slice_time = BLOCK_IO_SLICE_TIME; if (!bs->io_limits_enabled && bdrv_io_limits_enabled(bs)) { bdrv_io_limits_enable(bs); diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 6f362865f9..5b9257a9de 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -86,8 +86,7 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, spi = (SSIBus *)qdev_get_child_bus(dev, bus_name); for (j = 0; j < num_ss; ++j) { - flash_dev = ssi_create_slave_no_init(spi, "n25q128"); - qdev_init_nofail(flash_dev); + flash_dev = ssi_create_slave(spi, "n25q128"); cs_line = qdev_get_gpio_in(flash_dev, 0); sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line); diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index cfc02207ab..07dc808405 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -158,8 +158,7 @@ petalogix_ml605_init(QEMUMachineInitArgs *args) for (i = 0; i < NUM_SPI_FLASHES; i++) { qemu_irq cs_line; - dev = ssi_create_slave_no_init(spi, "n25q128"); - qdev_init_nofail(dev); + dev = ssi_create_slave(spi, "n25q128"); cs_line = qdev_get_gpio_in(dev, 0); sysbus_connect_irq(busdev, i+1, cs_line); } diff --git a/hw/pci/pci-hotplug.c b/hw/pci/pci-hotplug.c index f38df30540..180ee07fef 100644 --- a/hw/pci/pci-hotplug.c +++ b/hw/pci/pci-hotplug.c @@ -99,7 +99,7 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter, dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1); dinfo->bus = scsibus->busnr; scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit, - false, -1); + false, -1, NULL); if (!scsidev) { return -1; } diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 08787c2a9b..ac2093a5ef 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -207,7 +207,8 @@ static int scsi_qdev_exit(DeviceState *qdev) /* handle legacy '-drive if=scsi,...' cmd line args */ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, - int unit, bool removable, int bootindex) + int unit, bool removable, int bootindex, + const char *serial) { const char *driver; DeviceState *dev; @@ -221,6 +222,9 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, if (object_property_find(OBJECT(dev), "removable", NULL)) { qdev_prop_set_bit(dev, "removable", removable); } + if (serial) { + qdev_prop_set_string(dev, "serial", serial); + } if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) { qdev_free(dev); return NULL; @@ -243,7 +247,7 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus) continue; } qemu_opts_loc_restore(dinfo->opts); - if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false, -1)) { + if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false, -1, NULL)) { res = -1; break; } @@ -160,7 +160,8 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d) } SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, - int unit, bool removable, int bootindex); + int unit, bool removable, int bootindex, + const char *serial); int scsi_bus_legacy_handle_cmdline(SCSIBus *bus); /* diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index d3f01aa2a7..21651b3637 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -625,7 +625,7 @@ static int usb_msd_initfn_storage(USBDevice *dev) usb_desc_init(dev); scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_storage); scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable, - s->conf.bootindex); + s->conf.bootindex, s->serial); if (!scsi_dev) { return -1; } diff --git a/hw/xen_backend.c b/hw/xen_backend.c index 24381b55e5..02693d7565 100644 --- a/hw/xen_backend.c +++ b/hw/xen_backend.c @@ -85,12 +85,20 @@ char *xenstore_read_str(const char *base, const char *node) int xenstore_write_int(const char *base, const char *node, int ival) { - char val[32]; + char val[12]; snprintf(val, sizeof(val), "%d", ival); return xenstore_write_str(base, node, val); } +int xenstore_write_int64(const char *base, const char *node, int64_t ival) +{ + char val[21]; + + snprintf(val, sizeof(val), "%"PRId64, ival); + return xenstore_write_str(base, node, val); +} + int xenstore_read_int(const char *base, const char *node, int *ival) { char *val; @@ -114,6 +122,11 @@ int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival) return xenstore_write_int(xendev->be, node, ival); } +int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival) +{ + return xenstore_write_int64(xendev->be, node, ival); +} + char *xenstore_read_be_str(struct XenDevice *xendev, const char *node) { return xenstore_read_str(xendev->be, node); diff --git a/hw/xen_backend.h b/hw/xen_backend.h index 6d5c699c51..d04b985d10 100644 --- a/hw/xen_backend.h +++ b/hw/xen_backend.h @@ -63,11 +63,13 @@ extern const char *xen_protocol; /* xenstore helper functions */ int xenstore_write_str(const char *base, const char *node, const char *val); int xenstore_write_int(const char *base, const char *node, int ival); +int xenstore_write_int64(const char *base, const char *node, int64_t ival); char *xenstore_read_str(const char *base, const char *node); int xenstore_read_int(const char *base, const char *node, int *ival); int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val); int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival); +int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival); char *xenstore_read_be_str(struct XenDevice *xendev, const char *node); int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival); char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node); diff --git a/hw/xen_disk.c b/hw/xen_disk.c index 83329e2e69..47a51cf014 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -700,7 +700,7 @@ static void blk_alloc(struct XenDevice *xendev) static int blk_init(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); - int index, qflags, info = 0; + int info = 0; /* read xenstore entries */ if (blkdev->params == NULL) { @@ -743,10 +743,7 @@ static int blk_init(struct XenDevice *xendev) } /* read-only ? */ - qflags = BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO; - if (strcmp(blkdev->mode, "w") == 0) { - qflags |= BDRV_O_RDWR; - } else { + if (strcmp(blkdev->mode, "w")) { info |= VDISK_READONLY; } @@ -755,6 +752,41 @@ static int blk_init(struct XenDevice *xendev) info |= VDISK_CDROM; } + blkdev->file_blk = BLOCK_SIZE; + + /* fill info + * blk_connect supplies sector-size and sectors + */ + xenstore_write_be_int(&blkdev->xendev, "feature-flush-cache", 1); + xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1); + xenstore_write_be_int(&blkdev->xendev, "info", info); + return 0; + +out_error: + g_free(blkdev->params); + blkdev->params = NULL; + g_free(blkdev->mode); + blkdev->mode = NULL; + g_free(blkdev->type); + blkdev->type = NULL; + g_free(blkdev->dev); + blkdev->dev = NULL; + g_free(blkdev->devtype); + blkdev->devtype = NULL; + return -1; +} + +static int blk_connect(struct XenDevice *xendev) +{ + struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); + int pers, index, qflags; + + /* read-only ? */ + qflags = BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO; + if (strcmp(blkdev->mode, "w") == 0) { + qflags |= BDRV_O_RDWR; + } + /* init qemu block driver */ index = (blkdev->xendev.dev - 202 * 256) / 16; blkdev->dinfo = drive_get(IF_XEN, 0, index); @@ -770,7 +802,7 @@ static int blk_init(struct XenDevice *xendev) } } if (!blkdev->bs) { - goto out_error; + return -1; } } else { /* setup via qemu cmdline -> already setup for us */ @@ -778,7 +810,6 @@ static int blk_init(struct XenDevice *xendev) blkdev->bs = blkdev->dinfo->bdrv; } bdrv_attach_dev_nofail(blkdev->bs, blkdev); - blkdev->file_blk = BLOCK_SIZE; blkdev->file_size = bdrv_getlength(blkdev->bs); if (blkdev->file_size < 0) { xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n", @@ -792,33 +823,10 @@ static int blk_init(struct XenDevice *xendev) blkdev->type, blkdev->fileproto, blkdev->filename, blkdev->file_size, blkdev->file_size >> 20); - /* fill info */ - xenstore_write_be_int(&blkdev->xendev, "feature-flush-cache", 1); - xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1); - xenstore_write_be_int(&blkdev->xendev, "info", info); - xenstore_write_be_int(&blkdev->xendev, "sector-size", blkdev->file_blk); - xenstore_write_be_int(&blkdev->xendev, "sectors", - blkdev->file_size / blkdev->file_blk); - return 0; - -out_error: - g_free(blkdev->params); - blkdev->params = NULL; - g_free(blkdev->mode); - blkdev->mode = NULL; - g_free(blkdev->type); - blkdev->type = NULL; - g_free(blkdev->dev); - blkdev->dev = NULL; - g_free(blkdev->devtype); - blkdev->devtype = NULL; - return -1; -} - -static int blk_connect(struct XenDevice *xendev) -{ - struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); - int pers; + /* Fill in number of sector size and number of sectors */ + xenstore_write_be_int(&blkdev->xendev, "sector-size", blkdev->file_blk); + xenstore_write_be_int64(&blkdev->xendev, "sectors", + blkdev->file_size / blkdev->file_blk); if (xenstore_read_fe_int(&blkdev->xendev, "ring-ref", &blkdev->ring_ref) == -1) { return -1; diff --git a/include/block/block_int.h b/include/block/block_int.h index 0986a2d6ac..9aa98b5d12 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -252,11 +252,10 @@ struct BlockDriverState { unsigned int copy_on_read_in_flight; /* the time for latest disk I/O */ - int64_t slice_time; int64_t slice_start; int64_t slice_end; BlockIOLimit io_limits; - BlockIOBaseValue io_base; + BlockIOBaseValue slice_submitted; CoQueue throttled_reqs; QEMUTimer *block_timer; bool io_limits_enabled; diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h index 0e690f4849..1bc3666107 100644 --- a/include/qapi/qmp/qstring.h +++ b/include/qapi/qmp/qstring.h @@ -26,6 +26,7 @@ typedef struct QString { QString *qstring_new(void); QString *qstring_from_str(const char *str); QString *qstring_from_substr(const char *str, int start, int end); +size_t qstring_get_length(const QString *qstring); const char *qstring_get_str(const QString *qstring); void qstring_append_int(QString *qstring, int64_t value); void qstring_append(QString *qstring, const char *str); diff --git a/linux-user/strace.c b/linux-user/strace.c index 0fbae3c2f6..ea6c1d24e6 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -143,7 +143,7 @@ print_signal(abi_ulong arg, int last) case TARGET_SIGTTOU: signal_name = "SIGTTOU"; break; } if (signal_name == NULL) { - print_raw_param("%ld", arg, 1); + print_raw_param("%ld", arg, last); return; } gemu_log("%s%s", signal_name, get_comma(last)); diff --git a/main-loop.c b/main-loop.c index eb80ff369f..f46aece8b8 100644 --- a/main-loop.c +++ b/main-loop.c @@ -188,14 +188,39 @@ static void glib_pollfds_poll(void) } } +#define MAX_MAIN_LOOP_SPIN (1000) + static int os_host_main_loop_wait(uint32_t timeout) { int ret; + static int spin_counter; glib_pollfds_fill(&timeout); + /* If the I/O thread is very busy or we are incorrectly busy waiting in + * the I/O thread, this can lead to starvation of the BQL such that the + * VCPU threads never run. To make sure we can detect the later case, + * print a message to the screen. If we run into this condition, create + * a fake timeout in order to give the VCPU threads a chance to run. + */ + if (spin_counter > MAX_MAIN_LOOP_SPIN) { + static bool notified; + + if (!notified) { + fprintf(stderr, + "main-loop: WARNING: I/O thread spun for %d iterations\n", + MAX_MAIN_LOOP_SPIN); + notified = true; + } + + timeout = 1; + } + if (timeout > 0) { + spin_counter = 0; qemu_mutex_unlock_iothread(); + } else { + spin_counter++; } ret = g_poll((GPollFD *)gpollfds->data, gpollfds->len, timeout); @@ -188,8 +188,8 @@ struct Monitor { int reset_seen; int flags; int suspend_cnt; - uint8_t outbuf[1024]; - int outbuf_index; + bool skip_flush; + QString *outbuf; ReadLineState *rs; MonitorControl *mc; CPUArchState *mon_cpu; @@ -271,45 +271,56 @@ static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond, void monitor_flush(Monitor *mon) { int rc; + size_t len; + const char *buf; + + if (mon->skip_flush) { + return; + } - if (mon && mon->outbuf_index != 0 && !mon->mux_out) { - rc = qemu_chr_fe_write(mon->chr, mon->outbuf, mon->outbuf_index); - if (rc == mon->outbuf_index) { + buf = qstring_get_str(mon->outbuf); + len = qstring_get_length(mon->outbuf); + + if (mon && len && !mon->mux_out) { + rc = qemu_chr_fe_write(mon->chr, (const uint8_t *) buf, len); + if (rc == len) { /* all flushed */ - mon->outbuf_index = 0; + QDECREF(mon->outbuf); + mon->outbuf = qstring_new(); return; } if (rc > 0) { /* partinal write */ - memmove(mon->outbuf, mon->outbuf + rc, mon->outbuf_index - rc); - mon->outbuf_index -= rc; + QString *tmp = qstring_from_str(buf + rc); + QDECREF(mon->outbuf); + mon->outbuf = tmp; } qemu_chr_fe_add_watch(mon->chr, G_IO_OUT, monitor_unblocked, mon); } } -/* flush at every end of line or if the buffer is full */ +/* flush at every end of line */ static void monitor_puts(Monitor *mon, const char *str) { char c; for(;;) { - assert(mon->outbuf_index < sizeof(mon->outbuf) - 1); c = *str++; if (c == '\0') break; - if (c == '\n') - mon->outbuf[mon->outbuf_index++] = '\r'; - mon->outbuf[mon->outbuf_index++] = c; - if (mon->outbuf_index >= (sizeof(mon->outbuf) - 1) - || c == '\n') + if (c == '\n') { + qstring_append_chr(mon->outbuf, '\r'); + } + qstring_append_chr(mon->outbuf, c); + if (c == '\n') { monitor_flush(mon); + } } } void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { - char buf[4096]; + char *buf; if (!mon) return; @@ -318,8 +329,9 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) return; } - vsnprintf(buf, sizeof(buf), fmt, ap); + buf = g_strdup_vprintf(fmt, ap); monitor_puts(mon, buf); + g_free(buf); } void monitor_printf(Monitor *mon, const char *fmt, ...) @@ -668,11 +680,10 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, { char *output = NULL; Monitor *old_mon, hmp; - CharDriverState mchar; memset(&hmp, 0, sizeof(hmp)); - qemu_chr_init_mem(&mchar); - hmp.chr = &mchar; + hmp.outbuf = qstring_new(); + hmp.skip_flush = true; old_mon = cur_mon; cur_mon = &hmp; @@ -690,16 +701,14 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, handle_user_command(&hmp, command_line); cur_mon = old_mon; - if (qemu_chr_mem_osize(hmp.chr) > 0) { - QString *str = qemu_chr_mem_to_qs(hmp.chr); - output = g_strdup(qstring_get_str(str)); - QDECREF(str); + if (qstring_get_length(hmp.outbuf) > 0) { + output = g_strdup(qstring_get_str(hmp.outbuf)); } else { output = g_strdup(""); } out: - qemu_chr_close_mem(hmp.chr); + QDECREF(hmp.outbuf); return output; } @@ -4749,6 +4758,7 @@ void monitor_init(CharDriverState *chr, int flags) } mon = g_malloc0(sizeof(*mon)); + mon->outbuf = qstring_new(); mon->chr = chr; mon->flags = flags; diff --git a/qemu-char.c b/qemu-char.c index e5eb8dd2ef..dd410ce40f 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -594,65 +594,51 @@ int recv_all(int fd, void *_buf, int len1, bool single_read) typedef struct IOWatchPoll { + GSource parent; + GSource *src; - int max_size; IOCanReadHandler *fd_can_read; void *opaque; - - QTAILQ_ENTRY(IOWatchPoll) node; } IOWatchPoll; -static QTAILQ_HEAD(, IOWatchPoll) io_watch_poll_list = - QTAILQ_HEAD_INITIALIZER(io_watch_poll_list); - static IOWatchPoll *io_watch_poll_from_source(GSource *source) { - IOWatchPoll *i; - - QTAILQ_FOREACH(i, &io_watch_poll_list, node) { - if (i->src == source) { - return i; - } - } - - return NULL; + return container_of(source, IOWatchPoll, parent); } static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_) { IOWatchPoll *iwp = io_watch_poll_from_source(source); - - iwp->max_size = iwp->fd_can_read(iwp->opaque); - if (iwp->max_size == 0) { + bool now_active = iwp->fd_can_read(iwp->opaque) > 0; + bool was_active = g_source_get_context(iwp->src) != NULL; + if (was_active == now_active) { return FALSE; } - return g_io_watch_funcs.prepare(source, timeout_); + if (now_active) { + g_source_attach(iwp->src, NULL); + } else { + g_source_remove(g_source_get_id(iwp->src)); + } + return FALSE; } static gboolean io_watch_poll_check(GSource *source) { - IOWatchPoll *iwp = io_watch_poll_from_source(source); - - if (iwp->max_size == 0) { - return FALSE; - } - - return g_io_watch_funcs.check(source); + return FALSE; } static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) { - return g_io_watch_funcs.dispatch(source, callback, user_data); + abort(); } static void io_watch_poll_finalize(GSource *source) { IOWatchPoll *iwp = io_watch_poll_from_source(source); - QTAILQ_REMOVE(&io_watch_poll_list, iwp, node); - g_io_watch_funcs.finalize(source); + g_source_unref(iwp->src); } static GSourceFuncs io_watch_poll_funcs = { @@ -669,24 +655,14 @@ static guint io_add_watch_poll(GIOChannel *channel, gpointer user_data) { IOWatchPoll *iwp; - GSource *src; - guint tag; - src = g_io_create_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP); - g_source_set_funcs(src, &io_watch_poll_funcs); - g_source_set_callback(src, (GSourceFunc)fd_read, user_data, NULL); - tag = g_source_attach(src, NULL); - g_source_unref(src); - - iwp = g_malloc0(sizeof(*iwp)); - iwp->src = src; - iwp->max_size = 0; + iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs, sizeof(IOWatchPoll)); iwp->fd_can_read = fd_can_read; iwp->opaque = user_data; + iwp->src = g_io_create_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP); + g_source_set_callback(iwp->src, (GSourceFunc)fd_read, user_data, NULL); - QTAILQ_INSERT_HEAD(&io_watch_poll_list, iwp, node); - - return tag; + return g_source_attach(&iwp->parent, NULL); } #ifndef _WIN32 @@ -2796,70 +2772,6 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) return NULL; } -/***********************************************************/ -/* Memory chardev */ -typedef struct { - size_t outbuf_size; - size_t outbuf_capacity; - uint8_t *outbuf; -} MemoryDriver; - -static int mem_chr_write(CharDriverState *chr, const uint8_t *buf, int len) -{ - MemoryDriver *d = chr->opaque; - - /* TODO: the QString implementation has the same code, we should - * introduce a generic way to do this in cutils.c */ - if (d->outbuf_capacity < d->outbuf_size + len) { - /* grow outbuf */ - d->outbuf_capacity += len; - d->outbuf_capacity *= 2; - d->outbuf = g_realloc(d->outbuf, d->outbuf_capacity); - } - - memcpy(d->outbuf + d->outbuf_size, buf, len); - d->outbuf_size += len; - - return len; -} - -void qemu_chr_init_mem(CharDriverState *chr) -{ - MemoryDriver *d; - - d = g_malloc(sizeof(*d)); - d->outbuf_size = 0; - d->outbuf_capacity = 4096; - d->outbuf = g_malloc0(d->outbuf_capacity); - - memset(chr, 0, sizeof(*chr)); - chr->opaque = d; - chr->chr_write = mem_chr_write; -} - -QString *qemu_chr_mem_to_qs(CharDriverState *chr) -{ - MemoryDriver *d = chr->opaque; - return qstring_from_substr((char *) d->outbuf, 0, d->outbuf_size - 1); -} - -/* NOTE: this driver can not be closed with qemu_chr_delete()! */ -void qemu_chr_close_mem(CharDriverState *chr) -{ - MemoryDriver *d = chr->opaque; - - g_free(d->outbuf); - g_free(chr->opaque); - chr->opaque = NULL; - chr->chr_write = NULL; -} - -size_t qemu_chr_mem_osize(const CharDriverState *chr) -{ - const MemoryDriver *d = chr->opaque; - return d->outbuf_size; -} - /*********************************************************/ /* Ring buffer chardev */ diff --git a/qobject/qstring.c b/qobject/qstring.c index 5f7376c336..607b7a142c 100644 --- a/qobject/qstring.c +++ b/qobject/qstring.c @@ -32,6 +32,14 @@ QString *qstring_new(void) } /** + * qstring_get_length(): Get the length of a QString + */ +size_t qstring_get_length(const QString *qstring) +{ + return qstring->length; +} + +/** * qstring_from_substr(): Create a new QString from a C string substring * * Return string reference diff --git a/target-s390x/translate.c b/target-s390x/translate.c index a4f2194ec7..0c3cf68e1d 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -3088,6 +3088,7 @@ static ExitStatus op_srnm(DisasContext *s, DisasOps *o) break; case 0xb9: /* SRNMT */ pos = 4, len = 3; + break; default: tcg_abort(); } diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c index 3c6b8df607..e84926f97c 100644 --- a/tests/test-visitor-serialization.c +++ b/tests/test-visitor-serialization.c @@ -258,6 +258,7 @@ static void test_primitives(gconstpointer opaque) g_assert(pt_copy != NULL); if (pt->type == PTYPE_STRING) { g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string); + g_free((char *)pt_copy->value.string); } else if (pt->type == PTYPE_NUMBER) { /* we serialize with %f for our reference visitors, so rather than fuzzy * floating math to test "equality", just compare the formatted values @@ -275,6 +276,7 @@ static void test_primitives(gconstpointer opaque) ops->cleanup(serialize_data); g_free(args); + g_free(pt_copy); } static void test_struct(gconstpointer opaque) @@ -660,6 +662,7 @@ static void qmp_deserialize(void **native_out, void *datap, QDECREF(output_json); d->qiv = qmp_input_visitor_new(obj); + qobject_decref(obj); visit(qmp_input_get_visitor(d->qiv), native_out, errp); } @@ -668,9 +671,12 @@ static void qmp_cleanup(void *datap) QmpSerializeData *d = datap; qmp_output_visitor_cleanup(d->qov); qmp_input_visitor_cleanup(d->qiv); + + g_free(d); } typedef struct StringSerializeData { + char *string; StringOutputVisitor *sov; StringInputVisitor *siv; } StringSerializeData; @@ -690,15 +696,19 @@ static void string_deserialize(void **native_out, void *datap, { StringSerializeData *d = datap; - d->siv = string_input_visitor_new(string_output_get_string(d->sov)); + d->string = string_output_get_string(d->sov); + d->siv = string_input_visitor_new(d->string); visit(string_input_get_visitor(d->siv), native_out, errp); } static void string_cleanup(void *datap) { StringSerializeData *d = datap; + string_output_visitor_cleanup(d->sov); string_input_visitor_cleanup(d->siv); + g_free(d->string); + g_free(d); } /* visitor registration, test harness */ |