qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
To: Stefan Hajnoczi <stefanha@redhat.com>
Cc: qemu-devel <qemu-devel@nongnu.org>, Kevin Wolf <kwolf@redhat.com>,
	Alberto Garcia <berto@igalia.com>,
	qemu-block <qemu-block@nongnu.org>
Subject: Re: [Qemu-devel] [PATCH 4/7] block: convert ThrottleGroup to object with QOM
Date: Tue, 25 Jul 2017 13:29:08 +0300	[thread overview]
Message-ID: <20170725102908.6bwzz543pfi7ef7z@postretch> (raw)
In-Reply-To: <20170724151247.GJ2784@stefanha-x1.localdomain>

[-- Attachment #1: Type: text/plain, Size: 44556 bytes --]

On Mon, Jul 24, 2017 at 04:12:47PM +0100, Stefan Hajnoczi wrote:
>On Fri, Jul 14, 2017 at 12:45:18PM +0300, Manos Pitsidianakis wrote:
>> ThrottleGroup is converted to an object. This will allow the future
>> throttle block filter drive easy creation and configuration of throttle
>> groups in QMP and cli.
>>
>> A new QAPI struct, ThrottleLimits, is introduced to provide a shared
>> struct for all throttle configuration needs in QMP.
>>
>> ThrottleGroups can be created via CLI as
>>     -object throttling-group,id=foo,x-iops-total=100,x-..
>
>Please make the QOM name and struct name consistent.  Either
>ThrottleGroup/throttle-group or ThrottlingGroup/throttling-group but not
>ThrottleGroup/throttling-group.

I did this on purpose because current throttling has ThrottleGroup 
internally and throttling.group in the command line. Should we keep this 
only in legacy and make it throttle-group everywhere?

>> where x-* are individual limit properties. Since we can't add non-scalar
>> properties in -object this interface must be used instead. However,
>> setting these properties must be disabled after initialization because
>> certain combinations of limits are forbidden and thus configuration
>> changes should be done in one transaction. The individual properties
>> will go away when support for non-scalar values in CLI is implemented
>> and thus are marked as experimental.
>>
>> ThrottleGroup also has a `limits` property that uses the ThrottleLimits
>> struct.  It can be used to create ThrottleGroups or set the
>> configuration in existing groups as follows:
>>
>> { "execute": "object-add",
>>   "arguments": {
>>     "qom-type": "throttling-group",
>>     "id": "foo",
>>     "props" : {
>>       "limits": {
>>           "iops-total": 100
>>       }
>>     }
>>   }
>> }
>> { "execute" : "qom-set",
>>     "arguments" : {
>>         "path" : "foo",
>>         "property" : "limits",
>>         "value" : {
>>             "iops-total" : 99
>>         }
>>     }
>> }
>>
>> This also means a group's configuration can be fetched with qom-get.
>>
>> ThrottleGroups can be anonymous which means they can't get accessed by
>> other users ie they will always be units instead of group (Because they
>> have one ThrottleGroupMember).
>>
>> Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
>> ---
>>
>> Notes:
>>     Note: I tested Markus Armbruster's patch in <87wp7fghi9.fsf@dusky.pond.sub.org>
>>     on master and I can use this syntax successfuly:
>>     -object '{ "qom-type" : "throttling-group", "id" : "foo", "props" : { "limits" \
>>     : { "iops-total" : 1000 } } }'
>>     If this gets merged using -object will be a little more verbose but at least we
>>     won't have seperate properties, which is a good thing, so the x-* should be
>>     dropped.
>>
>>  block/throttle-groups.c         | 507 +++++++++++++++++++++++++++++++++++++---
>>  include/block/throttle-groups.h |   3 +
>>  include/qemu/throttle-options.h |  59 +++--
>>  include/qemu/throttle.h         |   3 +
>>  qapi/block-core.json            |  45 ++++
>>  tests/test-throttle.c           |   1 +
>>  util/throttle.c                 | 121 ++++++++++
>>  7 files changed, 689 insertions(+), 50 deletions(-)
>>
>> diff --git a/block/throttle-groups.c b/block/throttle-groups.c
>> index f711a3dc62..4d1f82ec06 100644
>> --- a/block/throttle-groups.c
>> +++ b/block/throttle-groups.c
>> @@ -25,9 +25,17 @@
>>  #include "qemu/osdep.h"
>>  #include "sysemu/block-backend.h"
>>  #include "block/throttle-groups.h"
>> +#include "qemu/throttle-options.h"
>>  #include "qemu/queue.h"
>>  #include "qemu/thread.h"
>>  #include "sysemu/qtest.h"
>> +#include "qapi/error.h"
>> +#include "qapi-visit.h"
>> +#include "qom/object.h"
>> +#include "qom/object_interfaces.h"
>> +
>> +static void throttle_group_obj_init(Object *obj);
>> +static void throttle_group_obj_complete(UserCreatable *obj, Error **errp);
>>
>>  /* The ThrottleGroup structure (with its ThrottleState) is shared
>>   * among different ThrottleGroupMembers and it's independent from
>> @@ -54,6 +62,10 @@
>>   * that ThrottleGroupMember has throttled requests in the queue.
>>   */
>>  typedef struct ThrottleGroup {
>> +    Object parent_obj;
>> +
>> +    /* refuse individual property change if initialization is complete */
>> +    bool is_initialized;
>>      char *name; /* This is constant during the lifetime of the group */
>>
>>      QemuMutex lock; /* This lock protects the following four fields */
>> @@ -63,8 +75,7 @@ typedef struct ThrottleGroup {
>>      bool any_timer_armed[2];
>>      QEMUClockType clock_type;
>>
>> -    /* These two are protected by the global throttle_groups_lock */
>> -    unsigned refcount;
>> +    /* This is protected by the global throttle_groups_lock */
>>      QTAILQ_ENTRY(ThrottleGroup) list;
>>  } ThrottleGroup;
>>
>> @@ -77,7 +88,8 @@ static QTAILQ_HEAD(, ThrottleGroup) throttle_groups =
>>   * If no ThrottleGroup is found with the given name a new one is
>>   * created.
>>   *
>> - * @name: the name of the ThrottleGroup
>> + * @name: the name of the ThrottleGroup, NULL means a new anonymous group will
>> + *        be created.
>>   * @ret:  the ThrottleState member of the ThrottleGroup
>>   */
>>  ThrottleState *throttle_group_incref(const char *name)
>> @@ -87,32 +99,30 @@ ThrottleState *throttle_group_incref(const char *name)
>>
>>      qemu_mutex_lock(&throttle_groups_lock);
>>
>> -    /* Look for an existing group with that name */
>> -    QTAILQ_FOREACH(iter, &throttle_groups, list) {
>> -        if (!strcmp(name, iter->name)) {
>> -            tg = iter;
>> -            break;
>> +    if (name) {
>> +        /* Look for an existing group with that name */
>> +        QTAILQ_FOREACH(iter, &throttle_groups, list) {
>> +            if (!g_strcmp0(name, iter->name)) {
>> +                tg = iter;
>> +                break;
>> +            }
>>          }
>>      }
>>
>>      /* Create a new one if not found */
>>      if (!tg) {
>> -        tg = g_new0(ThrottleGroup, 1);
>> +        /* new ThrottleGroup obj will have a refcnt = 1 */
>> +        tg = THROTTLE_GROUP(object_new(TYPE_THROTTLE_GROUP));
>>          tg->name = g_strdup(name);
>> -        tg->clock_type = QEMU_CLOCK_REALTIME;
>> -
>> -        if (qtest_enabled()) {
>> -            /* For testing block IO throttling only */
>> -            tg->clock_type = QEMU_CLOCK_VIRTUAL;
>> -        }
>> -        qemu_mutex_init(&tg->lock);
>> -        throttle_init(&tg->ts);
>> -        QLIST_INIT(&tg->head);
>> -
>> -        QTAILQ_INSERT_TAIL(&throttle_groups, tg, list);
>> +        throttle_group_obj_complete((UserCreatable *)tg, &error_abort);
>>      }
>>
>> -    tg->refcount++;
>> +    qemu_mutex_lock(&tg->lock);
>> +    if (!QLIST_EMPTY(&tg->head)) {
>> +        /* only ref if the group is not empty */
>> +        object_ref(OBJECT(tg));
>> +    }
>> +    qemu_mutex_unlock(&tg->lock);
>>
>>      qemu_mutex_unlock(&throttle_groups_lock);
>>
>> @@ -129,15 +139,7 @@ ThrottleState *throttle_group_incref(const char *name)
>>  void throttle_group_unref(ThrottleState *ts)
>>  {
>>      ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
>> -
>> -    qemu_mutex_lock(&throttle_groups_lock);
>> -    if (--tg->refcount == 0) {
>> -        QTAILQ_REMOVE(&throttle_groups, tg, list);
>> -        qemu_mutex_destroy(&tg->lock);
>> -        g_free(tg->name);
>> -        g_free(tg);
>> -    }
>> -    qemu_mutex_unlock(&throttle_groups_lock);
>> +    object_unref(OBJECT(tg));
>>  }
>>
>>  /* Get the name from a ThrottleGroupMember's group. The name (and the pointer)
>> @@ -572,9 +574,452 @@ void throttle_group_detach_aio_context(ThrottleGroupMember *tgm)
>>      throttle_timers_detach_aio_context(tt);
>>  }
>>
>> +#define DOUBLE 0
>> +#define UINT64 1
>> +#define UNSIGNED 2
>> +
>> +typedef struct {
>> +    BucketType type;
>> +    int data_type;
>> +    ptrdiff_t offset; /* offset in LeakyBucket struct. */
>> +} ThrottleParamInfo;
>> +
>> +static ThrottleParamInfo throttle_iops_total_info = {
>
>These can be made const.  This offers a tiny security benefit because
>.offset will be read-only and therefore cannot be used to overwrite
>arbitrary memory.  Exploits often gain control of execution by first
>overwriting a function pointer or pointer field that they can influence.
>
>Also, how about defining an array and looping over it to avoid
>repetition?
>
>  for (i = 0; i < ARRAY_SIZE(params); i++) {
>      object_class_property_add(klass,
>                                params[i].name,
>                                "int",
>                                throttle_group_get,
>                                throttle_group_set,
>                                NULL, &params[i],
>                                &error_abort);
>  }

Thanks, I will look into factoring these in.

>> +    THROTTLE_OPS_TOTAL, DOUBLE, offsetof(LeakyBucket, avg),
>> +};
>> +
>> +static ThrottleParamInfo throttle_iops_total_max_info = {
>> +    THROTTLE_OPS_TOTAL, DOUBLE, offsetof(LeakyBucket, max),
>> +};
>> +
>> +static ThrottleParamInfo throttle_iops_total_max_length_info = {
>> +    THROTTLE_OPS_TOTAL, UNSIGNED, offsetof(LeakyBucket, burst_length),
>> +};
>> +
>> +static ThrottleParamInfo throttle_iops_read_info = {
>> +    THROTTLE_OPS_READ, DOUBLE, offsetof(LeakyBucket, avg),
>> +};
>> +
>> +static ThrottleParamInfo throttle_iops_read_max_info = {
>> +    THROTTLE_OPS_READ, DOUBLE, offsetof(LeakyBucket, max),
>> +};
>> +
>> +static ThrottleParamInfo throttle_iops_read_max_length_info = {
>> +    THROTTLE_OPS_READ, UNSIGNED, offsetof(LeakyBucket, burst_length),
>> +};
>> +
>> +static ThrottleParamInfo throttle_iops_write_info = {
>> +    THROTTLE_OPS_WRITE, DOUBLE, offsetof(LeakyBucket, avg),
>> +};
>> +
>> +static ThrottleParamInfo throttle_iops_write_max_info = {
>> +    THROTTLE_OPS_WRITE, DOUBLE, offsetof(LeakyBucket, max),
>> +};
>> +
>> +static ThrottleParamInfo throttle_iops_write_max_length_info = {
>> +    THROTTLE_OPS_WRITE, UNSIGNED, offsetof(LeakyBucket, burst_length),
>> +};
>> +
>> +static ThrottleParamInfo throttle_bps_total_info = {
>> +    THROTTLE_BPS_TOTAL, DOUBLE, offsetof(LeakyBucket, avg),
>> +};
>> +
>> +static ThrottleParamInfo throttle_bps_total_max_info = {
>> +    THROTTLE_BPS_TOTAL, DOUBLE, offsetof(LeakyBucket, max),
>> +};
>> +
>> +static ThrottleParamInfo throttle_bps_total_max_length_info = {
>> +    THROTTLE_BPS_TOTAL, UNSIGNED, offsetof(LeakyBucket, burst_length),
>> +};
>> +
>> +static ThrottleParamInfo throttle_bps_read_info = {
>> +    THROTTLE_BPS_READ, DOUBLE, offsetof(LeakyBucket, avg),
>> +};
>> +
>> +static ThrottleParamInfo throttle_bps_read_max_info = {
>> +    THROTTLE_BPS_READ, DOUBLE, offsetof(LeakyBucket, max),
>> +};
>> +
>> +static ThrottleParamInfo throttle_bps_read_max_length_info = {
>> +    THROTTLE_BPS_READ, UNSIGNED, offsetof(LeakyBucket, burst_length),
>> +};
>> +
>> +static ThrottleParamInfo throttle_bps_write_info = {
>> +    THROTTLE_BPS_WRITE, DOUBLE, offsetof(LeakyBucket, avg),
>> +};
>> +
>> +static ThrottleParamInfo throttle_bps_write_max_info = {
>> +    THROTTLE_BPS_WRITE, DOUBLE, offsetof(LeakyBucket, max),
>> +};
>> +
>> +static ThrottleParamInfo throttle_bps_write_max_length_info = {
>> +    THROTTLE_BPS_WRITE, UNSIGNED, offsetof(LeakyBucket, burst_length),
>> +};
>> +
>> +static ThrottleParamInfo throttle_iops_size_info = {
>> +    0, UINT64, offsetof(ThrottleConfig, op_size),
>> +};
>> +
>> +static void throttle_group_obj_init(Object *obj)
>> +{
>> +    ThrottleGroup *tg = THROTTLE_GROUP(obj);
>> +
>> +    tg->clock_type = QEMU_CLOCK_REALTIME;
>> +    if (qtest_enabled()) {
>> +        /* For testing block IO throttling only */
>> +        tg->clock_type = QEMU_CLOCK_VIRTUAL;
>> +    }
>> +    tg->is_initialized = false;
>> +    qemu_mutex_init(&tg->lock);
>> +    throttle_init(&tg->ts);
>> +    QLIST_INIT(&tg->head);
>> +}
>> +
>> +static void throttle_group_obj_complete(UserCreatable *obj, Error **errp)
>> +{
>> +    ThrottleGroup *tg = THROTTLE_GROUP(obj), *iter;
>> +    ThrottleConfig *cfg = &tg->ts.cfg;
>> +
>> +    /* set group name to object id if it exists */
>> +    if (!tg->name && tg->parent_obj.parent) {
>> +        tg->name = object_get_canonical_path_component(OBJECT(obj));
>> +    }
>> +
>> +    if (tg->name) {
>> +        /* error if name is duplicate */
>> +        QTAILQ_FOREACH(iter, &throttle_groups, list) {
>> +            if (!g_strcmp0(tg->name, iter->name)) {
>> +                error_setg(errp, "A group with this name already exists");
>> +                goto fail;
>> +            }
>> +        }
>> +    }
>> +
>> +    /* unfix buckets to check validity */
>> +    throttle_get_config(&tg->ts, cfg);
>> +    if (!throttle_is_valid(cfg, errp)) {
>> +        goto fail;
>> +    }
>> +    /* fix buckets again */
>> +    throttle_config(&tg->ts, tg->clock_type, cfg);
>> +
>> +    tg->is_initialized = true;
>> +    QTAILQ_INSERT_TAIL(&throttle_groups, tg, list);
>> +    return;
>> +fail:
>> +    qemu_mutex_destroy(&tg->lock);
>> +    g_free(tg->name);
>
>If throttle_group_obj_finalize() can still be called there will be
>double-frees.  UserCreatable->complete() is not part of the core Object
>lifecycle so I think it could happen and it's safer to leave tg fields
>allocated so that throttle_group_obj_finalize() frees them once and only
>once.

Yeah it seems that it is called on error in QMP with object-add but not 
in CLI, thanks.

>> +}
>> +
>> +static void throttle_group_obj_finalize(Object *obj)
>> +{
>> +    ThrottleGroup *tg = THROTTLE_GROUP(obj);
>> +    qemu_mutex_lock(&throttle_groups_lock);
>> +    QTAILQ_REMOVE(&throttle_groups, tg, list);
>> +    qemu_mutex_unlock(&throttle_groups_lock);
>> +    qemu_mutex_destroy(&tg->lock);
>> +    g_free(tg->name);
>> +}
>> +
>> +static void throttle_group_set(Object *obj, Visitor *v, const char * name,
>> +        void *opaque, Error **errp)
>> +
>> +{
>> +    ThrottleGroup *tg = THROTTLE_GROUP(obj);
>> +    ThrottleConfig cfg;
>> +    ThrottleParamInfo *info = opaque;
>> +    ThrottleLimits *arg = NULL;
>> +    Error *local_err = NULL;
>> +    int64_t value;
>> +
>> +    if (!info) {
>> +        arg = g_new0(ThrottleLimits, 1);
>> +        visit_type_ThrottleLimits(v, name, &arg, &local_err);
>> +        if (local_err) {
>> +            goto fail;
>> +        }
>> +        qemu_mutex_lock(&tg->lock);
>> +        throttle_get_config(&tg->ts, &cfg);
>> +        throttle_limits_to_config(arg, &cfg, &local_err);
>> +        if (local_err) {
>> +            qemu_mutex_unlock(&tg->lock);
>> +            goto fail;
>> +        }
>> +        throttle_config(&tg->ts, tg->clock_type, &cfg);
>> +        qemu_mutex_unlock(&tg->lock);
>> +
>> +        goto ret;
>> +    }
>
>There is no need to share a function between ThrottleLimits and
>individual fields.  The code would be clearer with two separate setter
>functions.  The individual fields removal patch will also be cleaner
>because it just needs to delete lines of code instead of modifying
>throttle_group_set().
>
>> +
>> +    /* If we have finished initialization, don't accept individual property
>> +     * changes through QOM. Throttle configuration limits must be set in one
>> +     * transaction, as certain combinations are invalid.
>> +     */
>> +    if (tg->is_initialized) {
>> +        error_setg(&local_err, "Property cannot be set after initialization");
>> +        goto fail;
>> +    }
>> +
>> +    visit_type_int64(v, name, &value, &local_err);
>> +    if (local_err) {
>> +        goto fail;
>> +    }
>> +    if (value < 0) {
>> +        error_setg(&local_err, "Property value must be in range "
>> +                               "[0, %"PRId64"]", INT64_MAX);
>
>Please print the maximum value relevant to the actual field type instead
>of INT64_MAX.

This checks the limits of the int64 field you give to QOM. I think you 
mean in the value assignment to each field that follows? In any case, 
since unsigned is the only smaller field we could convert it to 
uint64_t/uint32_t internally.

>
>> +        goto fail;
>> +    }
>> +
>> +    cfg = tg->ts.cfg;
>> +    switch (info->data_type) {
>> +    case UINT64:
>> +        {
>> +            uint64_t *field = (void *)&cfg.buckets[info->type] + info->offset;
>> +            *field = value;
>> +        }
>> +        break;
>> +    case DOUBLE:
>> +        {
>> +            double *field = (void *)&cfg.buckets[info->type] + info->offset;
>> +            *field = value;
>> +        }
>> +        break;
>> +    case UNSIGNED:
>> +        {
>> +            unsigned *field = (void *)&cfg.buckets[info->type] + info->offset;
>> +            *field = value;
>> +        }
>> +    }
>> +
>> +    tg->ts.cfg = cfg;
>> +    goto ret;
>> +
>> +fail:
>> +    error_propagate(errp, local_err);
>> +ret:
>> +    g_free(arg);
>> +    return;
>> +
>> +}
>> +
>> +static void throttle_group_get(Object *obj, Visitor *v, const char *name,
>> +        void *opaque, Error **errp)
>> +{
>> +    ThrottleGroup *tg = THROTTLE_GROUP(obj);
>> +    ThrottleConfig cfg;
>> +    ThrottleParamInfo *info = opaque;
>> +    ThrottleLimits *arg = NULL;
>> +    int64_t value;
>> +
>> +    if (!info) {
>> +        arg = g_new0(ThrottleLimits, 1);
>> +        qemu_mutex_lock(&tg->lock);
>> +        throttle_get_config(&tg->ts, &cfg);
>> +        qemu_mutex_unlock(&tg->lock);
>> +        throttle_config_to_throttle_limits(&cfg, arg);
>> +        visit_type_ThrottleLimits(v, name, &arg, errp);
>> +        g_free(arg);
>> +        return;
>> +    }
>> +
>> +    cfg = tg->ts.cfg;
>> +    switch (info->data_type) {
>> +    case UINT64:
>> +        {
>> +            uint64_t *field = (void *)&cfg.buckets[info->type] + info->offset;
>> +            value = *field;
>> +        }
>> +        break;
>> +    case DOUBLE:
>> +        {
>> +            double *field = (void *)&cfg.buckets[info->type] + info->offset;
>> +            value = *field;
>> +        }
>> +        break;
>> +    case UNSIGNED:
>> +        {
>> +            unsigned *field = (void *)&cfg.buckets[info->type] + info->offset;
>> +            value = *field;
>> +        }
>> +    }
>> +
>> +    visit_type_int64(v, name, &value, errp);
>> +}
>> +
>> +#undef THROTTLE_OPT_PREFIX
>> +#define THROTTLE_OPT_PREFIX "x-"
>> +static void throttle_group_obj_class_init(ObjectClass *klass, void *class_data)
>> +{
>> +    UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
>> +
>> +    ucc->complete = throttle_group_obj_complete;
>> +    /* iops limits */
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_iops_total_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL_MAX,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_iops_total_max_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX
>> +                              QEMU_OPT_IOPS_TOTAL_MAX_LENGTH,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_iops_total_max_length_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_iops_read_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ_MAX,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_iops_read_max_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX
>> +                              QEMU_OPT_IOPS_READ_MAX_LENGTH,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_iops_read_max_length_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_iops_write_info, &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE_MAX,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_iops_write_max_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX
>> +                              QEMU_OPT_IOPS_WRITE_MAX_LENGTH,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_iops_write_max_length_info,
>> +                              &error_abort);
>> +    /* bps limits */
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_bps_total_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_bps_total_max_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX
>> +                              QEMU_OPT_BPS_TOTAL_MAX_LENGTH,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_bps_total_max_length_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_bps_read_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_bps_read_max_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX_LENGTH,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_bps_read_max_length_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_bps_write_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_bps_write_max_info,
>> +                              &error_abort);
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX
>> +                              QEMU_OPT_BPS_WRITE_MAX_LENGTH,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_bps_write_max_length_info,
>> +                              &error_abort);
>> +    /* rest */
>> +    object_class_property_add(klass,
>> +                              THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_SIZE,
>> +                              "int",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, &throttle_iops_size_info,
>> +                              &error_abort);
>> +
>> +    /* ThrottleLimits */
>> +    object_class_property_add(klass,
>> +                              "limits", "ThrottleLimits",
>> +                              throttle_group_get,
>> +                              throttle_group_set,
>> +                              NULL, NULL,
>> +                              &error_abort);
>> +}
>> +
>> +static const TypeInfo throttle_group_info = {
>> +   .name = TYPE_THROTTLE_GROUP,
>> +   .parent = TYPE_OBJECT,
>> +   .class_init = throttle_group_obj_class_init,
>> +   .instance_size = sizeof(ThrottleGroup),
>> +   .instance_init = throttle_group_obj_init,
>> +   .instance_finalize = throttle_group_obj_finalize,
>> +   .interfaces = (InterfaceInfo[]) {
>> +       { TYPE_USER_CREATABLE },
>> +       { }
>> +   },
>> +};
>> +
>>  static void throttle_groups_init(void)
>>  {
>>      qemu_mutex_init(&throttle_groups_lock);
>> +    type_register_static(&throttle_group_info);
>>  }
>>
>> -block_init(throttle_groups_init);
>> +type_init(throttle_groups_init);
>> diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
>> index a0f27cac63..096d05ef92 100644
>> --- a/include/block/throttle-groups.h
>> +++ b/include/block/throttle-groups.h
>> @@ -53,6 +53,9 @@ typedef struct ThrottleGroupMember {
>>
>>  } ThrottleGroupMember;
>>
>> +#define TYPE_THROTTLE_GROUP "throttling-group"
>> +#define THROTTLE_GROUP(obj) OBJECT_CHECK(ThrottleGroup, (obj), TYPE_THROTTLE_GROUP)
>> +
>>  const char *throttle_group_get_name(ThrottleGroupMember *tgm);
>>
>>  ThrottleState *throttle_group_incref(const char *name);
>> diff --git a/include/qemu/throttle-options.h b/include/qemu/throttle-options.h
>> index 3133d1ca40..182b7896e1 100644
>> --- a/include/qemu/throttle-options.h
>> +++ b/include/qemu/throttle-options.h
>> @@ -10,81 +10,102 @@
>>  #ifndef THROTTLE_OPTIONS_H
>>  #define THROTTLE_OPTIONS_H
>>
>> +#define QEMU_OPT_IOPS_TOTAL "iops-total"
>> +#define QEMU_OPT_IOPS_TOTAL_MAX "iops-total-max"
>> +#define QEMU_OPT_IOPS_TOTAL_MAX_LENGTH "iops-total-max-length"
>> +#define QEMU_OPT_IOPS_READ "iops-read"
>> +#define QEMU_OPT_IOPS_READ_MAX "iops-read-max"
>> +#define QEMU_OPT_IOPS_READ_MAX_LENGTH "iops-read-max-length"
>> +#define QEMU_OPT_IOPS_WRITE "iops-write"
>> +#define QEMU_OPT_IOPS_WRITE_MAX "iops-write-max"
>> +#define QEMU_OPT_IOPS_WRITE_MAX_LENGTH "iops-write-max-length"
>> +#define QEMU_OPT_BPS_TOTAL "bps-total"
>> +#define QEMU_OPT_BPS_TOTAL_MAX "bps-total-max"
>> +#define QEMU_OPT_BPS_TOTAL_MAX_LENGTH "bps-total-max-length"
>> +#define QEMU_OPT_BPS_READ "bps-read"
>> +#define QEMU_OPT_BPS_READ_MAX "bps-read-max"
>> +#define QEMU_OPT_BPS_READ_MAX_LENGTH "bps-read-max-length"
>> +#define QEMU_OPT_BPS_WRITE "bps-write"
>> +#define QEMU_OPT_BPS_WRITE_MAX "bps-write-max"
>> +#define QEMU_OPT_BPS_WRITE_MAX_LENGTH "bps-write-max-length"
>> +#define QEMU_OPT_IOPS_SIZE "iops-size"
>> +
>> +#define THROTTLE_OPT_PREFIX "throttling."
>>  #define THROTTLE_OPTS \
>>            { \
>> -            .name = "throttling.iops-total",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "limit total I/O operations per second",\
>>          },{ \
>> -            .name = "throttling.iops-read",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "limit read operations per second",\
>>          },{ \
>> -            .name = "throttling.iops-write",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "limit write operations per second",\
>>          },{ \
>> -            .name = "throttling.bps-total",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "limit total bytes per second",\
>>          },{ \
>> -            .name = "throttling.bps-read",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "limit read bytes per second",\
>>          },{ \
>> -            .name = "throttling.bps-write",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "limit write bytes per second",\
>>          },{ \
>> -            .name = "throttling.iops-total-max",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL_MAX,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "I/O operations burst",\
>>          },{ \
>> -            .name = "throttling.iops-read-max",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ_MAX,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "I/O operations read burst",\
>>          },{ \
>> -            .name = "throttling.iops-write-max",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE_MAX,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "I/O operations write burst",\
>>          },{ \
>> -            .name = "throttling.bps-total-max",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "total bytes burst",\
>>          },{ \
>> -            .name = "throttling.bps-read-max",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "total bytes read burst",\
>>          },{ \
>> -            .name = "throttling.bps-write-max",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "total bytes write burst",\
>>          },{ \
>> -            .name = "throttling.iops-total-max-length",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL_MAX_LENGTH,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "length of the iops-total-max burst period, in seconds",\
>>          },{ \
>> -            .name = "throttling.iops-read-max-length",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ_MAX_LENGTH,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "length of the iops-read-max burst period, in seconds",\
>>          },{ \
>> -            .name = "throttling.iops-write-max-length",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE_MAX_LENGTH,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "length of the iops-write-max burst period, in seconds",\
>>          },{ \
>> -            .name = "throttling.bps-total-max-length",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX_LENGTH,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "length of the bps-total-max burst period, in seconds",\
>>          },{ \
>> -            .name = "throttling.bps-read-max-length",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX_LENGTH,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "length of the bps-read-max burst period, in seconds",\
>>          },{ \
>> -            .name = "throttling.bps-write-max-length",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX_LENGTH,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "length of the bps-write-max burst period, in seconds",\
>>          },{ \
>> -            .name = "throttling.iops-size",\
>> +            .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_SIZE,\
>>              .type = QEMU_OPT_NUMBER,\
>>              .help = "when limiting by iops max size of an I/O in bytes",\
>>          }
>> diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h
>> index d056008c18..17e750b12d 100644
>> --- a/include/qemu/throttle.h
>> +++ b/include/qemu/throttle.h
>> @@ -152,5 +152,8 @@ bool throttle_schedule_timer(ThrottleState *ts,
>>                               bool is_write);
>>
>>  void throttle_account(ThrottleState *ts, bool is_write, uint64_t size);
>> +void throttle_limits_to_config(ThrottleLimits *arg, ThrottleConfig *cfg,
>> +                               Error **errp);
>> +void throttle_config_to_throttle_limits(ThrottleConfig *cfg, ThrottleLimits *var);
>>
>>  #endif
>> diff --git a/qapi/block-core.json b/qapi/block-core.json
>> index c437aa50ef..1084158b6a 100644
>> --- a/qapi/block-core.json
>> +++ b/qapi/block-core.json
>> @@ -1896,6 +1896,51 @@
>>              '*iops_size': 'int', '*group': 'str' } }
>>
>>  ##
>> +# @ThrottleLimits:
>> +#
>> +# Limit parameters for throttling.
>
>Please add a note that atomic updates are recommended.  Even though
>fields are optional it's best to specify all fields one wishes to change
>at once instead of performing multiple changes.

