Commit 96637bcd authored by Luiz Capitulino's avatar Luiz Capitulino
Browse files

qapi: Convert query-balloon



Please, note that some of the code supporting memory statistics is
still around (eg. virtio_balloon_receive_stats() and reset_stats()).

Also, the qmp_query_balloon() function is synchronous and thus doesn't
make any use of the (not fully working) monitor's asynchronous command
support (the old non-qapi implementation did).

Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>
Signed-off-by: default avatarLuiz Capitulino <lcapitulino@redhat.com>
parent d1f29646
Loading
Loading
Loading
Loading
+14 −58
Original line number Diff line number Diff line
@@ -25,12 +25,11 @@
 */

#include "monitor.h"
#include "qjson.h"
#include "qint.h"
#include "cpu-common.h"
#include "kvm.h"
#include "balloon.h"
#include "trace.h"
#include "qmp-commands.h"

static QEMUBalloonEvent *balloon_event_fn;
static QEMUBalloonStatus *balloon_stat_fn;
@@ -72,76 +71,33 @@ static int qemu_balloon(ram_addr_t target)
    return 1;
}

static int qemu_balloon_status(MonitorCompletion cb, void *opaque)
static int qemu_balloon_status(BalloonInfo *info)
{
    if (!balloon_stat_fn) {
        return 0;
    }
    balloon_stat_fn(balloon_opaque, cb, opaque);
    balloon_stat_fn(balloon_opaque, info);
    return 1;
}

static void print_balloon_stat(const char *key, QObject *obj, void *opaque)
BalloonInfo *qmp_query_balloon(Error **errp)
{
    Monitor *mon = opaque;

    if (strcmp(key, "actual")) {
        monitor_printf(mon, ",%s=%" PRId64, key,
                       qint_get_int(qobject_to_qint(obj)));
    }
}

void monitor_print_balloon(Monitor *mon, const QObject *data)
{
    QDict *qdict;

    qdict = qobject_to_qdict(data);
    if (!qdict_haskey(qdict, "actual")) {
        return;
    }
    monitor_printf(mon, "balloon: actual=%" PRId64,
                   qdict_get_int(qdict, "actual") >> 20);
    qdict_iter(qdict, print_balloon_stat, mon);
    monitor_printf(mon, "\n");
}

/**
 * do_info_balloon(): Balloon information
 *
 * Make an asynchronous request for balloon info.  When the request completes
 * a QDict will be returned according to the following specification:
 *
 * - "actual": current balloon value in bytes
 * The following fields may or may not be present:
 * - "mem_swapped_in": Amount of memory swapped in (bytes)
 * - "mem_swapped_out": Amount of memory swapped out (bytes)
 * - "major_page_faults": Number of major faults
 * - "minor_page_faults": Number of minor faults
 * - "free_mem": Total amount of free and unused memory (bytes)
 * - "total_mem": Total amount of available memory (bytes)
 *
 * Example:
 *
 * { "actual": 1073741824, "mem_swapped_in": 0, "mem_swapped_out": 0,
 *   "major_page_faults": 142, "minor_page_faults": 239245,
 *   "free_mem": 1014185984, "total_mem": 1044668416 }
 */
int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque)
{
    int ret;
    BalloonInfo *info;

    if (kvm_enabled() && !kvm_has_sync_mmu()) {
        qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
        return -1;
        error_set(errp, QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
        return NULL;
    }

    ret = qemu_balloon_status(cb, opaque);
    if (!ret) {
        qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
        return -1;
    info = g_malloc0(sizeof(*info));

    if (qemu_balloon_status(info) == 0) {
        error_set(errp, QERR_DEVICE_NOT_ACTIVE, "balloon");
        qapi_free_BalloonInfo(info);
        return NULL;
    }

    return 0;
    return info;
}

/**
+2 −4
Original line number Diff line number Diff line
@@ -15,17 +15,15 @@
#define _QEMU_BALLOON_H

#include "monitor.h"
#include "qapi-types.h"

typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
typedef void (QEMUBalloonStatus)(void *opaque, MonitorCompletion cb,
                                 void *cb_data);
typedef void (QEMUBalloonStatus)(void *opaque, BalloonInfo *info);

int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
			     QEMUBalloonStatus *stat_func, void *opaque);
void qemu_remove_balloon_handler(void *opaque);

void monitor_print_balloon(Monitor *mon, const QObject *data);
int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque);
int do_balloon(Monitor *mon, const QDict *params,
               MonitorCompletion cb, void *opaque);

+39 −0
Original line number Diff line number Diff line
@@ -349,6 +349,45 @@ out:
    qapi_free_SpiceInfo(info);
}

void hmp_info_balloon(Monitor *mon)
{
    BalloonInfo *info;
    Error *err = NULL;

    info = qmp_query_balloon(&err);
    if (err) {
        monitor_printf(mon, "%s\n", error_get_pretty(err));
        error_free(err);
        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");

    qapi_free_BalloonInfo(info);
}

void hmp_quit(Monitor *mon, const QDict *qdict)
{
    monitor_suspend(mon);
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ void hmp_info_block(Monitor *mon);
void hmp_info_blockstats(Monitor *mon);
void hmp_info_vnc(Monitor *mon);
void hmp_info_spice(Monitor *mon);
void hmp_info_balloon(Monitor *mon);
void hmp_quit(Monitor *mon, const QDict *qdict);
void hmp_stop(Monitor *mon, const QDict *qdict);
void hmp_system_reset(Monitor *mon, const QDict *qdict);
+14 −64
Original line number Diff line number Diff line
@@ -18,22 +18,14 @@
#include "virtio.h"
#include "pc.h"
#include "cpu.h"
#include "monitor.h"
#include "balloon.h"
#include "virtio-balloon.h"
#include "kvm.h"
#include "qlist.h"
#include "qint.h"
#include "qstring.h"

#if defined(__linux__)
#include <sys/mman.h>
#endif

/* Disable guest-provided stats by now (https://bugzilla.redhat.com/show_bug.cgi?id=623903) */
#define ENABLE_GUEST_STATS   0


typedef struct VirtIOBalloon
{
    VirtIODevice vdev;
@@ -43,8 +35,6 @@ typedef struct VirtIOBalloon
    uint64_t stats[VIRTIO_BALLOON_S_NR];
    VirtQueueElement stats_vq_elem;
    size_t stats_vq_offset;
    MonitorCompletion *stats_callback;
    void *stats_opaque_callback_data;
    DeviceState *qdev;
} VirtIOBalloon;

@@ -76,31 +66,6 @@ static inline void reset_stats(VirtIOBalloon *dev)
    for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1);
}

