Commit 6cebf7af authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote-tracking branch 'luiz/queue/qmp' into staging

# By Lei Li (3) and others
# Via Luiz Capitulino
* luiz/queue/qmp:
  QAPI: Introduce memchar-read QMP command
  QAPI: Introduce memchar-write QMP command
  qemu-char: Add new char backend CirMemCharDriver
  docs: document virtio-balloon stats
  balloon: re-enable balloon stats
  balloon: drop old stats code & API
  block: Monitor command commit neglects to report some errors
parents 6034fe7b 49b6d722
Loading
Loading
Loading
Loading
+5 −9
Original line number Diff line number Diff line
@@ -642,21 +642,17 @@ void do_commit(Monitor *mon, const QDict *qdict)

    if (!strcmp(device, "all")) {
        ret = bdrv_commit_all();
        if (ret == -EBUSY) {
            qerror_report(QERR_DEVICE_IN_USE, device);
            return;
        }
    } else {
        bs = bdrv_find(device);
        if (!bs) {
            qerror_report(QERR_DEVICE_NOT_FOUND, device);
            monitor_printf(mon, "Device '%s' not found\n", device);
            return;
        }
        ret = bdrv_commit(bs);
        if (ret == -EBUSY) {
            qerror_report(QERR_DEVICE_IN_USE, device);
            return;
    }
    if (ret < 0) {
        monitor_printf(mon, "'commit' error for '%s': %s\n", device,
                       strerror(-ret));
    }
}

+104 −0
Original line number Diff line number Diff line
virtio balloon memory statistics
================================

The virtio balloon driver supports guest memory statistics reporting. These
statistics are available to QEMU users as QOM (QEMU Object Model) device
properties via a polling mechanism.

Before querying the available stats, clients first have to enable polling.
This is done by writing a time interval value (in seconds) to the
guest-stats-polling-interval property. This value can be:

  > 0  enables polling in the specified interval. If polling is already
       enabled, the polling time interval is changed to the new value

  0    disables polling. Previous polled statistics are still valid and
       can be queried.

Once polling is enabled, the virtio-balloon device in QEMU will start
polling the guest's balloon driver for new stats in the specified time
interval.

To retrieve those stats, clients have to query the guest-stats property,
which will return a dictionary containing:

  o A key named 'stats', containing all available stats. If the guest
    doesn't support a particular stat, or if it couldn't be retrieved,
    its value will be -1. Currently, the following stats are supported:

      - stat-swap-in
      - stat-swap-out
      - stat-major-faults
      - stat-minor-faults
      - stat-free-memory
      - stat-total-memory

  o A key named last-update, which contains the last stats update
    timestamp in seconds. Since this timestamp is generated by the host,
    a buggy guest can't influence its value

It's also important to note the following:

 - Previously polled statistics remain available even if the polling is
   later disabled

 - As noted above, if a guest doesn't support a particular stat its value
   will always be -1. However, it's also possible that a guest temporarily
   couldn't update one or even all stats. If this happens, just wait for
   the next update

 - Polling can be enabled even if the guest doesn't have stats support
   or the balloon driver wasn't loaded in the guest. If this is the case
   and stats are queried, an error will be returned

 - The polling timer is only re-armed when the guest responds to the
   statistics request. This means that if a (buggy) guest doesn't ever
   respond to the request the timer will never be re-armed, which has
   the same effect as disabling polling

Here are a few examples. QEMU is started with '-balloon virtio', which
generates '/machine/peripheral-anon/device[1]' as the QOM path for the
balloon device.

Enable polling with 2 seconds interval:

{ "execute": "qom-set",
             "arguments": { "path": "/machine/peripheral-anon/device[1]",
			 "property": "guest-stats-polling-interval", "value": 2 } }

{ "return": {} }

Change polling to 10 seconds:

{ "execute": "qom-set",
             "arguments": { "path": "/machine/peripheral-anon/device[1]",
			 "property": "guest-stats-polling-interval", "value": 10 } }

{ "return": {} }

Get stats:

{ "execute": "qom-get",
  "arguments": { "path": "/machine/peripheral-anon/device[1]",
  "property": "guest-stats" } }
{
    "return": {
        "stats": {
            "stat-swap-out": 0,
            "stat-free-memory": 844943360,
            "stat-minor-faults": 219028,
            "stat-major-faults": 235,
            "stat-total-memory": 1044406272,
            "stat-swap-in": 0
        },
        "last-update": 1358529861
    }
}

Disable polling:

{ "execute": "qom-set",
             "arguments": { "path": "/machine/peripheral-anon/device[1]",
			 "property": "stats-polling-interval", "value": 0 } }

{ "return": {} }
+39 −0
Original line number Diff line number Diff line
@@ -837,6 +837,45 @@ STEXI
@item nmi @var{cpu}
@findex nmi
Inject an NMI on the given CPU (x86 only).

ETEXI

    {
        .name       = "memchar_write",
        .args_type  = "device:s,data:s",
        .params     = "device data",
        .help       = "Provide writing interface for CirMemCharDriver. Write"
                      "'data' to it.",
        .mhandler.cmd = hmp_memchar_write,
    },

STEXI
@item memchar_write @var{device} @var{data}
@findex memchar_write
Provide writing interface for CirMemCharDriver. Write @var{data}
to char device 'memory'.

ETEXI

    {
        .name       = "memchar_read",
        .args_type  = "device:s,size:i",
        .params     = "device size",
        .help       = "Provide read interface for CirMemCharDriver. Read from"
                      "it and return the data with size.",
        .mhandler.cmd = hmp_memchar_read,
    },

STEXI
@item memchar_read @var{device}
@findex memchar_read
Provide read interface for CirMemCharDriver. Read from char device
'memory' and return the data.

@var{size} is the size of data want to read from. Refer to unencoded
size of the raw data, would adjust to the init size of the memchar
if the requested size is larger than it.

ETEXI

    {
+35 −23
Original line number Diff line number Diff line
@@ -465,29 +465,7 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict)
        return;
    }

    monitor_printf(mon, "balloon: actual=%" PRId64, info->actual >> 20);
    if (info->has_mem_swapped_in) {
        monitor_printf(mon, " mem_swapped_in=%" PRId64, info->mem_swapped_in);
    }
    if (info->has_mem_swapped_out) {
        monitor_printf(mon, " mem_swapped_out=%" PRId64, info->mem_swapped_out);
    }
    if (info->has_major_page_faults) {
        monitor_printf(mon, " major_page_faults=%" PRId64,
                       info->major_page_faults);
    }
    if (info->has_minor_page_faults) {
        monitor_printf(mon, " minor_page_faults=%" PRId64,
                       info->minor_page_faults);
    }
    if (info->has_free_mem) {
        monitor_printf(mon, " free_mem=%" PRId64, info->free_mem);
    }
    if (info->has_total_mem) {
        monitor_printf(mon, " total_mem=%" PRId64, info->total_mem);
    }

    monitor_printf(mon, "\n");
    monitor_printf(mon, "balloon: actual=%" PRId64 "\n", info->actual >> 20);

    qapi_free_BalloonInfo(info);
}
@@ -684,6 +662,40 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict)
    hmp_handle_error(mon, &errp);
}

void hmp_memchar_write(Monitor *mon, const QDict *qdict)
{
    uint32_t size;
    const char *chardev = qdict_get_str(qdict, "device");
    const char *data = qdict_get_str(qdict, "data");
    Error *errp = NULL;

    size = strlen(data);
    qmp_memchar_write(chardev, size, data, false, 0, &errp);

    hmp_handle_error(mon, &errp);
}

void hmp_memchar_read(Monitor *mon, const QDict *qdict)
{
    uint32_t size = qdict_get_int(qdict, "size");
    const char *chardev = qdict_get_str(qdict, "device");
    MemCharRead *meminfo;
    Error *errp = NULL;

    meminfo = qmp_memchar_read(chardev, size, false, 0, &errp);
    if (errp) {
        monitor_printf(mon, "%s\n", error_get_pretty(errp));
        error_free(errp);
        return;
    }

    if (meminfo->count > 0) {
        monitor_printf(mon, "%s\n", meminfo->data);
    }

    qapi_free_MemCharRead(meminfo);
}

static void hmp_cont_cb(void *opaque, int err)
{
    if (!err) {
+2 −0
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@ void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
void hmp_cpu(Monitor *mon, const QDict *qdict);
void hmp_memsave(Monitor *mon, const QDict *qdict);
void hmp_pmemsave(Monitor *mon, const QDict *qdict);
void hmp_memchar_write(Monitor *mon, const QDict *qdict);
void hmp_memchar_read(Monitor *mon, const QDict *qdict);
void hmp_cont(Monitor *mon, const QDict *qdict);
void hmp_system_wakeup(Monitor *mon, const QDict *qdict);
void hmp_inject_nmi(Monitor *mon, const QDict *qdict);
Loading