Will do, thanks.
>
>> +#
>> +# @iops-total:             limit total I/O operations per second
>> +# @iops-total-max:         I/O operations burst
>> +# @iops-total-max-length:  length of the iops-total-max burst period, in seconds
>> +#                          It must only be set if @iops-total-max is set as well.
>> +# @iops-read:              limit read operations per second
>> +# @iops-read-max:          I/O operations read burst
>> +# @iops-read-max-length:   length of the iops-read-max burst period, in seconds
>> +#                          It must only be set if @iops-read-max is set as well.
>> +# @iops-write:             limit write operations per second
>> +# @iops-write-max:         I/O operations write burst
>> +# @iops-write-max-length:  length of the iops-write-max burst period, in seconds
>> +#                          It must only be set if @iops-write-max is set as well.
>> +# @bps-total:              limit total bytes per second
>> +# @bps-total-max:          total bytes burst
>> +# @bps-total-max-length:   length of the bps-total-max burst period, in seconds.
>> +#                          It must only be set if @bps-total-max is set as well.
>> +# @bps-read:               limit read bytes per second
>> +# @bps-read-max:           total bytes read burst
>> +# @bps-read-max-length:    length of the bps-read-max burst period, in seconds
>> +#                          It must only be set if @bps-read-max is set as well.
>> +# @bps-write:              limit write bytes per second
>> +# @bps-write-max:          total bytes write burst
>> +# @bps-write-max-length:   length of the bps-write-max burst period, in seconds
>> +#                          It must only be set if @bps-write-max is set as well.
>> +# @iops-size:              when limiting by iops max size of an I/O in bytes
>> +#
>> +# Since: 2.10
>> +##
>> +{ 'struct': 'ThrottleLimits',
>> +  'data': { '*iops-total' : 'int', '*iops-total-max' : 'int',
>> +            '*iops-total-max-length' : 'int', '*iops-read' : 'int',
>> +            '*iops-read-max' : 'int', '*iops-read-max-length' : 'int',
>> +            '*iops-write' : 'int', '*iops-write-max' : 'int',
>> +            '*iops-write-max-length' : 'int', '*bps-total' : 'int',
>> +            '*bps-total-max' : 'int', '*bps-total-max-length' : 'int',
>> +            '*bps-read' : 'int', '*bps-read-max' : 'int',
>> +            '*bps-read-max-length' : 'int', '*bps-write' : 'int',
>> +            '*bps-write-max' : 'int', '*bps-write-max-length' : 'int',
>> +            '*iops-size' : 'int' } }
>> +
>> +##
>>  # @block-stream:
>>  #
>>  # Copy data from a backing file into a block device.
>> diff --git a/tests/test-throttle.c b/tests/test-throttle.c
>> index 57cf5ba711..0ea9093eee 100644
>> --- a/tests/test-throttle.c
>> +++ b/tests/test-throttle.c
>> @@ -662,6 +662,7 @@ int main(int argc, char **argv)
>>      qemu_init_main_loop(&error_fatal);
>>      ctx = qemu_get_aio_context();
>>      bdrv_init();
>> +    module_call_init(MODULE_INIT_QOM);
>>
>>      do {} while (g_main_context_iteration(NULL, false));
>>
>> diff --git a/util/throttle.c b/util/throttle.c
>> index b2a52b8b34..3bb21a63e6 100644
>> --- a/util/throttle.c
>> +++ b/util/throttle.c
>> @@ -502,3 +502,124 @@ void throttle_account(ThrottleState *ts, bool is_write, uint64_t size)
>>      }
>>  }
>>
>> +/* return a ThrottleConfig based on the options in a ThrottleLimits
>> + *
>> + * @arg:    the ThrottleLimits object to read from
>> + * @cfg:    the ThrottleConfig to edit
>> + * @errp:   error object
>> + */
>> +void throttle_limits_to_config(ThrottleLimits *arg, ThrottleConfig *cfg,
>> +                               Error **errp)
>> +{
>> +    if (arg->has_bps_total) {
>> +        cfg->buckets[THROTTLE_BPS_TOTAL].avg = arg->bps_total;
>> +    }
>> +    if (arg->has_bps_read) {
>> +        cfg->buckets[THROTTLE_BPS_READ].avg  = arg->bps_read;
>> +    }
>> +    if (arg->has_bps_write) {
>> +        cfg->buckets[THROTTLE_BPS_WRITE].avg = arg->bps_write;
>> +    }
>> +
>> +    if (arg->has_iops_total) {
>> +        cfg->buckets[THROTTLE_OPS_TOTAL].avg = arg->iops_total;
>> +    }
>> +    if (arg->has_iops_read) {
>> +        cfg->buckets[THROTTLE_OPS_READ].avg  = arg->iops_read;
>> +    }
>> +    if (arg->has_iops_write) {
>> +        cfg->buckets[THROTTLE_OPS_WRITE].avg = arg->iops_write;
>> +    }
>> +
>> +    if (arg->has_bps_total_max) {
>> +        cfg->buckets[THROTTLE_BPS_TOTAL].max = arg->bps_total_max;
>> +    }
>> +    if (arg->has_bps_read_max) {
>> +        cfg->buckets[THROTTLE_BPS_READ].max = arg->bps_read_max;
>> +    }
>> +    if (arg->has_bps_write_max) {
>> +        cfg->buckets[THROTTLE_BPS_WRITE].max = arg->bps_write_max;
>> +    }
>> +    if (arg->has_iops_total_max) {
>> +        cfg->buckets[THROTTLE_OPS_TOTAL].max = arg->iops_total_max;
>> +    }
>> +    if (arg->has_iops_read_max) {
>> +        cfg->buckets[THROTTLE_OPS_READ].max = arg->iops_read_max;
>> +    }
>> +    if (arg->has_iops_write_max) {
>> +        cfg->buckets[THROTTLE_OPS_WRITE].max = arg->iops_write_max;
>> +    }
>> +
>> +    if (arg->has_bps_total_max_length) {
>> +        cfg->buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_total_max_length;
>> +    }
>> +    if (arg->has_bps_read_max_length) {
>> +        cfg->buckets[THROTTLE_BPS_READ].burst_length = arg->bps_read_max_length;
>> +    }
>> +    if (arg->has_bps_write_max_length) {
>> +        cfg->buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_write_max_length;
>> +    }
>> +    if (arg->has_iops_total_max_length) {
>> +        cfg->buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_total_max_length;
>> +    }
>> +    if (arg->has_iops_read_max_length) {
>> +        cfg->buckets[THROTTLE_OPS_READ].burst_length = arg->iops_read_max_length;
>> +    }
>> +    if (arg->has_iops_write_max_length) {
>> +        cfg->buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_write_max_length;
>> +    }
>> +
>> +    if (arg->has_iops_size) {
>> +        cfg->op_size = arg->iops_size;
>> +    }
>> +
>> +    throttle_is_valid(cfg, errp);
>> +}
>> +
>> +/* write the options of a ThrottleConfig to a ThrottleLimits
>> + *
>> + * @cfg:    the ThrottleConfig to read from
>> + * @var:    the ThrottleLimits to write to
>> + */
>> +void throttle_config_to_throttle_limits(ThrottleConfig *cfg, ThrottleLimits *var)
>> +{
>> +    var->bps_total               = cfg->buckets[THROTTLE_BPS_TOTAL].avg;
>> +    var->bps_read                = cfg->buckets[THROTTLE_BPS_READ].avg;
>> +    var->bps_write               = cfg->buckets[THROTTLE_BPS_WRITE].avg;
>> +    var->iops_total              = cfg->buckets[THROTTLE_OPS_TOTAL].avg;
>> +    var->iops_read               = cfg->buckets[THROTTLE_OPS_READ].avg;
>> +    var->iops_write              = cfg->buckets[THROTTLE_OPS_WRITE].avg;
>> +    var->bps_total_max           = cfg->buckets[THROTTLE_BPS_TOTAL].max;
>> +    var->bps_read_max            = cfg->buckets[THROTTLE_BPS_READ].max;
>> +    var->bps_write_max           = cfg->buckets[THROTTLE_BPS_WRITE].max;
>> +    var->iops_total_max          = cfg->buckets[THROTTLE_OPS_TOTAL].max;
>> +    var->iops_read_max           = cfg->buckets[THROTTLE_OPS_READ].max;
>> +    var->iops_write_max          = cfg->buckets[THROTTLE_OPS_WRITE].max;
>> +    var->bps_total_max_length    = cfg->buckets[THROTTLE_BPS_TOTAL].burst_length;
>> +    var->bps_read_max_length     = cfg->buckets[THROTTLE_BPS_READ].burst_length;
>> +    var->bps_write_max_length    = cfg->buckets[THROTTLE_BPS_WRITE].burst_length;
>> +    var->iops_total_max_length   = cfg->buckets[THROTTLE_OPS_TOTAL].burst_length;
>> +    var->iops_read_max_length    = cfg->buckets[THROTTLE_OPS_READ].burst_length;
>> +    var->iops_write_max_length   = cfg->buckets[THROTTLE_OPS_WRITE].burst_length;
>> +    var->iops_size               = cfg->op_size;
>> +
>> +    var->has_bps_total = true;
>> +    var->has_bps_read = true;
>> +    var->has_bps_write = true;
>> +    var->has_iops_total = true;
>> +    var->has_iops_read = true;
>> +    var->has_iops_write = true;
>> +    var->has_bps_total_max = true;
>> +    var->has_bps_read_max = true;
>> +    var->has_bps_write_max = true;
>> +    var->has_iops_total_max = true;
>> +    var->has_iops_read_max = true;
>> +    var->has_iops_write_max = true;
>> +    var->has_bps_read_max_length = true;
>> +    var->has_bps_total_max_length = true;
>> +    var->has_bps_write_max_length = true;
>> +    var->has_iops_total_max_length = true;
>> +    var->has_iops_read_max_length = true;
>> +    var->has_iops_write_max_length = true;
>> +    var->has_iops_size = true;
>> +}
>> --
>> 2.11.0
>>