static void stat_put(QDict *dict, const char *label, uint64_t val)
{
    if (val != -1)
        qdict_put(dict, label, qint_from_int(val));
}

static QObject *get_stats_qobject(VirtIOBalloon *dev)
{
    QDict *dict = qdict_new();
    uint64_t actual = ram_size - ((uint64_t) dev->actual <<
                                  VIRTIO_BALLOON_PFN_SHIFT);

    stat_put(dict, "actual", actual);
#if ENABLE_GUEST_STATS
    stat_put(dict, "mem_swapped_in", dev->stats[VIRTIO_BALLOON_S_SWAP_IN]);
    stat_put(dict, "mem_swapped_out", dev->stats[VIRTIO_BALLOON_S_SWAP_OUT]);
    stat_put(dict, "major_page_faults", dev->stats[VIRTIO_BALLOON_S_MAJFLT]);
    stat_put(dict, "minor_page_faults", dev->stats[VIRTIO_BALLOON_S_MINFLT]);
    stat_put(dict, "free_mem", dev->stats[VIRTIO_BALLOON_S_MEMFREE]);
    stat_put(dict, "total_mem", dev->stats[VIRTIO_BALLOON_S_MEMTOT]);
#endif

    return QOBJECT(dict);
}

static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
    VirtIOBalloon *s = to_virtio_balloon(vdev);
@@ -131,20 +96,6 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
    }
}

static void complete_stats_request(VirtIOBalloon *vb)
{
    QObject *stats;

    if (!vb->stats_opaque_callback_data)
        return;

    stats = get_stats_qobject(vb);
    vb->stats_callback(vb->stats_opaque_callback_data, stats);
    qobject_decref(stats);
    vb->stats_opaque_callback_data = NULL;
    vb->stats_callback = NULL;
}

static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
{
    VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
@@ -172,8 +123,6 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
            s->stats[tag] = val;
    }
    s->stats_vq_offset = offset;

    complete_stats_request(s);
}

static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
@@ -202,32 +151,33 @@ static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
    return f;
}

static void virtio_balloon_stat(void *opaque, MonitorCompletion cb,
                                void *cb_data)
static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
{
    VirtIOBalloon *dev = opaque;

    /* For now, only allow one request at a time.  This restriction can be
     * removed later by queueing callback and data pairs.
#if 0
    /* Disable guest-provided stats for now. For more details please check:
     * https://bugzilla.redhat.com/show_bug.cgi?id=623903
     *
     * If you do enable it (which is probably not going to happen as we
     * need a new command for it), remember that you also need to fill the
     * appropriate members of the BalloonInfo structure so that the stats
     * are returned to the client.
     */
    if (dev->stats_callback != NULL) {
        return;
    }
    dev->stats_callback = cb;
    dev->stats_opaque_callback_data = cb_data;

    if (ENABLE_GUEST_STATS
        && (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) {
    if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) {
        virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
        virtio_notify(&dev->vdev, dev->svq);
        return;
    }
#endif

    /* Stats are not supported.  Clear out any stale values that might
     * have been set by a more featureful guest kernel.
     */
    reset_stats(dev);
    complete_stats_request(dev);

    info->actual = ram_size - ((uint64_t) dev->actual <<
                               VIRTIO_BALLOON_PFN_SHIFT);
}

static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
Loading