[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

  reply	other threads:[~2017-07-25 10:30 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-14  9:45 [Qemu-devel] [PATCH 0/7] add throttle block driver filter Manos Pitsidianakis
2017-07-14  9:45 ` [Qemu-devel] [PATCH 1/7] block: move ThrottleGroup membership to ThrottleGroupMember Manos Pitsidianakis
2017-07-24 14:36   ` Stefan Hajnoczi
2017-07-14  9:45 ` [Qemu-devel] [PATCH 2/7] block: add aio_context field in ThrottleGroupMember Manos Pitsidianakis
2017-07-24 14:38   ` Stefan Hajnoczi
2017-07-14  9:45 ` [Qemu-devel] [PATCH 3/7] block: tidy ThrottleGroupMember initializations Manos Pitsidianakis
2017-07-24 14:39   ` Stefan Hajnoczi
2017-07-14  9:45 ` [Qemu-devel] [PATCH 4/7] block: convert ThrottleGroup to object with QOM Manos Pitsidianakis
2017-07-24 15:12   ` Stefan Hajnoczi
2017-07-25 10:29     ` Manos Pitsidianakis [this message]
2017-07-25 16:09       ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
2017-07-25 16:21         ` Manos Pitsidianakis
2017-07-26 11:40           ` Stefan Hajnoczi
2017-07-14  9:45 ` [Qemu-devel] [PATCH 5/7] block: add throttle block filter driver Manos Pitsidianakis
2017-07-18  9:21   ` [Qemu-devel] [Qemu-block] " Manos Pitsidianakis
2017-07-14  9:45 ` [Qemu-devel] [PATCH 6/7] block: add BlockDevOptionsThrottle to QAPI Manos Pitsidianakis
2017-07-14  9:45 ` [Qemu-devel] [PATCH 7/7] block: add throttle block filter driver interface tests Manos Pitsidianakis

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170725102908.6bwzz543pfi7ef7z@postretch \
    --to=el13635@mail.ntua.gr \
    --cc=berto@igalia.com \
    --cc=kwolf@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).