[Qemu-devel] [PATCH v3 7/7] qemu-iotests: add 191 for legacy throttling interface

2017-08-25 Thread Manos Pitsidianakis
Check that the implicit throttle filter driver node, used for
compatibility with the legacy throttling interface on the BlockBackend
level, works.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 tests/qemu-iotests/191 | 138 +
 tests/qemu-iotests/191.out |   5 ++
 tests/qemu-iotests/group   |   1 +
 3 files changed, 144 insertions(+)
 create mode 100644 tests/qemu-iotests/191
 create mode 100644 tests/qemu-iotests/191.out

diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
new file mode 100644
index 00..82fd0b2fe5
--- /dev/null
+++ b/tests/qemu-iotests/191
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+#
+# Tests that the legacy throttling interface using an implicit throttle filter
+# driver node works
+#
+# Copyright (C) 2017 Manos Pitsidianakis
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import iotests
+
+class TestLegacyThrottling(iotests.QMPTestCase):
+test_img = os.path.join(iotests.test_dir, "test.img")
+target_img = os.path.join(iotests.test_dir, "target.img")
+base_img = os.path.join(iotests.test_dir, "base.img")
+
+def setUp(self):
+iotests.qemu_img("create", "-f", iotests.imgfmt, self.base_img, "1G")
+iotests.qemu_img("create", "-f", iotests.imgfmt, self.test_img, "-b", 
self.base_img)
+iotests.qemu_io("-f", iotests.imgfmt, "-c", "write -P0x5d 1M 128M", 
self.test_img)
+self.vm = iotests.VM().add_drive(self.test_img)
+self.vm.launch()
+
+def tearDown(self):
+self.do_check_throttle_node(expect=True)
+params = {"device": "drive0",
+  "bps": 0,
+  "bps_rd": 0,
+  "bps_wr": 0,
+  "iops": 0,
+  "iops_rd": 0,
+  "iops_wr": 0,
+ }
+"""
+This must remove the implicit throttle_node
+"""
+result = self.vm.qmp("block_set_io_throttle", conv_keys=False,
+ **params)
+self.do_check_throttle_node(expect=False)
+self.vm.shutdown()
+
+def do_test_job(self, cmd, **args):
+params = {"device": "drive0",
+  "bps": 1024,
+  "bps_rd": 0,
+  "bps_wr": 0,
+  "iops": 0,
+  "iops_rd": 0,
+  "iops_wr": 0,
+ }
+result = self.vm.qmp("block_set_io_throttle", conv_keys=False,
+ **params)
+self.assert_qmp(result, "return", {})
+result = self.vm.qmp(cmd, **args)
+self.assert_qmp(result, "return", {})
+result = self.vm.qmp("query-block-jobs")
+self.assert_qmp(result, "return[0]/device", "drive0")
+
+def do_check_throttle_node(self, expect):
+result = self.vm.qmp("query-named-block-nodes")
+for r in result["return"]:
+if r["drv"] == "throttle":
+self.assertTrue(expect)
+return
+if expect:
+""" throttle_node missing! """
+self.assertTrue(False)
+
+def do_check_params(self, file):
+result = self.vm.qmp("query-block")
+self.assert_qmp(result, "return[0]/inserted/bps", 1024)
+self.assert_qmp(result, "return[0]/inserted/drv", iotests.imgfmt)
+self.assert_qmp(result, "return[0]/inserted/file", file)
+
+"""
+Check that query-block reports the correct throttling parameters while
+ignoring the implicit throttle node.
+"""
+def test_query_block(self):
+params = {"device": "drive0",
+  "bps": 1024,
+  "bps_rd": 0,
+  "bps_wr": 0,
+  "iops":

[Qemu-devel] [PATCH v3 2/7] block: add options parameter to bdrv_new_open_driver()

2017-08-25 Thread Manos Pitsidianakis
Allow passing a QDict *options parameter to bdrv_new_open_driver() so
that it can be used if a driver needs it upon creation. The previous
behaviour (empty bs->options and bs->explicit_options) remains when
options is NULL.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 include/block/block.h |  2 +-
 block.c   | 16 +---
 block/commit.c|  4 ++--
 block/mirror.c|  2 +-
 block/vvfat.c |  2 +-
 5 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/include/block/block.h b/include/block/block.h
index ab80195378..d1f03cb48b 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -263,7 +263,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict 
*parent_options,
 BlockDriverState *bdrv_open(const char *filename, const char *reference,
 QDict *options, int flags, Error **errp);
 BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
-   int flags, Error **errp);
+   int flags, QDict *options, Error 
**errp);
 BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
 BlockDriverState *bs,
 QDict *options, int flags);
diff --git a/block.c b/block.c
index e35d546c08..2de1c29eb3 100644
--- a/block.c
+++ b/block.c
@@ -1153,16 +1153,26 @@ open_failed:
 return ret;
 }
 
+/*
+ * If options is not NULL, its ownership is transferred to the block layer. The
+ * caller must use QINCREF() if they wish to keep ownership.
+ */
 BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
-   int flags, Error **errp)
+   int flags, QDict *options, Error **errp)
 {
 BlockDriverState *bs;
 int ret;
 
 bs = bdrv_new();
 bs->open_flags = flags;
-bs->explicit_options = qdict_new();
-bs->options = qdict_new();
+if (options) {
+bs->explicit_options = qdict_clone_shallow(options);
+bs->options = qdict_clone_shallow(options);
+QDECREF(options);
+} else {
+bs->explicit_options = qdict_new();
+bs->options = qdict_new();
+}
 bs->opaque = NULL;
 
 update_options_from_flags(bs->options, flags);
diff --git a/block/commit.c b/block/commit.c
index c7857c3321..539e23c3f8 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -342,7 +342,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
 /* Insert commit_top block node above top, so we can block consistent read
  * on the backing chain below it */
 commit_top_bs = bdrv_new_open_driver(_commit_top, filter_node_name, 0,
- errp);
+ NULL, errp);
 if (commit_top_bs == NULL) {
 goto fail;
 }
@@ -494,7 +494,7 @@ int bdrv_commit(BlockDriverState *bs)
 backing_file_bs = backing_bs(bs);
 
 commit_top_bs = bdrv_new_open_driver(_commit_top, NULL, BDRV_O_RDWR,
- _err);
+ NULL, _err);
 if (commit_top_bs == NULL) {
 error_report_err(local_err);
 goto ro_cleanup;
diff --git a/block/mirror.c b/block/mirror.c
index c9a6a3ca86..e1a160e6ea 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -1164,7 +1164,7 @@ static void mirror_start_job(const char *job_id, 
BlockDriverState *bs,
  * reads on the top, while disabling it in the intermediate nodes, and make
  * the backing chain writable. */
 mirror_top_bs = bdrv_new_open_driver(_mirror_top, filter_node_name,
- BDRV_O_RDWR, errp);
+ BDRV_O_RDWR, NULL, errp);
 if (mirror_top_bs == NULL) {
 return;
 }
diff --git a/block/vvfat.c b/block/vvfat.c
index a9e207f7f0..6c59473baf 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -3194,7 +3194,7 @@ static int enable_write_target(BlockDriverState *bs, 
Error **errp)
 #endif
 
 backing = bdrv_new_open_driver(_write_target, NULL, 
BDRV_O_ALLOW_RDWR,
-   _abort);
+   NULL, _abort);
 *(void**) backing->opaque = s;
 
 bdrv_set_backing_hd(s->bs, backing, _abort);
-- 
2.11.0




[Qemu-devel] [PATCH v9 5/6] block: add throttle block filter driver

2017-08-25 Thread Manos Pitsidianakis
block/throttle.c uses existing I/O throttle infrastructure inside a
block filter driver. I/O operations are intercepted in the filter's
read/write coroutines, and referred to block/throttle-groups.c

The driver can be used with the syntax
-drive driver=throttle,file.filename=foo.qcow2,throttle-group=bar

which registers the throttle filter node with the ThrottleGroup 'bar'. The
given group must be created beforehand with object-add or -object.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 qapi/block-core.json|  18 ++-
 include/block/throttle-groups.h |   5 +
 include/qemu/throttle-options.h |   1 +
 block/throttle-groups.c |  15 ++-
 block/throttle.c| 250 
 block/Makefile.objs |   1 +
 6 files changed, 288 insertions(+), 2 deletions(-)
 create mode 100644 block/throttle.c

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 0bdc69aa5f..03724146a4 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -,6 +,7 @@
 # Drivers that are supported in block device operations.
 #
 # @vxhs: Since 2.10
+# @throttle: Since 2.11
 #
 # Since: 2.9
 ##
@@ -2231,7 +2232,7 @@
 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
 'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
 'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
-'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
+'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
 
 ##
 # @BlockdevOptionsFile:
@@ -3095,6 +3096,20 @@
 '*tls-creds': 'str' } }
 
 ##
+# @BlockdevOptionsThrottle:
+#
+# Driver specific block device options for the throttle driver
+#
+# @throttle-group:   the name of the throttle-group object to use. It
+#must already exist.
+# @file: reference to or definition of the data source block device
+# Since: 2.11
+##
+{ 'struct': 'BlockdevOptionsThrottle',
+  'data': { 'throttle-group': 'str',
+'file' : 'BlockdevRef'
+ } }
+##
 # @BlockdevOptions:
 #
 # Options for creating a block device.  Many options are available for all
@@ -3155,6 +3170,7 @@
   'replication':'BlockdevOptionsReplication',
   'sheepdog':   'BlockdevOptionsSheepdog',
   'ssh':'BlockdevOptionsSsh',
+  'throttle':   'BlockdevOptionsThrottle',
   'vdi':'BlockdevOptionsGenericFormat',
   'vhdx':   'BlockdevOptionsGenericFormat',
   'vmdk':   'BlockdevOptionsGenericCOWFormat',
diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
index 82f030523f..e2fd0513c4 100644
--- a/include/block/throttle-groups.h
+++ b/include/block/throttle-groups.h
@@ -76,5 +76,10 @@ void coroutine_fn 
throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm
 void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
AioContext *new_context);
 void throttle_group_detach_aio_context(ThrottleGroupMember *tgm);
+/*
+ * throttle_group_exists() must be called under the global
+ * mutex.
+ */
+bool throttle_group_exists(const char *name);
 
 #endif
diff --git a/include/qemu/throttle-options.h b/include/qemu/throttle-options.h
index 182b7896e1..3528a8f4a2 100644
--- a/include/qemu/throttle-options.h
+++ b/include/qemu/throttle-options.h
@@ -29,6 +29,7 @@
 #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 QEMU_OPT_THROTTLE_GROUP_NAME "throttle-group"
 
 #define THROTTLE_OPT_PREFIX "throttling."
 #define THROTTLE_OPTS \
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index 5993575838..454bfcb067 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -101,6 +101,14 @@ static ThrottleGroup *throttle_group_by_name(const char 
*name)
 return NULL;
 }
 
+/* This function reads throttle_groups and must be called under the global
+ * mutex.
+ */
+bool throttle_group_exists(const char *name)
+{
+return throttle_group_by_name(name) != NULL;
+}
+
 /* Increments the reference count of a ThrottleGroup given its name.
  *
  * If no ThrottleGroup is found with the given name a new one is
@@ -543,6 +551,11 @@ void throttle_group_unregister_tgm(ThrottleGroupMember 
*tgm)
 ThrottleGroupMember *token;
 int i;
 
+if (!ts) {
+/* Discard already unregistered tgm */
+return;
+}
+
 assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0);
 assert(qemu_co_queue_empty(>throttled_reqs[0]));
 assert(qemu_co_queue_empty(>throttled_reqs[1]));
@@ -709,7 +722,7 @@ static void throttle_group_obj_complete(UserCreatable *obj, 
Error **errp)
 assert(tg->name);
 
 /* error if name is duplicate */
-if

[Qemu-devel] [PATCH v9 1/6] block: move ThrottleGroup membership to ThrottleGroupMember

2017-08-25 Thread Manos Pitsidianakis
This commit eliminates the 1:1 relationship between BlockBackend and
throttle group state.  Users will be able to create multiple throttle
nodes, each with its own throttle group state, in the future.  The
throttle group state cannot be per-BlockBackend anymore, it must be
per-throttle node. This is done by gathering ThrottleGroup membership
details from BlockBackendPublic into ThrottleGroupMember and refactoring
existing code to use the structure.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 include/block/throttle-groups.h |  39 +-
 include/sysemu/block-backend.h  |  20 +--
 block/block-backend.c   |  66 +
 block/qapi.c|   8 +-
 block/throttle-groups.c | 288 
 blockdev.c  |   4 +-
 tests/test-throttle.c   |  53 
 7 files changed, 252 insertions(+), 226 deletions(-)

diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
index d983d34074..1a6bcdae74 100644
--- a/include/block/throttle-groups.h
+++ b/include/block/throttle-groups.h
@@ -28,19 +28,44 @@
 #include "qemu/throttle.h"
 #include "block/block_int.h"
 
-const char *throttle_group_get_name(BlockBackend *blk);
+/* The ThrottleGroupMember structure indicates membership in a ThrottleGroup
+ * and holds related data.
+ */
+
+typedef struct ThrottleGroupMember {
+/* throttled_reqs_lock protects the CoQueues for throttled requests.  */
+CoMutex  throttled_reqs_lock;
+CoQueue  throttled_reqs[2];
+
+/* Nonzero if the I/O limits are currently being ignored; generally
+ * it is zero.  Accessed with atomic operations.
+ */
+unsigned int io_limits_disabled;
+
+/* The following fields are protected by the ThrottleGroup lock.
+ * See the ThrottleGroup documentation for details.
+ * throttle_state tells us if I/O limits are configured. */
+ThrottleState *throttle_state;
+ThrottleTimers throttle_timers;
+unsigned   pending_reqs[2];
+QLIST_ENTRY(ThrottleGroupMember) round_robin;
+
+} ThrottleGroupMember;
+
+const char *throttle_group_get_name(ThrottleGroupMember *tgm);
 
 ThrottleState *throttle_group_incref(const char *name);
 void throttle_group_unref(ThrottleState *ts);
 
-void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg);
-void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg);
+void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
+void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
 
-void throttle_group_register_blk(BlockBackend *blk, const char *groupname);
-void throttle_group_unregister_blk(BlockBackend *blk);
-void throttle_group_restart_blk(BlockBackend *blk);
+void throttle_group_register_tgm(ThrottleGroupMember *tgm,
+const char *groupname);
+void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
+void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
 
-void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk,
+void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember 
*tgm,
 unsigned int bytes,
 bool is_write);
 
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 4a3730596b..0e0cda7521 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -70,24 +70,10 @@ typedef struct BlockDevOps {
 
 /* This struct is embedded in (the private) BlockBackend struct and contains
  * fields that must be public. This is in particular for QLIST_ENTRY() and
- * friends so that BlockBackends can be kept in lists outside block-backend.c 
*/
+ * friends so that BlockBackends can be kept in lists outside block-backend.c
+ * */
 typedef struct BlockBackendPublic {
-/* throttled_reqs_lock protects the CoQueues for throttled requests.  */
-CoMutex  throttled_reqs_lock;
-CoQueue  throttled_reqs[2];
-
-/* Nonzero if the I/O limits are currently being ignored; generally
- * it is zero.  Accessed with atomic operations.
- */
-unsigned int io_limits_disabled;
-
-/* The following fields are protected by the ThrottleGroup lock.
- * See the ThrottleGroup documentation for details.
- * throttle_state tells us if I/O limits are configured. */
-ThrottleState *throttle_state;
-ThrottleTimers throttle_timers;
-unsigned   pending_reqs[2];
-QLIST_ENTRY(BlockBackendPublic) round_robin;
+ThrottleGroupMember throttle_group_member;
 } BlockBackendPublic;
 
 BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm);
diff --git a/block/block-backend.c b/block/block-backend.c
index e9798e897d..7b981e00bb 100644
--- a/block/block

[Qemu-devel] [PATCH v9 6/6] qemu-iotests: add 184 for throttle filter driver

2017-08-25 Thread Manos Pitsidianakis
Reviewed-by: Alberto Garcia <be...@igalia.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 tests/qemu-iotests/184 | 205 +++
 tests/qemu-iotests/184.out | 300 +
 tests/qemu-iotests/group   |   1 +
 3 files changed, 506 insertions(+)
 create mode 100755 tests/qemu-iotests/184
 create mode 100644 tests/qemu-iotests/184.out

diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
new file mode 100755
index 00..704f38f936
--- /dev/null
+++ b/tests/qemu-iotests/184
@@ -0,0 +1,205 @@
+#!/bin/bash
+#
+# Test I/O throttle block filter driver interface
+#
+# Copyright (C) 2017 Manos Pitsidianakis
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner="Manos Pitsidianakis"
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1   # failure is the default!
+
+_cleanup()
+{
+_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+function do_run_qemu()
+{
+echo Testing: "$@" | _filter_imgfmt
+$QEMU -nographic -qmp-pretty stdio -serial none "$@"
+echo
+}
+
+function run_qemu()
+{
+do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
+  | _filter_qemu_io | _filter_generated_node_ids
+}
+
+_make_test_img 64M
+test_throttle=$($QEMU_IMG --help|grep throttle)
+[ "$test_throttle" = "" ] && _supported_fmt throttle
+
+echo
+echo "== checking interface =="
+
+run_qemu <

[Qemu-devel] [PATCH v9 0/6] add throttle block driver filter

2017-08-25 Thread Manos Pitsidianakis
This series adds a throttle block driver filter. Currently throttling is done
at the BlockBackend level. Using block driver interfaces we can move the
throttling to any point in the BDS graph using a throttle node which uses the
existing throttling code. This allows for potentially more complex
configurations (throttling at any point in the graph, chained filters)

v9:
  fix suggestions by stefanha in patch 4
  add 'throttle_group_can_be_deleted' function in patch 4

v8:
  fix suggestions by berto

v7:
  remove anonymous groups
  error on missing throttle-group option on block/throttle.c
  change switch case format in block/throttle-groups.c (berto)

v6:
  don't allow named group limit configuration in block/throttle.c; allow either
-drive driver=throttle,file.filename=foo.qcow2, \
limits.iops-total=...
  or
-drive driver=throttle,file.filename=foo.qcow2,throttle-group=bar
  fixes suggested by berto

v5:
  fix crash in 'add aio_context field in ThrottleGroupMember'
  fix suggestions in block/throttle.c

v4:
  fix suggestions in block/throttle.c
  fix suggestions in block/throttle_groups.c
  add doc note in BlockDevOptionsThrottle

v3:
  fix style error in 'add aio_context field in ThrottleGroupMember'

v2:
  change QOM throttle group object name
  print valid ranges for uint on error
  move frees in throttle_group_obj_finalize()
  split throttle_group_{set,get}()
  add throttle_recurse_is_first_non_filter()


Manos Pitsidianakis (6):
  block: move ThrottleGroup membership to ThrottleGroupMember
  block: add aio_context field in ThrottleGroupMember
  block: tidy ThrottleGroupMember initializations
  block: convert ThrottleGroup to object with QOM
  block: add throttle block filter driver
  qemu-iotests: add 184 for throttle filter driver

 qapi/block-core.json|  66 +++-
 include/block/throttle-groups.h |  52 ++-
 include/qemu/throttle-options.h |  60 +++-
 include/qemu/throttle.h |   3 +
 include/sysemu/block-backend.h  |  20 +-
 block/block-backend.c   |  62 ++--
 block/qapi.c|   8 +-
 block/throttle-groups.c | 748 ++--
 block/throttle.c| 250 ++
 blockdev.c  |   4 +-
 tests/test-throttle.c   | 111 +++---
 util/throttle.c | 151 
 block/Makefile.objs |   1 +
 tests/qemu-iotests/184  | 205 +++
 tests/qemu-iotests/184.out  | 300 
 tests/qemu-iotests/group|   1 +
 16 files changed, 1721 insertions(+), 321 deletions(-)
 create mode 100644 block/throttle.c
 create mode 100755 tests/qemu-iotests/184
 create mode 100644 tests/qemu-iotests/184.out

-- 
2.11.0




[Qemu-devel] [PATCH v9 4/6] block: convert ThrottleGroup to object with QOM

2017-08-25 Thread Manos Pitsidianakis
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 throttle-group,id=foo,x-iops-total=100,x-..
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": "throttle-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.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 qapi/block-core.json|  48 +
 include/block/throttle-groups.h |   3 +
 include/qemu/throttle-options.h |  59 --
 include/qemu/throttle.h |   3 +
 block/throttle-groups.c | 422 
 tests/test-throttle.c   |   1 +
 util/throttle.c | 151 ++
 7 files changed, 627 insertions(+), 60 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 833c602150..0bdc69aa5f 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1905,6 +1905,54 @@
 '*iops_size': 'int', '*group': 'str' } }
 
 ##
+# @ThrottleLimits:
+#
+# Limit parameters for throttling.
+# Since some limit combinations are illegal, limits should always be set in one
+# transaction. All fields are optional. When setting limits, if a field is
+# missing the current value is not changed.
+#
+# @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.11
+##
+{ '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',
+'*iop

[Qemu-devel] [PATCH v9 2/6] block: add aio_context field in ThrottleGroupMember

2017-08-25 Thread Manos Pitsidianakis
timer_cb() needs to know about the current Aio context of the throttle
request that is woken up. In order to make ThrottleGroupMember backend
agnostic, this information is stored in an aio_context field instead of
accessing it from BlockBackend.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 include/block/throttle-groups.h |  7 -
 block/block-backend.c   | 15 --
 block/throttle-groups.c | 38 -
 tests/test-throttle.c   | 63 +
 4 files changed, 69 insertions(+), 54 deletions(-)

diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
index 1a6bcdae74..a0f27cac63 100644
--- a/include/block/throttle-groups.h
+++ b/include/block/throttle-groups.h
@@ -33,6 +33,7 @@
  */
 
 typedef struct ThrottleGroupMember {
+AioContext   *aio_context;
 /* throttled_reqs_lock protects the CoQueues for throttled requests.  */
 CoMutex  throttled_reqs_lock;
 CoQueue  throttled_reqs[2];
@@ -61,12 +62,16 @@ void throttle_group_config(ThrottleGroupMember *tgm, 
ThrottleConfig *cfg);
 void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
 
 void throttle_group_register_tgm(ThrottleGroupMember *tgm,
-const char *groupname);
+const char *groupname,
+AioContext *ctx);
 void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
 void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
 
 void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember 
*tgm,
 unsigned int bytes,
 bool is_write);
+void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
+   AioContext *new_context);
+void throttle_group_detach_aio_context(ThrottleGroupMember *tgm);
 
 #endif
diff --git a/block/block-backend.c b/block/block-backend.c
index 7b981e00bb..9ba800e733 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1726,18 +1726,14 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB 
*acb)
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
 {
 BlockDriverState *bs = blk_bs(blk);
-ThrottleTimers *tt;
+ThrottleGroupMember *tgm = >public.throttle_group_member;
 
 if (bs) {
-if (blk->public.throttle_group_member.throttle_state) {
-tt = >public.throttle_group_member.throttle_timers;
-throttle_timers_detach_aio_context(tt);
+if (tgm->throttle_state) {
+throttle_group_detach_aio_context(tgm);
+throttle_group_attach_aio_context(tgm, new_context);
 }
 bdrv_set_aio_context(bs, new_context);
-if (blk->public.throttle_group_member.throttle_state) {
-tt = >public.throttle_group_member.throttle_timers;
-throttle_timers_attach_aio_context(tt, new_context);
-}
 }
 }
 
@@ -1970,7 +1966,8 @@ void blk_io_limits_disable(BlockBackend *blk)
 void blk_io_limits_enable(BlockBackend *blk, const char *group)
 {
 assert(!blk->public.throttle_group_member.throttle_state);
-throttle_group_register_tgm(>public.throttle_group_member, group);
+throttle_group_register_tgm(>public.throttle_group_member,
+group, blk_get_aio_context(blk));
 }
 
 void blk_io_limits_update_group(BlockBackend *blk, const char *group)
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index c8ed16ddf8..3b07b25f39 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -391,9 +391,6 @@ static void coroutine_fn 
throttle_group_restart_queue_entry(void *opaque)
 
 static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool 
is_write)
 {
-BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic,
-throttle_group_member);
-BlockBackend *blk = blk_by_public(blkp);
 Coroutine *co;
 RestartData rd = {
 .tgm = tgm,
@@ -401,7 +398,7 @@ static void 
throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write
 };
 
 co = qemu_coroutine_create(throttle_group_restart_queue_entry, );
-aio_co_enter(blk_get_aio_context(blk), co);
+aio_co_enter(tgm->aio_context, co);
 }
 
 void throttle_group_restart_tgm(ThrottleGroupMember *tgm)
@@ -449,13 +446,11 @@ void throttle_group_get_config(ThrottleGroupMember *tgm, 
ThrottleConfig *cfg)
 /* ThrottleTimers callback. This wakes up a request that was waiting
  * because it had been throttled.
  *
- * @blk:   the BlockBackend whose request had been throttled
+ * @tgm:   the ThrottleGroupMember whose request had been throttled
  * @is_write:  the type of operation (rea

[Qemu-devel] [PATCH v9 3/6] block: tidy ThrottleGroupMember initializations

2017-08-25 Thread Manos Pitsidianakis
Move the CoMutex and CoQueue inits inside throttle_group_register_tgm()
which is called whenever a ThrottleGroupMember is initialized. There's
no need for them to be separate.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block/block-backend.c   | 3 ---
 block/throttle-groups.c | 3 +++
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 9ba800e733..c51fb8c8aa 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -252,9 +252,6 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
 blk->shared_perm = shared_perm;
 blk_set_enable_write_cache(blk, true);
 
-qemu_co_mutex_init(>public.throttle_group_member.throttled_reqs_lock);
-qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[0]);
-qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[1]);
 block_acct_init(>stats);
 
 notifier_list_init(>remove_bs_notifiers);
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index 3b07b25f39..7749cf043f 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -508,6 +508,9 @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm,
  read_timer_cb,
  write_timer_cb,
  tgm);
+qemu_co_mutex_init(>throttled_reqs_lock);
+qemu_co_queue_init(>throttled_reqs[0]);
+qemu_co_queue_init(>throttled_reqs[1]);
 
 qemu_mutex_unlock(>lock);
 }
-- 
2.11.0




Re: [Qemu-devel] [PATCH v7 6/6] qemu-iotests: add 184 for throttle filter driver

2017-08-24 Thread Manos Pitsidianakis

On Thu, Aug 24, 2017 at 07:43:08PM +0100, Stefan Hajnoczi wrote:

On Tue, Aug 22, 2017 at 01:15:35PM +0300, Manos Pitsidianakis wrote:

+_supported_fmt qcow2


What makes this test qcow2-specific?  With additional filtering for
IMGFMT it should be possible to run this on any image format.


I think none of the available filters hide all of the image details in 
query-block and company. _filter_imgfmt hides the image extensions but 
not the image specific fields (eg virtual-size, actual-size and 
format-specific). Perhaps a new filter that hides everything but 
"format" and "filename" in the "image" subdict can be introduced later.


signature.asc
Description: PGP signature


[Qemu-devel] [PATCH v8 6/6] qemu-iotests: add 184 for throttle filter driver

2017-08-24 Thread Manos Pitsidianakis
Reviewed-by: Alberto Garcia <be...@igalia.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 tests/qemu-iotests/184 | 205 +++
 tests/qemu-iotests/184.out | 300 +
 tests/qemu-iotests/group   |   1 +
 3 files changed, 506 insertions(+)
 create mode 100755 tests/qemu-iotests/184
 create mode 100644 tests/qemu-iotests/184.out

diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
new file mode 100755
index 00..704f38f936
--- /dev/null
+++ b/tests/qemu-iotests/184
@@ -0,0 +1,205 @@
+#!/bin/bash
+#
+# Test I/O throttle block filter driver interface
+#
+# Copyright (C) 2017 Manos Pitsidianakis
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner="Manos Pitsidianakis"
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1   # failure is the default!
+
+_cleanup()
+{
+_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+function do_run_qemu()
+{
+echo Testing: "$@" | _filter_imgfmt
+$QEMU -nographic -qmp-pretty stdio -serial none "$@"
+echo
+}
+
+function run_qemu()
+{
+do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
+  | _filter_qemu_io | _filter_generated_node_ids
+}
+
+_make_test_img 64M
+test_throttle=$($QEMU_IMG --help|grep throttle)
+[ "$test_throttle" = "" ] && _supported_fmt throttle
+
+echo
+echo "== checking interface =="
+
+run_qemu <

[Qemu-devel] [PATCH v8 0/6] add throttle block driver filter

2017-08-24 Thread Manos Pitsidianakis
This series adds a throttle block driver filter. Currently throttling is done
at the BlockBackend level. Using block driver interfaces we can move the
throttling to any point in the BDS graph using a throttle node which uses the
existing throttling code. This allows for potentially more complex
configurations (throttling at any point in the graph, chained filters)

v8:
  fix suggestions by berto

v7:
  remove anonymous groups
  error on missing throttle-group option on block/throttle.c
  change switch case format in block/throttle-groups.c (berto)

v6:
  don't allow named group limit configuration in block/throttle.c; allow either
-drive driver=throttle,file.filename=foo.qcow2, \
limits.iops-total=...
  or
-drive driver=throttle,file.filename=foo.qcow2,throttle-group=bar
  fixes suggested by berto

v5:
  fix crash in 'add aio_context field in ThrottleGroupMember'
  fix suggestions in block/throttle.c

v4:
  fix suggestions in block/throttle.c
  fix suggestions in block/throttle_groups.c
  add doc note in BlockDevOptionsThrottle

v3:
  fix style error in 'add aio_context field in ThrottleGroupMember'

v2:
  change QOM throttle group object name
  print valid ranges for uint on error
  move frees in throttle_group_obj_finalize()
  split throttle_group_{set,get}()
  add throttle_recurse_is_first_non_filter()


Manos Pitsidianakis (6):
  block: move ThrottleGroup membership to ThrottleGroupMember
  block: add aio_context field in ThrottleGroupMember
  block: tidy ThrottleGroupMember initializations
  block: convert ThrottleGroup to object with QOM
  block: add throttle block filter driver
  qemu-iotests: add 184 for throttle filter driver

 qapi/block-core.json|  66 +++-
 include/block/throttle-groups.h |  48 ++-
 include/qemu/throttle-options.h |  60 ++--
 include/qemu/throttle.h |   3 +
 include/sysemu/block-backend.h  |  20 +-
 block/block-backend.c   |  62 ++--
 block/qapi.c|   8 +-
 block/throttle-groups.c | 736 +---
 block/throttle.c| 250 ++
 blockdev.c  |   4 +-
 tests/test-throttle.c   | 111 +++---
 util/throttle.c | 151 +
 block/Makefile.objs |   1 +
 tests/qemu-iotests/184  | 205 +++
 tests/qemu-iotests/184.out  | 300 
 tests/qemu-iotests/group|   1 +
 16 files changed, 1705 insertions(+), 321 deletions(-)
 create mode 100644 block/throttle.c
 create mode 100755 tests/qemu-iotests/184
 create mode 100644 tests/qemu-iotests/184.out

-- 
2.11.0




[Qemu-devel] [PATCH v8 4/6] block: convert ThrottleGroup to object with QOM

2017-08-24 Thread Manos Pitsidianakis
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 throttle-group,id=foo,x-iops-total=100,x-..
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": "throttle-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.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 qapi/block-core.json|  48 +
 include/block/throttle-groups.h |   3 +
 include/qemu/throttle-options.h |  59 --
 include/qemu/throttle.h |   3 +
 block/throttle-groups.c | 413 
 tests/test-throttle.c   |   1 +
 util/throttle.c | 151 +++
 7 files changed, 618 insertions(+), 60 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 833c602150..0bdc69aa5f 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1905,6 +1905,54 @@
 '*iops_size': 'int', '*group': 'str' } }
 
 ##
+# @ThrottleLimits:
+#
+# Limit parameters for throttling.
+# Since some limit combinations are illegal, limits should always be set in one
+# transaction. All fields are optional. When setting limits, if a field is
+# missing the current value is not changed.
+#
+# @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.11
+##
+{ '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',
+  

[Qemu-devel] [PATCH v8 5/6] block: add throttle block filter driver

2017-08-24 Thread Manos Pitsidianakis
block/throttle.c uses existing I/O throttle infrastructure inside a
block filter driver. I/O operations are intercepted in the filter's
read/write coroutines, and referred to block/throttle-groups.c

The driver can be used with the syntax
-drive driver=throttle,file.filename=foo.qcow2,throttle-group=bar

which registers the throttle filter node with the ThrottleGroup 'bar'. The
given group must be created beforehand with object-add or -object.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 qapi/block-core.json|  18 ++-
 include/block/throttle-groups.h |   1 +
 include/qemu/throttle-options.h |   1 +
 block/throttle-groups.c |  12 +-
 block/throttle.c| 250 
 block/Makefile.objs |   1 +
 6 files changed, 281 insertions(+), 2 deletions(-)
 create mode 100644 block/throttle.c

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 0bdc69aa5f..03724146a4 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -,6 +,7 @@
 # Drivers that are supported in block device operations.
 #
 # @vxhs: Since 2.10
+# @throttle: Since 2.11
 #
 # Since: 2.9
 ##
@@ -2231,7 +2232,7 @@
 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
 'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
 'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
-'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
+'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
 
 ##
 # @BlockdevOptionsFile:
@@ -3095,6 +3096,20 @@
 '*tls-creds': 'str' } }
 
 ##
+# @BlockdevOptionsThrottle:
+#
+# Driver specific block device options for the throttle driver
+#
+# @throttle-group:   the name of the throttle-group object to use. It
+#must already exist.
+# @file: reference to or definition of the data source block device
+# Since: 2.11
+##
+{ 'struct': 'BlockdevOptionsThrottle',
+  'data': { 'throttle-group': 'str',
+'file' : 'BlockdevRef'
+ } }
+##
 # @BlockdevOptions:
 #
 # Options for creating a block device.  Many options are available for all
@@ -3155,6 +3170,7 @@
   'replication':'BlockdevOptionsReplication',
   'sheepdog':   'BlockdevOptionsSheepdog',
   'ssh':'BlockdevOptionsSsh',
+  'throttle':   'BlockdevOptionsThrottle',
   'vdi':'BlockdevOptionsGenericFormat',
   'vhdx':   'BlockdevOptionsGenericFormat',
   'vmdk':   'BlockdevOptionsGenericCOWFormat',
diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
index 82f030523f..ec969e84fe 100644
--- a/include/block/throttle-groups.h
+++ b/include/block/throttle-groups.h
@@ -76,5 +76,6 @@ void coroutine_fn 
throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm
 void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
AioContext *new_context);
 void throttle_group_detach_aio_context(ThrottleGroupMember *tgm);
+bool throttle_group_exists(const char *name);
 
 #endif
diff --git a/include/qemu/throttle-options.h b/include/qemu/throttle-options.h
index 182b7896e1..3528a8f4a2 100644
--- a/include/qemu/throttle-options.h
+++ b/include/qemu/throttle-options.h
@@ -29,6 +29,7 @@
 #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 QEMU_OPT_THROTTLE_GROUP_NAME "throttle-group"
 
 #define THROTTLE_OPT_PREFIX "throttling."
 #define THROTTLE_OPTS \
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index 8421921bed..98ec39df3f 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -101,6 +101,11 @@ static ThrottleGroup *throttle_group_by_name(const char 
*name)
 return NULL;
 }
 
+bool throttle_group_exists(const char *name)
+{
+return throttle_group_by_name(name) != NULL;
+}
+
 /* Increments the reference count of a ThrottleGroup given its name.
  *
  * If no ThrottleGroup is found with the given name a new one is
@@ -543,6 +548,11 @@ void throttle_group_unregister_tgm(ThrottleGroupMember 
*tgm)
 ThrottleGroupMember *token;
 int i;
 
+if (!ts) {
+/* Discard already unregistered tgm */
+return;
+}
+
 assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0);
 assert(qemu_co_queue_empty(>throttled_reqs[0]));
 assert(qemu_co_queue_empty(>throttled_reqs[1]));
@@ -709,7 +719,7 @@ static void throttle_group_obj_complete(UserCreatable *obj, 
Error **errp)
 assert(tg->name);
 
 /* error if name is duplicate */
-if (throttle_group_by_name(tg->name) != NULL) {
+if (throttle_group_exists(tg->name)) {
 error_setg(errp, "A group with this name already exists");
 return;
 }
diff --git a/block/throttle.c

[Qemu-devel] [PATCH v8 2/6] block: add aio_context field in ThrottleGroupMember

2017-08-24 Thread Manos Pitsidianakis
timer_cb() needs to know about the current Aio context of the throttle
request that is woken up. In order to make ThrottleGroupMember backend
agnostic, this information is stored in an aio_context field instead of
accessing it from BlockBackend.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 include/block/throttle-groups.h |  7 -
 block/block-backend.c   | 15 --
 block/throttle-groups.c | 38 -
 tests/test-throttle.c   | 63 +
 4 files changed, 69 insertions(+), 54 deletions(-)

diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
index 1a6bcdae74..a0f27cac63 100644
--- a/include/block/throttle-groups.h
+++ b/include/block/throttle-groups.h
@@ -33,6 +33,7 @@
  */
 
 typedef struct ThrottleGroupMember {
+AioContext   *aio_context;
 /* throttled_reqs_lock protects the CoQueues for throttled requests.  */
 CoMutex  throttled_reqs_lock;
 CoQueue  throttled_reqs[2];
@@ -61,12 +62,16 @@ void throttle_group_config(ThrottleGroupMember *tgm, 
ThrottleConfig *cfg);
 void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
 
 void throttle_group_register_tgm(ThrottleGroupMember *tgm,
-const char *groupname);
+const char *groupname,
+AioContext *ctx);
 void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
 void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
 
 void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember 
*tgm,
 unsigned int bytes,
 bool is_write);
+void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
+   AioContext *new_context);
+void throttle_group_detach_aio_context(ThrottleGroupMember *tgm);
 
 #endif
diff --git a/block/block-backend.c b/block/block-backend.c
index 7b981e00bb..9ba800e733 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1726,18 +1726,14 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB 
*acb)
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
 {
 BlockDriverState *bs = blk_bs(blk);
-ThrottleTimers *tt;
+ThrottleGroupMember *tgm = >public.throttle_group_member;
 
 if (bs) {
-if (blk->public.throttle_group_member.throttle_state) {
-tt = >public.throttle_group_member.throttle_timers;
-throttle_timers_detach_aio_context(tt);
+if (tgm->throttle_state) {
+throttle_group_detach_aio_context(tgm);
+throttle_group_attach_aio_context(tgm, new_context);
 }
 bdrv_set_aio_context(bs, new_context);
-if (blk->public.throttle_group_member.throttle_state) {
-tt = >public.throttle_group_member.throttle_timers;
-throttle_timers_attach_aio_context(tt, new_context);
-}
 }
 }
 
@@ -1970,7 +1966,8 @@ void blk_io_limits_disable(BlockBackend *blk)
 void blk_io_limits_enable(BlockBackend *blk, const char *group)
 {
 assert(!blk->public.throttle_group_member.throttle_state);
-throttle_group_register_tgm(>public.throttle_group_member, group);
+throttle_group_register_tgm(>public.throttle_group_member,
+group, blk_get_aio_context(blk));
 }
 
 void blk_io_limits_update_group(BlockBackend *blk, const char *group)
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index c8ed16ddf8..3b07b25f39 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -391,9 +391,6 @@ static void coroutine_fn 
throttle_group_restart_queue_entry(void *opaque)
 
 static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool 
is_write)
 {
-BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic,
-throttle_group_member);
-BlockBackend *blk = blk_by_public(blkp);
 Coroutine *co;
 RestartData rd = {
 .tgm = tgm,
@@ -401,7 +398,7 @@ static void 
throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write
 };
 
 co = qemu_coroutine_create(throttle_group_restart_queue_entry, );
-aio_co_enter(blk_get_aio_context(blk), co);
+aio_co_enter(tgm->aio_context, co);
 }
 
 void throttle_group_restart_tgm(ThrottleGroupMember *tgm)
@@ -449,13 +446,11 @@ void throttle_group_get_config(ThrottleGroupMember *tgm, 
ThrottleConfig *cfg)
 /* ThrottleTimers callback. This wakes up a request that was waiting
  * because it had been throttled.
  *
- * @blk:   the BlockBackend whose request had been throttled
+ * @tgm:   the ThrottleGroupMember whose request had been throttled
  * @is_write:  the type of operation (rea

[Qemu-devel] [PATCH v8 1/6] block: move ThrottleGroup membership to ThrottleGroupMember

2017-08-24 Thread Manos Pitsidianakis
This commit eliminates the 1:1 relationship between BlockBackend and
throttle group state.  Users will be able to create multiple throttle
nodes, each with its own throttle group state, in the future.  The
throttle group state cannot be per-BlockBackend anymore, it must be
per-throttle node. This is done by gathering ThrottleGroup membership
details from BlockBackendPublic into ThrottleGroupMember and refactoring
existing code to use the structure.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 include/block/throttle-groups.h |  39 +-
 include/sysemu/block-backend.h  |  20 +--
 block/block-backend.c   |  66 +
 block/qapi.c|   8 +-
 block/throttle-groups.c | 288 
 blockdev.c  |   4 +-
 tests/test-throttle.c   |  53 
 7 files changed, 252 insertions(+), 226 deletions(-)

diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
index d983d34074..1a6bcdae74 100644
--- a/include/block/throttle-groups.h
+++ b/include/block/throttle-groups.h
@@ -28,19 +28,44 @@
 #include "qemu/throttle.h"
 #include "block/block_int.h"
 
-const char *throttle_group_get_name(BlockBackend *blk);
+/* The ThrottleGroupMember structure indicates membership in a ThrottleGroup
+ * and holds related data.
+ */
+
+typedef struct ThrottleGroupMember {
+/* throttled_reqs_lock protects the CoQueues for throttled requests.  */
+CoMutex  throttled_reqs_lock;
+CoQueue  throttled_reqs[2];
+
+/* Nonzero if the I/O limits are currently being ignored; generally
+ * it is zero.  Accessed with atomic operations.
+ */
+unsigned int io_limits_disabled;
+
+/* The following fields are protected by the ThrottleGroup lock.
+ * See the ThrottleGroup documentation for details.
+ * throttle_state tells us if I/O limits are configured. */
+ThrottleState *throttle_state;
+ThrottleTimers throttle_timers;
+unsigned   pending_reqs[2];
+QLIST_ENTRY(ThrottleGroupMember) round_robin;
+
+} ThrottleGroupMember;
+
+const char *throttle_group_get_name(ThrottleGroupMember *tgm);
 
 ThrottleState *throttle_group_incref(const char *name);
 void throttle_group_unref(ThrottleState *ts);
 
-void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg);
-void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg);
+void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
+void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
 
-void throttle_group_register_blk(BlockBackend *blk, const char *groupname);
-void throttle_group_unregister_blk(BlockBackend *blk);
-void throttle_group_restart_blk(BlockBackend *blk);
+void throttle_group_register_tgm(ThrottleGroupMember *tgm,
+const char *groupname);
+void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
+void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
 
-void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk,
+void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember 
*tgm,
 unsigned int bytes,
 bool is_write);
 
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 4a3730596b..0e0cda7521 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -70,24 +70,10 @@ typedef struct BlockDevOps {
 
 /* This struct is embedded in (the private) BlockBackend struct and contains
  * fields that must be public. This is in particular for QLIST_ENTRY() and
- * friends so that BlockBackends can be kept in lists outside block-backend.c 
*/
+ * friends so that BlockBackends can be kept in lists outside block-backend.c
+ * */
 typedef struct BlockBackendPublic {
-/* throttled_reqs_lock protects the CoQueues for throttled requests.  */
-CoMutex  throttled_reqs_lock;
-CoQueue  throttled_reqs[2];
-
-/* Nonzero if the I/O limits are currently being ignored; generally
- * it is zero.  Accessed with atomic operations.
- */
-unsigned int io_limits_disabled;
-
-/* The following fields are protected by the ThrottleGroup lock.
- * See the ThrottleGroup documentation for details.
- * throttle_state tells us if I/O limits are configured. */
-ThrottleState *throttle_state;
-ThrottleTimers throttle_timers;
-unsigned   pending_reqs[2];
-QLIST_ENTRY(BlockBackendPublic) round_robin;
+ThrottleGroupMember throttle_group_member;
 } BlockBackendPublic;
 
 BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm);
diff --git a/block/block-backend.c b/block/block-backend.c
index e9798e897d..7b981e00bb 100644
--- a/block/block

[Qemu-devel] [PATCH v8 3/6] block: tidy ThrottleGroupMember initializations

2017-08-24 Thread Manos Pitsidianakis
Move the CoMutex and CoQueue inits inside throttle_group_register_tgm()
which is called whenever a ThrottleGroupMember is initialized. There's
no need for them to be separate.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block/block-backend.c   | 3 ---
 block/throttle-groups.c | 3 +++
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 9ba800e733..c51fb8c8aa 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -252,9 +252,6 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
 blk->shared_perm = shared_perm;
 blk_set_enable_write_cache(blk, true);
 
-qemu_co_mutex_init(>public.throttle_group_member.throttled_reqs_lock);
-qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[0]);
-qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[1]);
 block_acct_init(>stats);
 
 notifier_list_init(>remove_bs_notifiers);
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index 3b07b25f39..7749cf043f 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -508,6 +508,9 @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm,
  read_timer_cb,
  write_timer_cb,
  tgm);
+qemu_co_mutex_init(>throttled_reqs_lock);
+qemu_co_queue_init(>throttled_reqs[0]);
+qemu_co_queue_init(>throttled_reqs[1]);
 
 qemu_mutex_unlock(>lock);
 }
-- 
2.11.0




Re: [Qemu-devel] [PATCH v7 5/6] block: add throttle block filter driver

2017-08-22 Thread Manos Pitsidianakis

On Tue, Aug 22, 2017 at 04:16:26PM +0200, Alberto Garcia wrote:

On Tue 22 Aug 2017 12:15:34 PM CEST, Manos Pitsidianakis wrote:

@@ -548,6 +548,11 @@ void throttle_group_unregister_tgm(ThrottleGroupMember 
*tgm)
 ThrottleGroupMember *token;
 int i;

+if (!ts) {
+/* Discard uninitialized tgm */
+return;
+}
+


Is this change needed in case throttle_configure_tgm() fails?


Yes, now all errors are before throttle_group_register_tgm(), therefore 
the unregister part in throttle_close() will not have valid data.


signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH v7 4/6] block: convert ThrottleGroup to object with QOM

2017-08-22 Thread Manos Pitsidianakis

On Tue, Aug 22, 2017 at 03:25:41PM +0200, Alberto Garcia wrote:

+/* This function edits throttle_groups and must be called under the global
+ * mutex */
+static void throttle_group_obj_complete(UserCreatable *obj, Error **errp)
+{
+ThrottleGroup *tg = THROTTLE_GROUP(obj);
+ThrottleConfig 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));
+}
+/* We must have a group name at this point */
+assert(tg->name);
+
+/* error if name is duplicate */
+if (throttle_group_exists(tg->name)) {
+error_setg(errp, "A group with this name already exists");
+return;
+}
+
+/* check validity */
+throttle_get_config(>ts, );
+if (!throttle_is_valid(, errp)) {
+return;
+}


My fault here because I suggested its removal, but I actually think we
still need to call throttle_config() here so bkt->max is initialized in
throttle_fix_bucket(). I'll take care of updating this call once my
patches to remove throttle_fix_bucket() are applied, but for now we
still need it.


Oh yes, that is the reason I originally had done it but forgot why.


signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH v2 3/6] block: require job-id when device is a node name

2017-08-22 Thread Manos Pitsidianakis

On Tue, Aug 22, 2017 at 11:57:28AM +0200, Alberto Garcia wrote:

On Mon 21 Aug 2017 05:39:48 PM CEST, Manos Pitsidianakis wrote:

-if (job_id == NULL && !(flags & BLOCK_JOB_INTERNAL)) {
-job_id = bdrv_get_device_name(bs);
-if (!*job_id) {
-error_setg(errp, "An explicit job ID is required for this node");
-return NULL;
-}
-}
-
-if (job_id) {
-if (flags & BLOCK_JOB_INTERNAL) {
+if (flags & BLOCK_JOB_INTERNAL) {
+if (job_id) {
 error_setg(errp, "Cannot specify job ID for internal block job");
 return NULL;
 }


When BLOCK_JOB_INTERNAL is set, then job_id must be NULL...


-
+} else {
+/* Require job-id. */
+assert(job_id);
 if (!id_wellformed(job_id)) {
 error_setg(errp, "Invalid job ID '%s'", job_id);
 return NULL;
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
index f13ad05c0d..ff906808a6 100644
--- a/include/block/blockjob_int.h
+++ b/include/block/blockjob_int.h
@@ -112,8 +112,7 @@ struct BlockJobDriver {

 /**
  * block_job_create:
- * @job_id: The id of the newly-created job, or %NULL to have one
- * generated automatically.
+ * @job_id: The id of the newly-created job, must be non %NULL.


...but here you say that it must not be NULL.

And since job_id can be NULL in some cases I think I'd replace the
assert(job_id) that you added to block_job_create() with a normal
pointer check + error_setg().


@@ -93,9 +93,6 @@ static void test_job_ids(void)
 blk[1] = create_blk("drive1");
 blk[2] = create_blk("drive2");

-/* No job ID provided and the block backend has no name */
-job[0] = do_test_id(blk[0], NULL, false);
-


If you decide to handle NULL ids by returning and error instead of
asserting, we should keep a couple of tests for that scenario.

Berto



Thanks, I will change that. What cases are you thinking of besides
internal jobs though?


Both cases (external job with a NULL id and internal job with non-NULL
id), checking that block_job_create() does return an error.


I thought we handled the external job case by requiring job_id is set 
before calling block_job_create(). I will check my patch again.





And should documentation of block_job_create reflect that internal
jobs have job_id == NULL?


Yes, it should document the restrictions of the job_id parameter.

Berto



signature.asc
Description: PGP signature


[Qemu-devel] [PATCH v7 4/6] block: convert ThrottleGroup to object with QOM

2017-08-22 Thread Manos Pitsidianakis
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 throttle-group,id=foo,x-iops-total=100,x-..
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": "throttle-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.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 qapi/block-core.json|  48 +
 include/block/throttle-groups.h |   3 +
 include/qemu/throttle-options.h |  59 --
 include/qemu/throttle.h |   3 +
 block/throttle-groups.c | 419 
 tests/test-throttle.c   |   1 +
 util/throttle.c | 151 +++
 7 files changed, 624 insertions(+), 60 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 833c602150..0bdc69aa5f 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1905,6 +1905,54 @@
 '*iops_size': 'int', '*group': 'str' } }
 
 ##
+# @ThrottleLimits:
+#
+# Limit parameters for throttling.
+# Since some limit combinations are illegal, limits should always be set in one
+# transaction. All fields are optional. When setting limits, if a field is
+# missing the current value is not changed.
+#
+# @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.11
+##
+{ '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',
+  

[Qemu-devel] [PATCH v7 5/6] block: add throttle block filter driver

2017-08-22 Thread Manos Pitsidianakis
block/throttle.c uses existing I/O throttle infrastructure inside a
block filter driver. I/O operations are intercepted in the filter's
read/write coroutines, and referred to block/throttle-groups.c

The driver can be used with the syntax
-drive driver=throttle,file.filename=foo.qcow2,throttle-group=bar

which registers the throttle filter node with the ThrottleGroup 'bar'. The
given group must be created beforehand with object-add or -object.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 qapi/block-core.json|  18 ++-
 include/block/throttle-groups.h |   1 +
 include/qemu/throttle-options.h |   1 +
 block/throttle-groups.c |   7 +-
 block/throttle.c| 250 
 block/Makefile.objs |   1 +
 6 files changed, 276 insertions(+), 2 deletions(-)
 create mode 100644 block/throttle.c

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 0bdc69aa5f..405c181954 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -,6 +,7 @@
 # Drivers that are supported in block device operations.
 #
 # @vxhs: Since 2.10
+# @throttle: Since 2.11
 #
 # Since: 2.9
 ##
@@ -2231,7 +2232,7 @@
 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
 'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
 'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
-'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
+'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
 
 ##
 # @BlockdevOptionsFile:
@@ -3095,6 +3096,20 @@
 '*tls-creds': 'str' } }
 
 ##
+# @BlockdevOptionsThrottle:
+#
+# Driver specific block device options for the throttle driver
+#
+# @throttle-group:   the name of the throttle-group object to use. It
+#must already exist.
+# @file: reference to or definition of the data source block device
+# Since: 2.11
+##
+{ 'struct': 'BlockdevOptionsThrottle',
+  'data': { '*throttle-group': 'str',
+'file' : 'BlockdevRef'
+ } }
+##
 # @BlockdevOptions:
 #
 # Options for creating a block device.  Many options are available for all
@@ -3155,6 +3170,7 @@
   'replication':'BlockdevOptionsReplication',
   'sheepdog':   'BlockdevOptionsSheepdog',
   'ssh':'BlockdevOptionsSsh',
+  'throttle':   'BlockdevOptionsThrottle',
   'vdi':'BlockdevOptionsGenericFormat',
   'vhdx':   'BlockdevOptionsGenericFormat',
   'vmdk':   'BlockdevOptionsGenericCOWFormat',
diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
index 82f030523f..ec969e84fe 100644
--- a/include/block/throttle-groups.h
+++ b/include/block/throttle-groups.h
@@ -76,5 +76,6 @@ void coroutine_fn 
throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm
 void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
AioContext *new_context);
 void throttle_group_detach_aio_context(ThrottleGroupMember *tgm);
+bool throttle_group_exists(const char *name);
 
 #endif
diff --git a/include/qemu/throttle-options.h b/include/qemu/throttle-options.h
index 182b7896e1..3528a8f4a2 100644
--- a/include/qemu/throttle-options.h
+++ b/include/qemu/throttle-options.h
@@ -29,6 +29,7 @@
 #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 QEMU_OPT_THROTTLE_GROUP_NAME "throttle-group"
 
 #define THROTTLE_OPT_PREFIX "throttling."
 #define THROTTLE_OPTS \
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index a4268a954e..4b483a16d4 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -101,7 +101,7 @@ static ThrottleGroup *throttle_group_by_name(const char 
*name)
 return NULL;
 }
 
-static bool throttle_group_exists(const char *name)
+bool throttle_group_exists(const char *name)
 {
 return throttle_group_by_name(name) ? true : false;
 }
@@ -548,6 +548,11 @@ void throttle_group_unregister_tgm(ThrottleGroupMember 
*tgm)
 ThrottleGroupMember *token;
 int i;
 
+if (!ts) {
+/* Discard uninitialized tgm */
+return;
+}
+
 assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0);
 assert(qemu_co_queue_empty(>throttled_reqs[0]));
 assert(qemu_co_queue_empty(>throttled_reqs[1]));
diff --git a/block/throttle.c b/block/throttle.c
new file mode 100644
index 00..910de27dcd
--- /dev/null
+++ b/block/throttle.c
@@ -0,0 +1,250 @@
+/*
+ * QEMU block throttling filter driver infrastructure
+ *
+ * Copyright (c) 2017 Manos Pitsidianakis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your optio

[Qemu-devel] [PATCH v7 2/6] block: add aio_context field in ThrottleGroupMember

2017-08-22 Thread Manos Pitsidianakis
timer_cb() needs to know about the current Aio context of the throttle
request that is woken up. In order to make ThrottleGroupMember backend
agnostic, this information is stored in an aio_context field instead of
accessing it from BlockBackend.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 include/block/throttle-groups.h |  7 -
 block/block-backend.c   | 15 --
 block/throttle-groups.c | 38 -
 tests/test-throttle.c   | 63 +
 4 files changed, 69 insertions(+), 54 deletions(-)

diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
index 1a6bcdae74..a0f27cac63 100644
--- a/include/block/throttle-groups.h
+++ b/include/block/throttle-groups.h
@@ -33,6 +33,7 @@
  */
 
 typedef struct ThrottleGroupMember {
+AioContext   *aio_context;
 /* throttled_reqs_lock protects the CoQueues for throttled requests.  */
 CoMutex  throttled_reqs_lock;
 CoQueue  throttled_reqs[2];
@@ -61,12 +62,16 @@ void throttle_group_config(ThrottleGroupMember *tgm, 
ThrottleConfig *cfg);
 void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
 
 void throttle_group_register_tgm(ThrottleGroupMember *tgm,
-const char *groupname);
+const char *groupname,
+AioContext *ctx);
 void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
 void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
 
 void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember 
*tgm,
 unsigned int bytes,
 bool is_write);
+void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
+   AioContext *new_context);
+void throttle_group_detach_aio_context(ThrottleGroupMember *tgm);
 
 #endif
diff --git a/block/block-backend.c b/block/block-backend.c
index 7b981e00bb..9ba800e733 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1726,18 +1726,14 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB 
*acb)
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
 {
 BlockDriverState *bs = blk_bs(blk);
-ThrottleTimers *tt;
+ThrottleGroupMember *tgm = >public.throttle_group_member;
 
 if (bs) {
-if (blk->public.throttle_group_member.throttle_state) {
-tt = >public.throttle_group_member.throttle_timers;
-throttle_timers_detach_aio_context(tt);
+if (tgm->throttle_state) {
+throttle_group_detach_aio_context(tgm);
+throttle_group_attach_aio_context(tgm, new_context);
 }
 bdrv_set_aio_context(bs, new_context);
-if (blk->public.throttle_group_member.throttle_state) {
-tt = >public.throttle_group_member.throttle_timers;
-throttle_timers_attach_aio_context(tt, new_context);
-}
 }
 }
 
@@ -1970,7 +1966,8 @@ void blk_io_limits_disable(BlockBackend *blk)
 void blk_io_limits_enable(BlockBackend *blk, const char *group)
 {
 assert(!blk->public.throttle_group_member.throttle_state);
-throttle_group_register_tgm(>public.throttle_group_member, group);
+throttle_group_register_tgm(>public.throttle_group_member,
+group, blk_get_aio_context(blk));
 }
 
 void blk_io_limits_update_group(BlockBackend *blk, const char *group)
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index c8ed16ddf8..3b07b25f39 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -391,9 +391,6 @@ static void coroutine_fn 
throttle_group_restart_queue_entry(void *opaque)
 
 static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool 
is_write)
 {
-BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic,
-throttle_group_member);
-BlockBackend *blk = blk_by_public(blkp);
 Coroutine *co;
 RestartData rd = {
 .tgm = tgm,
@@ -401,7 +398,7 @@ static void 
throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write
 };
 
 co = qemu_coroutine_create(throttle_group_restart_queue_entry, );
-aio_co_enter(blk_get_aio_context(blk), co);
+aio_co_enter(tgm->aio_context, co);
 }
 
 void throttle_group_restart_tgm(ThrottleGroupMember *tgm)
@@ -449,13 +446,11 @@ void throttle_group_get_config(ThrottleGroupMember *tgm, 
ThrottleConfig *cfg)
 /* ThrottleTimers callback. This wakes up a request that was waiting
  * because it had been throttled.
  *
- * @blk:   the BlockBackend whose request had been throttled
+ * @tgm:   the ThrottleGroupMember whose request had been throttled
  * @is_write:  the type of operation (rea

[Qemu-devel] [PATCH v7 6/6] qemu-iotests: add 184 for throttle filter driver

2017-08-22 Thread Manos Pitsidianakis
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 tests/qemu-iotests/184 | 205 +++
 tests/qemu-iotests/184.out | 300 +
 tests/qemu-iotests/group   |   1 +
 3 files changed, 506 insertions(+)
 create mode 100755 tests/qemu-iotests/184
 create mode 100644 tests/qemu-iotests/184.out

diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
new file mode 100755
index 00..704f38f936
--- /dev/null
+++ b/tests/qemu-iotests/184
@@ -0,0 +1,205 @@
+#!/bin/bash
+#
+# Test I/O throttle block filter driver interface
+#
+# Copyright (C) 2017 Manos Pitsidianakis
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner="Manos Pitsidianakis"
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1   # failure is the default!
+
+_cleanup()
+{
+_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+function do_run_qemu()
+{
+echo Testing: "$@" | _filter_imgfmt
+$QEMU -nographic -qmp-pretty stdio -serial none "$@"
+echo
+}
+
+function run_qemu()
+{
+do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
+  | _filter_qemu_io | _filter_generated_node_ids
+}
+
+_make_test_img 64M
+test_throttle=$($QEMU_IMG --help|grep throttle)
+[ "$test_throttle" = "" ] && _supported_fmt throttle
+
+echo
+echo "== checking interface =="
+
+run_qemu <

[Qemu-devel] [PATCH v7 3/6] block: tidy ThrottleGroupMember initializations

2017-08-22 Thread Manos Pitsidianakis
Move the CoMutex and CoQueue inits inside throttle_group_register_tgm()
which is called whenever a ThrottleGroupMember is initialized. There's
no need for them to be separate.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block/block-backend.c   | 3 ---
 block/throttle-groups.c | 3 +++
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 9ba800e733..c51fb8c8aa 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -252,9 +252,6 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
 blk->shared_perm = shared_perm;
 blk_set_enable_write_cache(blk, true);
 
-qemu_co_mutex_init(>public.throttle_group_member.throttled_reqs_lock);
-qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[0]);
-qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[1]);
 block_acct_init(>stats);
 
 notifier_list_init(>remove_bs_notifiers);
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index 3b07b25f39..7749cf043f 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -508,6 +508,9 @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm,
  read_timer_cb,
  write_timer_cb,
  tgm);
+qemu_co_mutex_init(>throttled_reqs_lock);
+qemu_co_queue_init(>throttled_reqs[0]);
+qemu_co_queue_init(>throttled_reqs[1]);
 
 qemu_mutex_unlock(>lock);
 }
-- 
2.11.0




[Qemu-devel] [PATCH v7 1/6] block: move ThrottleGroup membership to ThrottleGroupMember

2017-08-22 Thread Manos Pitsidianakis
This commit eliminates the 1:1 relationship between BlockBackend and
throttle group state.  Users will be able to create multiple throttle
nodes, each with its own throttle group state, in the future.  The
throttle group state cannot be per-BlockBackend anymore, it must be
per-throttle node. This is done by gathering ThrottleGroup membership
details from BlockBackendPublic into ThrottleGroupMember and refactoring
existing code to use the structure.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 include/block/throttle-groups.h |  39 +-
 include/sysemu/block-backend.h  |  20 +--
 block/block-backend.c   |  66 +
 block/qapi.c|   8 +-
 block/throttle-groups.c | 288 
 blockdev.c  |   4 +-
 tests/test-throttle.c   |  53 
 7 files changed, 252 insertions(+), 226 deletions(-)

diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
index d983d34074..1a6bcdae74 100644
--- a/include/block/throttle-groups.h
+++ b/include/block/throttle-groups.h
@@ -28,19 +28,44 @@
 #include "qemu/throttle.h"
 #include "block/block_int.h"
 
-const char *throttle_group_get_name(BlockBackend *blk);
+/* The ThrottleGroupMember structure indicates membership in a ThrottleGroup
+ * and holds related data.
+ */
+
+typedef struct ThrottleGroupMember {
+/* throttled_reqs_lock protects the CoQueues for throttled requests.  */
+CoMutex  throttled_reqs_lock;
+CoQueue  throttled_reqs[2];
+
+/* Nonzero if the I/O limits are currently being ignored; generally
+ * it is zero.  Accessed with atomic operations.
+ */
+unsigned int io_limits_disabled;
+
+/* The following fields are protected by the ThrottleGroup lock.
+ * See the ThrottleGroup documentation for details.
+ * throttle_state tells us if I/O limits are configured. */
+ThrottleState *throttle_state;
+ThrottleTimers throttle_timers;
+unsigned   pending_reqs[2];
+QLIST_ENTRY(ThrottleGroupMember) round_robin;
+
+} ThrottleGroupMember;
+
+const char *throttle_group_get_name(ThrottleGroupMember *tgm);
 
 ThrottleState *throttle_group_incref(const char *name);
 void throttle_group_unref(ThrottleState *ts);
 
-void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg);
-void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg);
+void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
+void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
 
-void throttle_group_register_blk(BlockBackend *blk, const char *groupname);
-void throttle_group_unregister_blk(BlockBackend *blk);
-void throttle_group_restart_blk(BlockBackend *blk);
+void throttle_group_register_tgm(ThrottleGroupMember *tgm,
+const char *groupname);
+void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
+void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
 
-void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk,
+void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember 
*tgm,
 unsigned int bytes,
 bool is_write);
 
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 4a3730596b..0e0cda7521 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -70,24 +70,10 @@ typedef struct BlockDevOps {
 
 /* This struct is embedded in (the private) BlockBackend struct and contains
  * fields that must be public. This is in particular for QLIST_ENTRY() and
- * friends so that BlockBackends can be kept in lists outside block-backend.c 
*/
+ * friends so that BlockBackends can be kept in lists outside block-backend.c
+ * */
 typedef struct BlockBackendPublic {
-/* throttled_reqs_lock protects the CoQueues for throttled requests.  */
-CoMutex  throttled_reqs_lock;
-CoQueue  throttled_reqs[2];
-
-/* Nonzero if the I/O limits are currently being ignored; generally
- * it is zero.  Accessed with atomic operations.
- */
-unsigned int io_limits_disabled;
-
-/* The following fields are protected by the ThrottleGroup lock.
- * See the ThrottleGroup documentation for details.
- * throttle_state tells us if I/O limits are configured. */
-ThrottleState *throttle_state;
-ThrottleTimers throttle_timers;
-unsigned   pending_reqs[2];
-QLIST_ENTRY(BlockBackendPublic) round_robin;
+ThrottleGroupMember throttle_group_member;
 } BlockBackendPublic;
 
 BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm);
diff --git a/block/block-backend.c b/block/block-backend.c
index e9798e897d..7b981e00bb 100644
--- a/block/block

[Qemu-devel] [PATCH v7 0/6] add throttle block driver filter

2017-08-22 Thread Manos Pitsidianakis
This series adds a throttle block driver filter. Currently throttling is done
at the BlockBackend level. Using block driver interfaces we can move the
throttling to any point in the BDS graph using a throttle node which uses the
existing throttling code. This allows for potentially more complex
configurations (throttling at any point in the graph, chained filters)

v7:
  remove anonymous groups
  error on missing throttle-group option on block/throttle.c
  change switch case format in block/throttle-groups.c (berto)

v6:
  don't allow named group limit configuration in block/throttle.c; allow either
-drive driver=throttle,file.filename=foo.qcow2, \
limits.iops-total=...
  or
-drive driver=throttle,file.filename=foo.qcow2,throttle-group=bar
  fixes suggested by berto

v5:
  fix crash in 'add aio_context field in ThrottleGroupMember'
  fix suggestions in block/throttle.c

v4:
  fix suggestions in block/throttle.c
  fix suggestions in block/throttle_groups.c
  add doc note in BlockDevOptionsThrottle

v3:
  fix style error in 'add aio_context field in ThrottleGroupMember'

v2:
  change QOM throttle group object name
  print valid ranges for uint on error
  move frees in throttle_group_obj_finalize()
  split throttle_group_{set,get}()
  add throttle_recurse_is_first_non_filter()

Manos Pitsidianakis (6):
  block: move ThrottleGroup membership to ThrottleGroupMember
  block: add aio_context field in ThrottleGroupMember
  block: tidy ThrottleGroupMember initializations
  block: convert ThrottleGroup to object with QOM
  block: add throttle block filter driver
  qemu-iotests: add 184 for throttle filter driver

 qapi/block-core.json|  66 +++-
 include/block/throttle-groups.h |  48 ++-
 include/qemu/throttle-options.h |  60 ++--
 include/qemu/throttle.h |   3 +
 include/sysemu/block-backend.h  |  20 +-
 block/block-backend.c   |  62 ++--
 block/qapi.c|   8 +-
 block/throttle-groups.c | 737 +---
 block/throttle.c| 250 ++
 blockdev.c  |   4 +-
 tests/test-throttle.c   | 111 +++---
 util/throttle.c | 151 
 block/Makefile.objs |   1 +
 tests/qemu-iotests/184  | 205 +++
 tests/qemu-iotests/184.out  | 300 
 tests/qemu-iotests/group|   1 +
 16 files changed, 1706 insertions(+), 321 deletions(-)
 create mode 100644 block/throttle.c
 create mode 100755 tests/qemu-iotests/184
 create mode 100644 tests/qemu-iotests/184.out

-- 
2.11.0




Re: [Qemu-devel] [PATCH v2 3/6] block: require job-id when device is a node name

2017-08-21 Thread Manos Pitsidianakis

On Mon, Aug 21, 2017 at 05:05:30PM +0200, Alberto Garcia wrote:

On Wed 09 Aug 2017 04:02:53 PM CEST, Manos Pitsidianakis wrote:

@@ -622,20 +622,14 @@ void *block_job_create(const char *job_id, const 
BlockJobDriver *driver,
 return NULL;
 }

-if (job_id == NULL && !(flags & BLOCK_JOB_INTERNAL)) {
-job_id = bdrv_get_device_name(bs);
-if (!*job_id) {
-error_setg(errp, "An explicit job ID is required for this node");
-return NULL;
-}
-}
-
-if (job_id) {
-if (flags & BLOCK_JOB_INTERNAL) {
+if (flags & BLOCK_JOB_INTERNAL) {
+if (job_id) {
 error_setg(errp, "Cannot specify job ID for internal block job");
 return NULL;
 }


When BLOCK_JOB_INTERNAL is set, then job_id must be NULL...


-
+} else {
+/* Require job-id. */
+assert(job_id);
 if (!id_wellformed(job_id)) {
 error_setg(errp, "Invalid job ID '%s'", job_id);
 return NULL;
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
index f13ad05c0d..ff906808a6 100644
--- a/include/block/blockjob_int.h
+++ b/include/block/blockjob_int.h
@@ -112,8 +112,7 @@ struct BlockJobDriver {

 /**
  * block_job_create:
- * @job_id: The id of the newly-created job, or %NULL to have one
- * generated automatically.
+ * @job_id: The id of the newly-created job, must be non %NULL.


...but here you say that it must not be NULL.

And since job_id can be NULL in some cases I think I'd replace the
assert(job_id) that you added to block_job_create() with a normal
pointer check + error_setg().


@@ -93,9 +93,6 @@ static void test_job_ids(void)
 blk[1] = create_blk("drive1");
 blk[2] = create_blk("drive2");

-/* No job ID provided and the block backend has no name */
-job[0] = do_test_id(blk[0], NULL, false);
-


If you decide to handle NULL ids by returning and error instead of
asserting, we should keep a couple of tests for that scenario.

Berto



Thanks, I will change that. What cases are you thinking of besides 
internal jobs though? And should documentation of block_job_create 
reflect that internal jobs have job_id == NULL?


signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH 3/4] throttle: Remove throttle_fix_bucket() / throttle_unfix_bucket()

2017-08-21 Thread Manos Pitsidianakis

On Mon, Aug 21, 2017 at 02:10:59PM +0200, Alberto Garcia wrote:

On Sat 19 Aug 2017 05:23:12 PM CEST, Manos Pitsidianakis wrote:

-/* If the bucket is full then we have to wait */
-extra = bkt->level - bkt->max * bkt->burst_length;
+if (!bkt->max) {
+/* If bkt->max is 0 we still want to allow short bursts of I/O
+ * from the guest, otherwise every other request will be throttled
+ * and performance will suffer considerably. */
+bucket_size = bkt->avg / 10;
+burst_bucket_size = 0;


Might be wrong, but shouldn't that be
bucket_size = (bkt->avg / 10) * bkt->burst_length?
burst_bucket_size = (bkt->avg / 10) / 10;


if !bkt->max then the user didn't define any bursts, and the I/O is only
throttled to the rate set in bkt->avg.


+} else {
+/* If we have a burst limit then we have to wait until all I/O
+ * at burst rate has finished before throttling to bkt->avg */
+bucket_size = bkt->max * bkt->burst_length;
+burst_bucket_size = bkt->max / 10;
+}
+
+/* If the main bucket is full then we have to wait */
+extra = bkt->level - bucket_size;

because it used to be that if bkt->max is 0 then
 extra = bkt->level - (bkt->avg /10) * bkt->burst_length; //fixed value
 and now it's
 extra = bkt->level - (bkt->avg / 10);

 and


if (extra > 0) {
return throttle_do_compute_wait(bkt->avg, extra);
}

-/* If the bucket is not full yet we have to make sure that we
- * fulfill the goal of bkt->max units per second. */
+/* If the main bucket is not full yet we still have to check the
+ * burst bucket in order to enforce the burst limit */
if (bkt->burst_length > 1) {
-/* We use 1/10 of the max value to smooth the throttling.
- * See throttle_fix_bucket() for more details. */
-extra = bkt->burst_level - bkt->max / 10;
+extra = bkt->burst_level - burst_bucket_size;

This used to be

extra = bkt->burst_level - (bkt->avg / 10) / 10;
and now it's
extra = bkt->burst_level  - 0;


No, if bkt->burst_length > 1 then bkt->max != 0, and therefore
burst_bucket_size is never 0 either.

Perhaps you missed the ! in the first "if (!bkt->max)" ?


Now it makes sense, thanks :) I reread the patch and you can add

Reviewed-by: Manos Pitsidianakis <el13...@mail.ntua.gr>


signature.asc
Description: PGP signature


[Qemu-devel] [PATCH v6 3/6] block: tidy ThrottleGroupMember initializations

2017-08-21 Thread Manos Pitsidianakis
Move the CoMutex and CoQueue inits inside throttle_group_register_tgm()
which is called whenever a ThrottleGroupMember is initialized. There's
no need for them to be separate.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block/block-backend.c   | 3 ---
 block/throttle-groups.c | 3 +++
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 9ba800e733..c51fb8c8aa 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -252,9 +252,6 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
 blk->shared_perm = shared_perm;
 blk_set_enable_write_cache(blk, true);
 
-qemu_co_mutex_init(>public.throttle_group_member.throttled_reqs_lock);
-qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[0]);
-qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[1]);
 block_acct_init(>stats);
 
 notifier_list_init(>remove_bs_notifiers);
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index 3b07b25f39..7749cf043f 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -508,6 +508,9 @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm,
  read_timer_cb,
  write_timer_cb,
  tgm);
+qemu_co_mutex_init(>throttled_reqs_lock);
+qemu_co_queue_init(>throttled_reqs[0]);
+qemu_co_queue_init(>throttled_reqs[1]);
 
 qemu_mutex_unlock(>lock);
 }
-- 
2.11.0




[Qemu-devel] [PATCH v6 1/6] block: move ThrottleGroup membership to ThrottleGroupMember

2017-08-21 Thread Manos Pitsidianakis
This commit eliminates the 1:1 relationship between BlockBackend and
throttle group state.  Users will be able to create multiple throttle
nodes, each with its own throttle group state, in the future.  The
throttle group state cannot be per-BlockBackend anymore, it must be
per-throttle node. This is done by gathering ThrottleGroup membership
details from BlockBackendPublic into ThrottleGroupMember and refactoring
existing code to use the structure.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 include/block/throttle-groups.h |  39 +-
 include/sysemu/block-backend.h  |  20 +--
 block/block-backend.c   |  66 +
 block/qapi.c|   8 +-
 block/throttle-groups.c | 288 
 blockdev.c  |   4 +-
 tests/test-throttle.c   |  53 
 7 files changed, 252 insertions(+), 226 deletions(-)

diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
index d983d34074..1a6bcdae74 100644
--- a/include/block/throttle-groups.h
+++ b/include/block/throttle-groups.h
@@ -28,19 +28,44 @@
 #include "qemu/throttle.h"
 #include "block/block_int.h"
 
-const char *throttle_group_get_name(BlockBackend *blk);
+/* The ThrottleGroupMember structure indicates membership in a ThrottleGroup
+ * and holds related data.
+ */
+
+typedef struct ThrottleGroupMember {
+/* throttled_reqs_lock protects the CoQueues for throttled requests.  */
+CoMutex  throttled_reqs_lock;
+CoQueue  throttled_reqs[2];
+
+/* Nonzero if the I/O limits are currently being ignored; generally
+ * it is zero.  Accessed with atomic operations.
+ */
+unsigned int io_limits_disabled;
+
+/* The following fields are protected by the ThrottleGroup lock.
+ * See the ThrottleGroup documentation for details.
+ * throttle_state tells us if I/O limits are configured. */
+ThrottleState *throttle_state;
+ThrottleTimers throttle_timers;
+unsigned   pending_reqs[2];
+QLIST_ENTRY(ThrottleGroupMember) round_robin;
+
+} ThrottleGroupMember;
+
+const char *throttle_group_get_name(ThrottleGroupMember *tgm);
 
 ThrottleState *throttle_group_incref(const char *name);
 void throttle_group_unref(ThrottleState *ts);
 
-void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg);
-void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg);
+void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
+void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
 
-void throttle_group_register_blk(BlockBackend *blk, const char *groupname);
-void throttle_group_unregister_blk(BlockBackend *blk);
-void throttle_group_restart_blk(BlockBackend *blk);
+void throttle_group_register_tgm(ThrottleGroupMember *tgm,
+const char *groupname);
+void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
+void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
 
-void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk,
+void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember 
*tgm,
 unsigned int bytes,
 bool is_write);
 
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 4a3730596b..0e0cda7521 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -70,24 +70,10 @@ typedef struct BlockDevOps {
 
 /* This struct is embedded in (the private) BlockBackend struct and contains
  * fields that must be public. This is in particular for QLIST_ENTRY() and
- * friends so that BlockBackends can be kept in lists outside block-backend.c 
*/
+ * friends so that BlockBackends can be kept in lists outside block-backend.c
+ * */
 typedef struct BlockBackendPublic {
-/* throttled_reqs_lock protects the CoQueues for throttled requests.  */
-CoMutex  throttled_reqs_lock;
-CoQueue  throttled_reqs[2];
-
-/* Nonzero if the I/O limits are currently being ignored; generally
- * it is zero.  Accessed with atomic operations.
- */
-unsigned int io_limits_disabled;
-
-/* The following fields are protected by the ThrottleGroup lock.
- * See the ThrottleGroup documentation for details.
- * throttle_state tells us if I/O limits are configured. */
-ThrottleState *throttle_state;
-ThrottleTimers throttle_timers;
-unsigned   pending_reqs[2];
-QLIST_ENTRY(BlockBackendPublic) round_robin;
+ThrottleGroupMember throttle_group_member;
 } BlockBackendPublic;
 
 BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm);
diff --git a/block/block-backend.c b/block/block-backend.c
index e9798e897d..7b981e00bb 100644
--- a/block/block

[Qemu-devel] [PATCH v6 4/6] block: convert ThrottleGroup to object with QOM

2017-08-21 Thread Manos Pitsidianakis
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 throttle-group,id=foo,x-iops-total=100,x-..
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": "throttle-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 <el13...@mail.ntua.gr>
---
 qapi/block-core.json|  48 +
 include/block/throttle-groups.h |   3 +
 include/qemu/throttle-options.h |  59 --
 include/qemu/throttle.h |   3 +
 block/throttle-groups.c | 416 
 tests/test-throttle.c   |   1 +
 util/throttle.c | 151 +++
 7 files changed, 621 insertions(+), 60 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 833c602150..0bdc69aa5f 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1905,6 +1905,54 @@
 '*iops_size': 'int', '*group': 'str' } }
 
 ##
+# @ThrottleLimits:
+#
+# Limit parameters for throttling.
+# Since some limit combinations are illegal, limits should always be set in one
+# transaction. All fields are optional. When setting limits, if a field is
+# missing the current value is not changed.
+#
+# @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.11
+##
+{ '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', 

[Qemu-devel] [PATCH v6 5/6] block: add throttle block filter driver

2017-08-21 Thread Manos Pitsidianakis
block/throttle.c uses existing I/O throttle infrastructure inside a
block filter driver. I/O operations are intercepted in the filter's
read/write coroutines, and referred to block/throttle-groups.c

The driver can be used with the syntax
-drive driver=throttle,file.filename=foo.qcow2, \
limits.iops-total=...

which creates an anonymous group with the specified limits, or
-drive driver=throttle,file.filename=foo.qcow2,throttle-group=bar

which registers the throttle filter node with the ThrottleGroup bar. The
given groups must be created with object-add or -object.

The limit parameters and their semantics are identical to the
hardcoded throttling ones. limits.* cannot be specified at the same time
as throttle-group.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 qapi/block-core.json|  22 ++-
 include/qapi/qmp/qdict.h|   1 +
 include/qemu/throttle-options.h |   1 +
 block/throttle-groups.c |   5 +
 block/throttle.c| 332 
 qobject/qdict.c |   2 +-
 block/Makefile.objs |   1 +
 7 files changed, 362 insertions(+), 2 deletions(-)
 create mode 100644 block/throttle.c

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 0bdc69aa5f..12fd749a94 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -,6 +,7 @@
 # Drivers that are supported in block device operations.
 #
 # @vxhs: Since 2.10
+# @throttle: Since 2.11
 #
 # Since: 2.9
 ##
@@ -2231,7 +2232,7 @@
 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
 'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
 'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
-'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
+'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
 
 ##
 # @BlockdevOptionsFile:
@@ -3095,6 +3096,24 @@
 '*tls-creds': 'str' } }
 
 ##
+# @BlockdevOptionsThrottle:
+#
+# Driver specific block device options for the throttle driver
+#
+# @throttle-group:   the name of the throttle-group object to use. It will be
+#created if it doesn't already exist. If not specified, an
+#anonymous group will be created, which cannot be
+#referenced by other throttle nodes.
+# @file: reference to or definition of the data source block device
+# @limits:   ThrottleLimits options
+# Since: 2.11
+##
+{ 'struct': 'BlockdevOptionsThrottle',
+  'data': { '*throttle-group': 'str',
+'file' : 'BlockdevRef',
+'*limits' : 'ThrottleLimits'
+ } }
+##
 # @BlockdevOptions:
 #
 # Options for creating a block device.  Many options are available for all
@@ -3155,6 +3174,7 @@
   'replication':'BlockdevOptionsReplication',
   'sheepdog':   'BlockdevOptionsSheepdog',
   'ssh':'BlockdevOptionsSsh',
+  'throttle':   'BlockdevOptionsThrottle',
   'vdi':'BlockdevOptionsGenericFormat',
   'vhdx':   'BlockdevOptionsGenericFormat',
   'vmdk':   'BlockdevOptionsGenericCOWFormat',
diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
index 363e431106..c1492ba84a 100644
--- a/include/qapi/qmp/qdict.h
+++ b/include/qapi/qmp/qdict.h
@@ -80,6 +80,7 @@ QDict *qdict_clone_shallow(const QDict *src);
 void qdict_flatten(QDict *qdict);
 
 void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
+int qdict_count_prefixed_entries(const QDict *src, const char *start);
 void qdict_array_split(QDict *src, QList **dst);
 int qdict_array_entries(QDict *src, const char *subqdict);
 QObject *qdict_crumple(const QDict *src, Error **errp);
diff --git a/include/qemu/throttle-options.h b/include/qemu/throttle-options.h
index 182b7896e1..3528a8f4a2 100644
--- a/include/qemu/throttle-options.h
+++ b/include/qemu/throttle-options.h
@@ -29,6 +29,7 @@
 #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 QEMU_OPT_THROTTLE_GROUP_NAME "throttle-group"
 
 #define THROTTLE_OPT_PREFIX "throttling."
 #define THROTTLE_OPTS \
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index 15f1697671..3d81e1ac27 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -534,6 +534,11 @@ void throttle_group_unregister_tgm(ThrottleGroupMember 
*tgm)
 ThrottleGroupMember *token;
 int i;
 
+if (!ts) {
+/* Discard uninitialized tgm */
+return;
+}
+
 assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0);
 assert(qemu_co_queue_empty(>throttled_reqs[0]));
 assert(qemu_co_queue_empty(>throttled_reqs[1]));
diff --git a/block/throttle.c b/block/throttle.c
new file mode 100644
index 00..daf4af4970
--- /dev/null
+++ b/bl

[Qemu-devel] [PATCH v6 6/6] qemu-iotests: add 184 for throttle filter driver

2017-08-21 Thread Manos Pitsidianakis
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 tests/qemu-iotests/184 | 244 
 tests/qemu-iotests/184.out | 339 +
 tests/qemu-iotests/group   |   1 +
 3 files changed, 584 insertions(+)
 create mode 100755 tests/qemu-iotests/184
 create mode 100644 tests/qemu-iotests/184.out

diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
new file mode 100755
index 00..7376c5119b
--- /dev/null
+++ b/tests/qemu-iotests/184
@@ -0,0 +1,244 @@
+#!/bin/bash
+#
+# Test I/O throttle block filter driver interface
+#
+# Copyright (C) 2017 Manos Pitsidianakis
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner="Manos Pitsidianakis"
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1   # failure is the default!
+
+_cleanup()
+{
+_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+function do_run_qemu()
+{
+echo Testing: "$@" | _filter_imgfmt
+$QEMU -nographic -qmp-pretty stdio -serial none "$@"
+echo
+}
+
+function run_qemu()
+{
+do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
+  | _filter_qemu_io | _filter_generated_node_ids
+}
+
+_make_test_img 64M
+test_throttle=$($QEMU_IMG --help|grep throttle)
+[ "$test_throttle" = "" ] && _supported_fmt throttle
+
+echo
+echo "== checking interface =="
+
+run_qemu <

[Qemu-devel] [PATCH v6 2/6] block: add aio_context field in ThrottleGroupMember

2017-08-21 Thread Manos Pitsidianakis
timer_cb() needs to know about the current Aio context of the throttle
request that is woken up. In order to make ThrottleGroupMember backend
agnostic, this information is stored in an aio_context field instead of
accessing it from BlockBackend.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 include/block/throttle-groups.h |  7 -
 block/block-backend.c   | 15 --
 block/throttle-groups.c | 38 -
 tests/test-throttle.c   | 63 +
 4 files changed, 69 insertions(+), 54 deletions(-)

diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
index 1a6bcdae74..a0f27cac63 100644
--- a/include/block/throttle-groups.h
+++ b/include/block/throttle-groups.h
@@ -33,6 +33,7 @@
  */
 
 typedef struct ThrottleGroupMember {
+AioContext   *aio_context;
 /* throttled_reqs_lock protects the CoQueues for throttled requests.  */
 CoMutex  throttled_reqs_lock;
 CoQueue  throttled_reqs[2];
@@ -61,12 +62,16 @@ void throttle_group_config(ThrottleGroupMember *tgm, 
ThrottleConfig *cfg);
 void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
 
 void throttle_group_register_tgm(ThrottleGroupMember *tgm,
-const char *groupname);
+const char *groupname,
+AioContext *ctx);
 void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
 void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
 
 void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember 
*tgm,
 unsigned int bytes,
 bool is_write);
+void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
+   AioContext *new_context);
+void throttle_group_detach_aio_context(ThrottleGroupMember *tgm);
 
 #endif
diff --git a/block/block-backend.c b/block/block-backend.c
index 7b981e00bb..9ba800e733 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1726,18 +1726,14 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB 
*acb)
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
 {
 BlockDriverState *bs = blk_bs(blk);
-ThrottleTimers *tt;
+ThrottleGroupMember *tgm = >public.throttle_group_member;
 
 if (bs) {
-if (blk->public.throttle_group_member.throttle_state) {
-tt = >public.throttle_group_member.throttle_timers;
-throttle_timers_detach_aio_context(tt);
+if (tgm->throttle_state) {
+throttle_group_detach_aio_context(tgm);
+throttle_group_attach_aio_context(tgm, new_context);
 }
 bdrv_set_aio_context(bs, new_context);
-if (blk->public.throttle_group_member.throttle_state) {
-tt = >public.throttle_group_member.throttle_timers;
-throttle_timers_attach_aio_context(tt, new_context);
-}
 }
 }
 
@@ -1970,7 +1966,8 @@ void blk_io_limits_disable(BlockBackend *blk)
 void blk_io_limits_enable(BlockBackend *blk, const char *group)
 {
 assert(!blk->public.throttle_group_member.throttle_state);
-throttle_group_register_tgm(>public.throttle_group_member, group);
+throttle_group_register_tgm(>public.throttle_group_member,
+group, blk_get_aio_context(blk));
 }
 
 void blk_io_limits_update_group(BlockBackend *blk, const char *group)
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index c8ed16ddf8..3b07b25f39 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -391,9 +391,6 @@ static void coroutine_fn 
throttle_group_restart_queue_entry(void *opaque)
 
 static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool 
is_write)
 {
-BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic,
-throttle_group_member);
-BlockBackend *blk = blk_by_public(blkp);
 Coroutine *co;
 RestartData rd = {
 .tgm = tgm,
@@ -401,7 +398,7 @@ static void 
throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write
 };
 
 co = qemu_coroutine_create(throttle_group_restart_queue_entry, );
-aio_co_enter(blk_get_aio_context(blk), co);
+aio_co_enter(tgm->aio_context, co);
 }
 
 void throttle_group_restart_tgm(ThrottleGroupMember *tgm)
@@ -449,13 +446,11 @@ void throttle_group_get_config(ThrottleGroupMember *tgm, 
ThrottleConfig *cfg)
 /* ThrottleTimers callback. This wakes up a request that was waiting
  * because it had been throttled.
  *
- * @blk:   the BlockBackend whose request had been throttled
+ * @tgm:   the ThrottleGroupMember whose request had been throttled
  * @is_write:  the type of operation (rea

[Qemu-devel] [PATCH v6 0/6] add throttle block driver filter

2017-08-21 Thread Manos Pitsidianakis
This series adds a throttle block driver filter. Currently throttling is done
at the BlockBackend level. Using block driver interfaces we can move the
throttling to any point in the BDS graph using a throttle node which uses the
existing throttling code. This allows for potentially more complex
configurations (throttling at any point in the graph, chained filters)

v6:
  don't allow named group limit configuration in block/throttle.c; allow either
-drive driver=throttle,file.filename=foo.qcow2, \
limits.iops-total=...
  or
-drive driver=throttle,file.filename=foo.qcow2,throttle-group=bar
  fixes suggested by berto

v5:
  fix crash in 'add aio_context field in ThrottleGroupMember'
  fix suggestions in block/throttle.c

v4:
  fix suggestions in block/throttle.c
  fix suggestions in block/throttle_groups.c
  add doc note in BlockDevOptionsThrottle

v3:
  fix style error in 'add aio_context field in ThrottleGroupMember'

v2:
  change QOM throttle group object name
  print valid ranges for uint on error
  move frees in throttle_group_obj_finalize()
  split throttle_group_{set,get}()
  add throttle_recurse_is_first_non_filter()

Manos Pitsidianakis (6):
  block: move ThrottleGroup membership to ThrottleGroupMember
  block: add aio_context field in ThrottleGroupMember
  block: tidy ThrottleGroupMember initializations
  block: convert ThrottleGroup to object with QOM
  block: add throttle block filter driver
  qemu-iotests: add 184 for throttle filter driver

 qapi/block-core.json|  70 +++-
 include/block/throttle-groups.h |  47 ++-
 include/qapi/qmp/qdict.h|   1 +
 include/qemu/throttle-options.h |  60 ++--
 include/qemu/throttle.h |   3 +
 include/sysemu/block-backend.h  |  20 +-
 block/block-backend.c   |  62 ++--
 block/qapi.c|   8 +-
 block/throttle-groups.c | 734 +---
 block/throttle.c| 332 ++
 blockdev.c  |   4 +-
 qobject/qdict.c |   2 +-
 tests/test-throttle.c   | 111 +++---
 util/throttle.c | 151 +
 block/Makefile.objs |   1 +
 tests/qemu-iotests/184  | 244 +
 tests/qemu-iotests/184.out  | 339 +++
 tests/qemu-iotests/group|   1 +
 18 files changed, 1868 insertions(+), 322 deletions(-)
 create mode 100644 block/throttle.c
 create mode 100755 tests/qemu-iotests/184
 create mode 100644 tests/qemu-iotests/184.out

-- 
2.11.0




Re: [Qemu-devel] [PATCH 3/4] throttle: Remove throttle_fix_bucket() / throttle_unfix_bucket()

2017-08-19 Thread Manos Pitsidianakis

On Thu, Aug 17, 2017 at 05:28:14PM +0300, Alberto Garcia wrote:

The throttling code can change internally the value of bkt->max if it
hasn't been set by the user. The problem with this is that if we want
to retrieve the original value we have to undo this change first. This
is ugly and unnecessary: this patch removes the throttle_fix_bucket()
and throttle_unfix_bucket() functions completely and moves the logic
to throttle_compute_wait().

Signed-off-by: Alberto Garcia 
---
util/throttle.c | 62 +
1 file changed, 23 insertions(+), 39 deletions(-)

diff --git a/util/throttle.c b/util/throttle.c
index 9a6bda813c..1f29cf9918 100644
--- a/util/throttle.c
+++ b/util/throttle.c
@@ -95,23 +95,36 @@ static int64_t throttle_do_compute_wait(double limit, 
double extra)
int64_t throttle_compute_wait(LeakyBucket *bkt)
{
double extra; /* the number of extra units blocking the io */
+double bucket_size;   /* I/O before throttling to bkt->avg */
+double burst_bucket_size; /* Before throttling to bkt->max */

if (!bkt->avg) {
return 0;
}

-/* If the bucket is full then we have to wait */
-extra = bkt->level - bkt->max * bkt->burst_length;
+if (!bkt->max) {
+/* If bkt->max is 0 we still want to allow short bursts of I/O
+ * from the guest, otherwise every other request will be throttled
+ * and performance will suffer considerably. */
+bucket_size = bkt->avg / 10;
+burst_bucket_size = 0;


Might be wrong, but shouldn't that be
   bucket_size = (bkt->avg / 10) * bkt->burst_length?
   burst_bucket_size = (bkt->avg / 10) / 10;


+} else {
+/* If we have a burst limit then we have to wait until all I/O
+ * at burst rate has finished before throttling to bkt->avg */
+bucket_size = bkt->max * bkt->burst_length;
+burst_bucket_size = bkt->max / 10;
+}
+
+/* If the main bucket is full then we have to wait */
+extra = bkt->level - bucket_size;

because it used to be that if bkt->max is 0 then
extra = bkt->level - (bkt->avg /10) * bkt->burst_length; //fixed value
and now it's
extra = bkt->level - (bkt->avg / 10);

and


if (extra > 0) {
return throttle_do_compute_wait(bkt->avg, extra);
}

-/* If the bucket is not full yet we have to make sure that we
- * fulfill the goal of bkt->max units per second. */
+/* If the main bucket is not full yet we still have to check the
+ * burst bucket in order to enforce the burst limit */
if (bkt->burst_length > 1) {
-/* We use 1/10 of the max value to smooth the throttling.
- * See throttle_fix_bucket() for more details. */
-extra = bkt->burst_level - bkt->max / 10;
+extra = bkt->burst_level - burst_bucket_size;
This used to be 


   extra = bkt->burst_level - (bkt->avg / 10) / 10;
and now it's
   extra = bkt->burst_level  - 0;



if (extra > 0) {
return throttle_do_compute_wait(bkt->max, extra);
}
@@ -358,31 +371,6 @@ bool throttle_is_valid(ThrottleConfig *cfg, Error **errp)
return true;
}

-/* fix bucket parameters */
-static void throttle_fix_bucket(LeakyBucket *bkt)
-{
-double min;
-
-/* zero bucket level */
-bkt->level = bkt->burst_level = 0;
-
-/* If bkt->max is 0 we still want to allow short bursts of I/O
- * from the guest, otherwise every other request will be throttled
- * and performance will suffer considerably. */
-min = bkt->avg / 10;
-if (bkt->avg && !bkt->max) {
-bkt->max = min;
-}
-}
-
-/* undo internal bucket parameter changes (see throttle_fix_bucket()) */
-static void throttle_unfix_bucket(LeakyBucket *bkt)
-{
-if (bkt->max < bkt->avg) {
-bkt->max = 0;
-}
-}
-
/* Used to configure the throttle
 *
 * @ts: the throttle state we are working on
@@ -397,8 +385,10 @@ void throttle_config(ThrottleState *ts,

ts->cfg = *cfg;

+/* Zero bucket level */
for (i = 0; i < BUCKETS_COUNT; i++) {
-throttle_fix_bucket(>cfg.buckets[i]);
+ts->cfg.buckets[i].level = 0;
+ts->cfg.buckets[i].burst_level = 0;
}

ts->previous_leak = qemu_clock_get_ns(clock_type);
@@ -411,13 +401,7 @@ void throttle_config(ThrottleState *ts,
 */
void throttle_get_config(ThrottleState *ts, ThrottleConfig *cfg)
{
-int i;
-
*cfg = ts->cfg;
-
-for (i = 0; i < BUCKETS_COUNT; i++) {
-throttle_unfix_bucket(>buckets[i]);
-}
}


--
2.11.0




signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH 4/4] throttle: Make LeakyBucket.avg and LeakyBucket.max integer types

2017-08-19 Thread Manos Pitsidianakis

On Thu, Aug 17, 2017 at 05:28:15PM +0300, Alberto Garcia wrote:

Both the throttling limits set with the throttling.iops-* and
throttling.bps-* options and their QMP equivalents defined in the
BlockIOThrottle struct are integer values.

Those limits are also reported in the BlockDeviceInfo struct and they
are integers there as well.

Therefore there's no reason to store them internally as double and do
the conversion everytime we're setting or querying them, so this patch
uses int64_t for those types.

LeakyBucket.level and LeakyBucket.burst_level do however remain double
because their value changes depending on the fraction of time elapsed
since the previous I/O operation.

Signed-off-by: Alberto Garcia <be...@igalia.com>


Reviewed-by: Manos Pitsidianakis <el13...@mail.ntua.gr>


include/qemu/throttle.h | 4 ++--
util/throttle.c | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h
index 66a8ac10a4..c466f6ccaa 100644
--- a/include/qemu/throttle.h
+++ b/include/qemu/throttle.h
@@ -77,8 +77,8 @@ typedef enum {
 */

typedef struct LeakyBucket {
-double  avg;  /* average goal in units per second */
-double  max;  /* leaky bucket max burst in units */
+int64_t avg;  /* average goal in units per second */
+int64_t max;  /* leaky bucket max burst in units */
double  level;/* bucket level in units */
double  burst_level;  /* bucket level in units (for computing bursts) */
unsigned burst_length;/* max length of the burst period, in seconds */
diff --git a/util/throttle.c b/util/throttle.c
index 1f29cf9918..55a2451a14 100644
--- a/util/throttle.c
+++ b/util/throttle.c
@@ -106,13 +106,13 @@ int64_t throttle_compute_wait(LeakyBucket *bkt)
/* If bkt->max is 0 we still want to allow short bursts of I/O
 * from the guest, otherwise every other request will be throttled
 * and performance will suffer considerably. */
-bucket_size = bkt->avg / 10;
+bucket_size = (double) bkt->avg / 10;
burst_bucket_size = 0;
} else {
/* If we have a burst limit then we have to wait until all I/O
 * at burst rate has finished before throttling to bkt->avg */
bucket_size = bkt->max * bkt->burst_length;
-burst_bucket_size = bkt->max / 10;
+burst_bucket_size = (double) bkt->max / 10;
}

/* If the main bucket is full then we have to wait */
--
2.11.0




signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH 1/4] throttle: Fix wrong variable name in the header documentation

2017-08-19 Thread Manos Pitsidianakis

On Thu, Aug 17, 2017 at 05:28:12PM +0300, Alberto Garcia wrote:

The level of the burst bucket is stored in bkt.burst_level, not
bkt.burst_lenght.


s/lenght/length, otherwise:

Reviewed-by: Manos Pitsidianakis <el13...@mail.ntua.gr>


Signed-off-by: Alberto Garcia <be...@igalia.com>
---
include/qemu/throttle.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h
index d056008c18..66a8ac10a4 100644
--- a/include/qemu/throttle.h
+++ b/include/qemu/throttle.h
@@ -63,7 +63,7 @@ typedef enum {
 * - The bkt.avg rate does not apply until the bucket is full,
 *   allowing the user to do bursts until then. The I/O limit during
 *   bursts is bkt.max. To enforce this limit we keep an additional
- *   bucket in bkt.burst_length that leaks at a rate of bkt.max units
+ *   bucket in bkt.burst_level that leaks at a rate of bkt.max units
 *   per second.
 *
 * - Because of all of the above, the user can perform I/O at a
--
2.11.0




signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH v5 4/6] block: convert ThrottleGroup to object with QOM

2017-08-19 Thread Manos Pitsidianakis

On Fri, Aug 18, 2017 at 03:05:31PM +0200, Alberto Garcia wrote:

On Fri 18 Aug 2017 05:10:17 AM CEST, Manos Pitsidianakis wrote:


  * If no ThrottleGroup is found with the given name a new one is
  * created.
  *
- * @name: the name of the ThrottleGroup
+ * This function edits throttle_groups and must be called under the global
+ * mutex.
+ *
+ * @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)


If we're not going to have anonymous groups in the end this patch needs
changes (name == NULL is no longer allowed).


+/* This function edits throttle_groups and must be called under the global
+ * mutex */
+static void throttle_group_obj_complete(UserCreatable *obj, Error **errp)
+{
+ThrottleGroup *tg = THROTTLE_GROUP(obj), *iter;
+ThrottleConfig *cfg = >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, _groups, list) {
+if (!g_strcmp0(tg->name, iter->name) && tg != iter) {


I'm just nitpicking here :) but if you change this and put 'tg != iter'
first you'll save one unnecessary string comparison.


Only in the case where tg == iter, otherwise you have one unnecessary 
pointer comparison for every other group.



+error_setg(errp, "A group with this name already exists");
+return;
+}
+}
+}
+
+/* unfix buckets to check validity */
+throttle_get_config(>ts, cfg);
+if (!throttle_is_valid(cfg, errp)) {
+return;
+}
+/* fix buckets again */
+throttle_config(>ts, tg->clock_type, cfg);


throttle_get_config(ts, cfg) makes a copy of the existing configuration,
but the cfg pointer that you are passing already points to the existing
configuration, so in practice you are doing

   *(ts->cfg) = *(ts->cfg);
   throttle_unfix_bucket(...);

and since you "unfixed" the configuration, then you need undo the whole
thing by setting the config again:

   *(ts->cfg) = *(ts->cfg);
   throttle_fix_bucket(...);

You should declare a local ThrottleConfig variable, copy the config
there, and run throttle_is_valid() on that copy. The final
throttle_config() call is unnecessary.


I figured I didn't have to make an extra copy but this looks bad in 
retrospect




Once the patches I sent yesterday are merged we'll be able to skip the
throttle_get_config() call and do throttle_is_valid(>ts.cfg, errp)
directly.


+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;
+Error *local_err = NULL;
+int64_t value;
+
+/* 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(_err, "Property cannot be set after initialization");
+goto ret;
+}
+
+visit_type_int64(v, name, , _err);
+if (local_err) {
+goto ret;
+}
+if (value < 0) {
+error_setg(_err, "Property values cannot be negative");
+goto ret;
+}
+
+cfg = tg->ts.cfg;
+switch (info->data_type) {
+case UINT64:
+{
+uint64_t *field = (void *)[info->type] + info->offset;
+*field = value;
+}
+break;
+case DOUBLE:
+{
+double *field = (void *)[info->type] + info->offset;
+*field = value;
+}
+break;
+case UNSIGNED:
+{
+if (value > UINT_MAX) {
+error_setg(_err, "%s value must be in the"
+   "range [0, %u]", info->name, UINT_MAX);
+goto ret;
+}
+unsigned *field = (void *)[info->type] + info->offset;
+*field = value;
+}
+}
+
+tg->ts.cfg = cfg;


There's a bit of black magic here :)


This offset business is indeed black magic! And university makes you 
think the world runs on ML and Haskell...



you have a user-defined enumeration
(UNSIGNED, DOUBLE, UINT64) to identify C types and I'm worried about
what happens if the data types of LeakyBucket change, will we be able to
detect the problem?

Out of the blue I can think of the following alternative:

  - There's 6 different buckets (we have BucketType listing them)

  - There's 3 va

Re: [Qemu-devel] [PATCH v5 5/6] block: add throttle block filter driver

2017-08-18 Thread Manos Pitsidianakis

On Fri, Aug 18, 2017 at 10:23:09AM +0200, Alberto Garcia wrote:

On Fri 18 Aug 2017 05:10:18 AM CEST, Manos Pitsidianakis wrote:

block/throttle.c uses existing I/O throttle infrastructure inside a
block filter driver. I/O operations are intercepted in the filter's
read/write coroutines, and referred to block/throttle-groups.c

The driver can be used with the syntax
-drive driver=throttle,file.filename=foo.qcow2, \
limits.iops-total=...,throttle-group=bar


I had understood that we would get rid of the limits.* options in this
driver, or did I get it wrong?

Other than that, the rest of the code looks perfect to me.

Berto



I was going to send a patch after this was merged along with adding 
ThrottleGroups to the root container, to speed things up. Do you prefer 
to do this in this patch?


The root container patch probably has to go to the 'remove legacy' 
series since adding it here means the name collision errors introduce 
error paths in block/block-backend.c that go away in that series, and 
that'd be a waste of effort.


signature.asc
Description: PGP signature


[Qemu-devel] [PATCH v5 4/6] block: convert ThrottleGroup to object with QOM

2017-08-17 Thread Manos Pitsidianakis
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 throttle-group,id=foo,x-iops-total=100,x-..
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": "throttle-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 <el13...@mail.ntua.gr>
---
 qapi/block-core.json|  48 +
 include/block/throttle-groups.h |   3 +
 include/qemu/throttle-options.h |  59 --
 include/qemu/throttle.h |   3 +
 block/throttle-groups.c | 421 
 tests/test-throttle.c   |   1 +
 util/throttle.c | 151 ++
 7 files changed, 626 insertions(+), 60 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 833c602150..0bdc69aa5f 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1905,6 +1905,54 @@
 '*iops_size': 'int', '*group': 'str' } }
 
 ##
+# @ThrottleLimits:
+#
+# Limit parameters for throttling.
+# Since some limit combinations are illegal, limits should always be set in one
+# transaction. All fields are optional. When setting limits, if a field is
+# missing the current value is not changed.
+#
+# @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.11
+##
+{ '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', 

[Qemu-devel] [PATCH v5 1/6] block: move ThrottleGroup membership to ThrottleGroupMember

2017-08-17 Thread Manos Pitsidianakis
This commit eliminates the 1:1 relationship between BlockBackend and
throttle group state.  Users will be able to create multiple throttle
nodes, each with its own throttle group state, in the future.  The
throttle group state cannot be per-BlockBackend anymore, it must be
per-throttle node. This is done by gathering ThrottleGroup membership
details from BlockBackendPublic into ThrottleGroupMember and refactoring
existing code to use the structure.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 include/block/throttle-groups.h |  39 +-
 include/sysemu/block-backend.h  |  20 +--
 block/block-backend.c   |  66 +
 block/qapi.c|   8 +-
 block/throttle-groups.c | 288 
 blockdev.c  |   4 +-
 tests/test-throttle.c   |  53 
 7 files changed, 252 insertions(+), 226 deletions(-)

diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
index d983d34074..1a6bcdae74 100644
--- a/include/block/throttle-groups.h
+++ b/include/block/throttle-groups.h
@@ -28,19 +28,44 @@
 #include "qemu/throttle.h"
 #include "block/block_int.h"
 
-const char *throttle_group_get_name(BlockBackend *blk);
+/* The ThrottleGroupMember structure indicates membership in a ThrottleGroup
+ * and holds related data.
+ */
+
+typedef struct ThrottleGroupMember {
+/* throttled_reqs_lock protects the CoQueues for throttled requests.  */
+CoMutex  throttled_reqs_lock;
+CoQueue  throttled_reqs[2];
+
+/* Nonzero if the I/O limits are currently being ignored; generally
+ * it is zero.  Accessed with atomic operations.
+ */
+unsigned int io_limits_disabled;
+
+/* The following fields are protected by the ThrottleGroup lock.
+ * See the ThrottleGroup documentation for details.
+ * throttle_state tells us if I/O limits are configured. */
+ThrottleState *throttle_state;
+ThrottleTimers throttle_timers;
+unsigned   pending_reqs[2];
+QLIST_ENTRY(ThrottleGroupMember) round_robin;
+
+} ThrottleGroupMember;
+
+const char *throttle_group_get_name(ThrottleGroupMember *tgm);
 
 ThrottleState *throttle_group_incref(const char *name);
 void throttle_group_unref(ThrottleState *ts);
 
-void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg);
-void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg);
+void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
+void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
 
-void throttle_group_register_blk(BlockBackend *blk, const char *groupname);
-void throttle_group_unregister_blk(BlockBackend *blk);
-void throttle_group_restart_blk(BlockBackend *blk);
+void throttle_group_register_tgm(ThrottleGroupMember *tgm,
+const char *groupname);
+void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
+void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
 
-void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk,
+void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember 
*tgm,
 unsigned int bytes,
 bool is_write);
 
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 4a3730596b..0e0cda7521 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -70,24 +70,10 @@ typedef struct BlockDevOps {
 
 /* This struct is embedded in (the private) BlockBackend struct and contains
  * fields that must be public. This is in particular for QLIST_ENTRY() and
- * friends so that BlockBackends can be kept in lists outside block-backend.c 
*/
+ * friends so that BlockBackends can be kept in lists outside block-backend.c
+ * */
 typedef struct BlockBackendPublic {
-/* throttled_reqs_lock protects the CoQueues for throttled requests.  */
-CoMutex  throttled_reqs_lock;
-CoQueue  throttled_reqs[2];
-
-/* Nonzero if the I/O limits are currently being ignored; generally
- * it is zero.  Accessed with atomic operations.
- */
-unsigned int io_limits_disabled;
-
-/* The following fields are protected by the ThrottleGroup lock.
- * See the ThrottleGroup documentation for details.
- * throttle_state tells us if I/O limits are configured. */
-ThrottleState *throttle_state;
-ThrottleTimers throttle_timers;
-unsigned   pending_reqs[2];
-QLIST_ENTRY(BlockBackendPublic) round_robin;
+ThrottleGroupMember throttle_group_member;
 } BlockBackendPublic;
 
 BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm);
diff --git a/block/block-backend.c b/block/block-backend.c
index e9798e897d..7b981e00bb 100644
--- a/block/block

[Qemu-devel] [PATCH v5 2/6] block: add aio_context field in ThrottleGroupMember

2017-08-17 Thread Manos Pitsidianakis
timer_cb() needs to know about the current Aio context of the throttle
request that is woken up. In order to make ThrottleGroupMember backend
agnostic, this information is stored in an aio_context field instead of
accessing it from BlockBackend.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 include/block/throttle-groups.h |  7 -
 block/block-backend.c   | 15 --
 block/throttle-groups.c | 38 -
 tests/test-throttle.c   | 63 +
 4 files changed, 69 insertions(+), 54 deletions(-)

diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
index 1a6bcdae74..a0f27cac63 100644
--- a/include/block/throttle-groups.h
+++ b/include/block/throttle-groups.h
@@ -33,6 +33,7 @@
  */
 
 typedef struct ThrottleGroupMember {
+AioContext   *aio_context;
 /* throttled_reqs_lock protects the CoQueues for throttled requests.  */
 CoMutex  throttled_reqs_lock;
 CoQueue  throttled_reqs[2];
@@ -61,12 +62,16 @@ void throttle_group_config(ThrottleGroupMember *tgm, 
ThrottleConfig *cfg);
 void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
 
 void throttle_group_register_tgm(ThrottleGroupMember *tgm,
-const char *groupname);
+const char *groupname,
+AioContext *ctx);
 void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
 void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
 
 void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember 
*tgm,
 unsigned int bytes,
 bool is_write);
+void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
+   AioContext *new_context);
+void throttle_group_detach_aio_context(ThrottleGroupMember *tgm);
 
 #endif
diff --git a/block/block-backend.c b/block/block-backend.c
index 7b981e00bb..9ba800e733 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1726,18 +1726,14 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB 
*acb)
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
 {
 BlockDriverState *bs = blk_bs(blk);
-ThrottleTimers *tt;
+ThrottleGroupMember *tgm = >public.throttle_group_member;
 
 if (bs) {
-if (blk->public.throttle_group_member.throttle_state) {
-tt = >public.throttle_group_member.throttle_timers;
-throttle_timers_detach_aio_context(tt);
+if (tgm->throttle_state) {
+throttle_group_detach_aio_context(tgm);
+throttle_group_attach_aio_context(tgm, new_context);
 }
 bdrv_set_aio_context(bs, new_context);
-if (blk->public.throttle_group_member.throttle_state) {
-tt = >public.throttle_group_member.throttle_timers;
-throttle_timers_attach_aio_context(tt, new_context);
-}
 }
 }
 
@@ -1970,7 +1966,8 @@ void blk_io_limits_disable(BlockBackend *blk)
 void blk_io_limits_enable(BlockBackend *blk, const char *group)
 {
 assert(!blk->public.throttle_group_member.throttle_state);
-throttle_group_register_tgm(>public.throttle_group_member, group);
+throttle_group_register_tgm(>public.throttle_group_member,
+group, blk_get_aio_context(blk));
 }
 
 void blk_io_limits_update_group(BlockBackend *blk, const char *group)
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index c8ed16ddf8..3b07b25f39 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -391,9 +391,6 @@ static void coroutine_fn 
throttle_group_restart_queue_entry(void *opaque)
 
 static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool 
is_write)
 {
-BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic,
-throttle_group_member);
-BlockBackend *blk = blk_by_public(blkp);
 Coroutine *co;
 RestartData rd = {
 .tgm = tgm,
@@ -401,7 +398,7 @@ static void 
throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write
 };
 
 co = qemu_coroutine_create(throttle_group_restart_queue_entry, );
-aio_co_enter(blk_get_aio_context(blk), co);
+aio_co_enter(tgm->aio_context, co);
 }
 
 void throttle_group_restart_tgm(ThrottleGroupMember *tgm)
@@ -449,13 +446,11 @@ void throttle_group_get_config(ThrottleGroupMember *tgm, 
ThrottleConfig *cfg)
 /* ThrottleTimers callback. This wakes up a request that was waiting
  * because it had been throttled.
  *
- * @blk:   the BlockBackend whose request had been throttled
+ * @tgm:   the ThrottleGroupMember whose request had been throttled
  * @is_write:  the type of operation (rea

[Qemu-devel] [PATCH v5 5/6] block: add throttle block filter driver

2017-08-17 Thread Manos Pitsidianakis
block/throttle.c uses existing I/O throttle infrastructure inside a
block filter driver. I/O operations are intercepted in the filter's
read/write coroutines, and referred to block/throttle-groups.c

The driver can be used with the syntax
-drive driver=throttle,file.filename=foo.qcow2, \
limits.iops-total=...,throttle-group=bar

The configuration flags and their semantics are identical to the
hardcoded throttling ones.

A node can be created referring to an existing group, and will overwrite
its limits if any are specified, otherwise they are retained.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 qapi/block-core.json|  22 ++-
 include/qemu/throttle-options.h |   1 +
 block/throttle.c| 314 
 block/Makefile.objs |   1 +
 4 files changed, 337 insertions(+), 1 deletion(-)
 create mode 100644 block/throttle.c

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 0bdc69aa5f..12fd749a94 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -,6 +,7 @@
 # Drivers that are supported in block device operations.
 #
 # @vxhs: Since 2.10
+# @throttle: Since 2.11
 #
 # Since: 2.9
 ##
@@ -2231,7 +2232,7 @@
 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
 'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
 'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
-'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
+'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
 
 ##
 # @BlockdevOptionsFile:
@@ -3095,6 +3096,24 @@
 '*tls-creds': 'str' } }
 
 ##
+# @BlockdevOptionsThrottle:
+#
+# Driver specific block device options for the throttle driver
+#
+# @throttle-group:   the name of the throttle-group object to use. It will be
+#created if it doesn't already exist. If not specified, an
+#anonymous group will be created, which cannot be
+#referenced by other throttle nodes.
+# @file: reference to or definition of the data source block device
+# @limits:   ThrottleLimits options
+# Since: 2.11
+##
+{ 'struct': 'BlockdevOptionsThrottle',
+  'data': { '*throttle-group': 'str',
+'file' : 'BlockdevRef',
+'*limits' : 'ThrottleLimits'
+ } }
+##
 # @BlockdevOptions:
 #
 # Options for creating a block device.  Many options are available for all
@@ -3155,6 +3174,7 @@
   'replication':'BlockdevOptionsReplication',
   'sheepdog':   'BlockdevOptionsSheepdog',
   'ssh':'BlockdevOptionsSsh',
+  'throttle':   'BlockdevOptionsThrottle',
   'vdi':'BlockdevOptionsGenericFormat',
   'vhdx':   'BlockdevOptionsGenericFormat',
   'vmdk':   'BlockdevOptionsGenericCOWFormat',
diff --git a/include/qemu/throttle-options.h b/include/qemu/throttle-options.h
index 182b7896e1..3528a8f4a2 100644
--- a/include/qemu/throttle-options.h
+++ b/include/qemu/throttle-options.h
@@ -29,6 +29,7 @@
 #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 QEMU_OPT_THROTTLE_GROUP_NAME "throttle-group"
 
 #define THROTTLE_OPT_PREFIX "throttling."
 #define THROTTLE_OPTS \
diff --git a/block/throttle.c b/block/throttle.c
new file mode 100644
index 00..6484c2ae2a
--- /dev/null
+++ b/block/throttle.c
@@ -0,0 +1,314 @@
+/*
+ * QEMU block throttling filter driver infrastructure
+ *
+ * Copyright (c) 2017 Manos Pitsidianakis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "block/throttle-groups.h"
+#include "qemu/throttle-options.h"
+#include "qapi/error.h"
+
+#undef THROTTLE_OPT_PREFIX
+#define THROTTLE_OPT_PREFIX "limits."
+static QemuOptsList throttle_opts = {
+.name = "throttle",
+.head = QTAILQ_HEAD_INITIALIZER(throttle_opts.head),
+.desc = {
+THROTTLE_OPTS,
+{
+.name = QEMU_OPT_THROTTLE_GROUP_NAME,
+.type = QEMU_OPT_STRING,
+.help = "throttle group name",
+},
+{ /* end of list */ }
+},
+};
+
+/* Extract ThrottleConfi

[Qemu-devel] [PATCH v5 3/6] block: tidy ThrottleGroupMember initializations

2017-08-17 Thread Manos Pitsidianakis
Move the CoMutex and CoQueue inits inside throttle_group_register_tgm()
which is called whenever a ThrottleGroupMember is initialized. There's
no need for them to be separate.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block/block-backend.c   | 3 ---
 block/throttle-groups.c | 3 +++
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 9ba800e733..c51fb8c8aa 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -252,9 +252,6 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
 blk->shared_perm = shared_perm;
 blk_set_enable_write_cache(blk, true);
 
-qemu_co_mutex_init(>public.throttle_group_member.throttled_reqs_lock);
-qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[0]);
-qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[1]);
 block_acct_init(>stats);
 
 notifier_list_init(>remove_bs_notifiers);
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index 3b07b25f39..7749cf043f 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -508,6 +508,9 @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm,
  read_timer_cb,
  write_timer_cb,
  tgm);
+qemu_co_mutex_init(>throttled_reqs_lock);
+qemu_co_queue_init(>throttled_reqs[0]);
+qemu_co_queue_init(>throttled_reqs[1]);
 
 qemu_mutex_unlock(>lock);
 }
-- 
2.11.0




[Qemu-devel] [PATCH v5 0/6] add throttle block driver filter

2017-08-17 Thread Manos Pitsidianakis
This series adds a throttle block driver filter. Currently throttling is done
at the BlockBackend level. Using block driver interfaces we can move the
throttling to any point in the BDS graph using a throttle node which uses the
existing throttling code. This allows for potentially more complex
configurations (throttling at any point in the graph, chained filters)

v5:
  fix crash in 'add aio_context field in ThrottleGroupMember'
  fix suggestions in block/throttle.c

v4:
  fix suggestions in block/throttle.c
  fix suggestions in block/throttle_groups.c
  add doc note in BlockDevOptionsThrottle

v3:
  fix style error in 'add aio_context field in ThrottleGroupMember'

v2:
  change QOM throttle group object name
  print valid ranges for uint on error
  move frees in throttle_group_obj_finalize()
  split throttle_group_{set,get}()
  add throttle_recurse_is_first_non_filter()

Manos Pitsidianakis (6):
  block: move ThrottleGroup membership to ThrottleGroupMember
  block: add aio_context field in ThrottleGroupMember
  block: tidy ThrottleGroupMember initializations
  block: convert ThrottleGroup to object with QOM
  block: add throttle block filter driver
  block: add iotest 184 for the throttle filter driver

 qapi/block-core.json|  70 +++-
 include/block/throttle-groups.h |  47 ++-
 include/qemu/throttle-options.h |  60 ++--
 include/qemu/throttle.h |   3 +
 include/sysemu/block-backend.h  |  20 +-
 block/block-backend.c   |  62 ++--
 block/qapi.c|   8 +-
 block/throttle-groups.c | 734 +---
 block/throttle.c| 314 +
 blockdev.c  |   4 +-
 tests/test-throttle.c   | 111 +++---
 util/throttle.c | 151 +
 block/Makefile.objs |   1 +
 tests/qemu-iotests/184  | 310 +
 tests/qemu-iotests/184.out  | 422 +++
 tests/qemu-iotests/group|   1 +
 16 files changed, 1997 insertions(+), 321 deletions(-)
 create mode 100644 block/throttle.c
 create mode 100755 tests/qemu-iotests/184
 create mode 100644 tests/qemu-iotests/184.out

-- 
2.11.0




[Qemu-devel] [PATCH v5 6/6] block: add iotest 184 for the throttle filter driver

2017-08-17 Thread Manos Pitsidianakis
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 tests/qemu-iotests/184 | 310 +
 tests/qemu-iotests/184.out | 422 +
 tests/qemu-iotests/group   |   1 +
 3 files changed, 733 insertions(+)
 create mode 100755 tests/qemu-iotests/184
 create mode 100644 tests/qemu-iotests/184.out

diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
new file mode 100755
index 00..5c11d1123d
--- /dev/null
+++ b/tests/qemu-iotests/184
@@ -0,0 +1,310 @@
+#!/bin/bash
+#
+# Test I/O throttle block filter driver interface
+#
+# Copyright (C) 2017 Manos Pitsidianakis
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner="Manos Pitsidianakis"
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1   # failure is the default!
+
+_cleanup()
+{
+_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+function do_run_qemu()
+{
+echo Testing: "$@" | _filter_imgfmt
+$QEMU -nographic -qmp-pretty stdio -serial none "$@"
+echo
+}
+
+function run_qemu()
+{
+do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
+  | _filter_qemu_io | _filter_generated_node_ids
+}
+
+_make_test_img 64M
+test_throttle=$($QEMU_IMG --help|grep throttle)
+[ "$test_throttle" = "" ] && _supported_fmt throttle
+
+echo
+echo "== checking interface =="
+
+run_qemu <

Re: [Qemu-devel] [Qemu-block] [PATCH v2 1/2] block: use internal filter node in backup

2017-08-16 Thread Manos Pitsidianakis

On Wed, Aug 16, 2017 at 02:25:44PM +0100, Stefan Hajnoczi wrote:

On Tue, Aug 15, 2017 at 11:18:53AM +0300, Manos Pitsidianakis wrote:

block/backup.c currently uses before write notifiers on the targeted
node. We can create a filter node instead to intercept write requests
for the backup job on the BDS level, instead of the BlockBackend level.

This is part of deprecating before write notifiers, which are hard coded
into the block layer. Block filter drivers are inserted into the graph
only when a feature is needed. This makes the block layer more modular
and reuses the block driver abstraction that is already present.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block.c|  89 +--
 block/backup.c | 207 -
 block/mirror.c |   7 +-
 blockdev.c |   2 +-
 include/block/block.h  |   8 +-
 tests/qemu-iotests/141.out |   2 +-
 6 files changed, 276 insertions(+), 39 deletions(-)

diff --git a/block.c b/block.c
index 2de1c29eb3..81bd51b670 100644
--- a/block.c
+++ b/block.c
@@ -2088,6 +2088,38 @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
 }

 /*
+ * Sets the file link of a BDS. A new reference is created; callers
+ * which don't need their own reference any more must call bdrv_unref().
+ */
+void bdrv_set_file(BlockDriverState *bs, BlockDriverState *file_bs,
+   Error **errp)
+{
+if (file_bs) {
+bdrv_ref(file_bs);
+}
+
+if (bs->file) {
+bdrv_unref_child(bs, bs->file);
+}
+
+if (!file_bs) {
+bs->file = NULL;
+goto out;
+}
+
+bs->file = bdrv_attach_child(bs, file_bs, "file", _file,
+ errp);
+if (!bs->file) {
+bdrv_unref(file_bs);
+}
+
+bdrv_refresh_filename(bs);
+
+out:
+bdrv_refresh_limits(bs, NULL);
+}
+
+/*
  * Sets the backing file link of a BDS. A new reference is created; callers
  * which don't need their own reference any more must call bdrv_unref().
  */
@@ -2355,12 +2387,12 @@ static BlockDriverState 
*bdrv_append_temp_snapshot(BlockDriverState *bs,
 goto out;
 }

-/* bdrv_append() consumes a strong reference to bs_snapshot
+/* bdrv_append_backing() consumes a strong reference to bs_snapshot
  * (i.e. it will call bdrv_unref() on it) even on error, so in
  * order to be able to return one, we have to increase
  * bs_snapshot's refcount here */
 bdrv_ref(bs_snapshot);
-bdrv_append(bs_snapshot, bs, _err);
+bdrv_append_backing(bs_snapshot, bs, _err);
 if (local_err) {
 error_propagate(errp, local_err);
 bs_snapshot = NULL;
@@ -3142,7 +3174,7 @@ static bool should_update_child(BdrvChild *c, 
BlockDriverState *to)
 return false;
 }

-if (c->role == _backing) {
+if (c->role == _backing || c->role == _file) {
 /* If @from is a backing file of @to, ignore the child to avoid
  * creating a loop. We only want to change the pointer of other
  * parents. */


This may have unwanted side-effects.  I think you're using is so that
bdrv_set_file() + bdrv_replace_node() does not create a loop in the
graph.  That is okay if there is only one parent with child_file.  If
there are multiple parents with that role then it's not clear to me that
they should all be skipped.


I am afraid I don't understand what you're saying. What is the 
difference with the child_backing scenario here?  In both cases we 
should update all from->parents children unless they also happen to be a 
child of `to`. If there are multiple parents with child_file, they are 
not skipped except for the ones where `to` is the parent.



@@ -3213,6 +3245,45 @@ out:
 }

 /*
+ * Add new bs node at the top of a BDS chain while the chain is
+ * live, while keeping required fields on the top layer.
+ *
+ * This will modify the BlockDriverState fields, and swap contents
+ * between bs_new and bs_top. Both bs_new and bs_top are modified.
+ *
+ * bs_new must not be attached to a BlockBackend.
+ *
+ * bdrv_append_file() takes ownership of a bs_new reference and unrefs it
+ * because that's what the callers commonly need. bs_new will be referenced by
+ * the old parents of bs_top after bdrv_append_file() returns. If the caller
+ * needs to keep a reference of its own, it must call bdrv_ref().
+ */
+void bdrv_append_file(BlockDriverState *bs_new, BlockDriverState *bs_top,
+  Error **errp)
+{
+Error *local_err = NULL;
+
+bdrv_ref(bs_top);
+bdrv_set_file(bs_new, bs_top, _err);


bdrv_set_file() takes its own reference so there's no need to call
bdrv_ref(bs_top).

But it would be more consistent with existing functions for
bdrv_set_file() *not* to take a new reference.  If you make that change
then this bdrv_ref() is correct.


+if (local_err) {
+error_propagate(errp, local_err);

Re: [Qemu-devel] [PATCH RFC] block: add block-insert-node QMP command

2017-08-16 Thread Manos Pitsidianakis

On Wed, Aug 16, 2017 at 06:59:25AM -0500, Eric Blake wrote:

On 08/16/2017 04:41 AM, Manos Pitsidianakis wrote:


+##
+# @block-insert-node:
+#
+# Insert a filter node between a specific edge in the block driver
state graph.
+# @parent:  the name of the parent node or device
+# @node:the name of the node to insert under parent
+# @child:   the name of the child of both node and parent


Is this always going to be between two existing nodes, or can this
command also be used to insert at the end of the chain (for example, if
parent or child is omitted)?


If this is used for filter nodes, I suppose only between would make
sense (for now). Is there a use case for the latter?


Perhaps.

Given a qcow2 image backing chain:

base <- active

there are four BDS (2 format, 2 protocol).  Ideally, I could add
filtering to any one of those four nodes (a filter on the base protocol
level restricts how much guest data can be used from the backing image,
but with no limits on the qcow2 metadata; a filter on the base format
level restricts metadata reads as well; similarly for filters on the
active protocol and format layers).

But adding a filter on 'active' at the format level has no pre-existing
parent (I'm adding the filter as the new top-level).  Or am I missing
something?


The parent in this case is the storage device (disk / cdrom), whose name 
is specified as the parent. The first example in the 
qapi/block-core.json is such a case. In code I check blk_by_name(parent) 
and if that doesn't exist, I try with bdrv_find_node(parent).  Perhaps I 
should reword the documentation or did I misunderstand what you wrote?


signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH RFC] block: add block-insert-node QMP command

2017-08-16 Thread Manos Pitsidianakis

On Tue, Aug 15, 2017 at 05:12:42PM -0500, Eric Blake wrote:

On 08/15/2017 02:45 AM, Manos Pitsidianakis wrote:

block-insert-node and its pair command block-remove-node provide runtime
insertion and removal of filter nodes.

block-insert-node takes a (parent, child) and (node, child) pair of
edges and unrefs the (parent, child) BdrvChild relationship and creates
a new (parent, node) child with the same BdrvChildRole.

This is a different approach than x-blockdev-change which uses the driver
methods bdrv_add_child() and bdrv_del_child(),

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block.c|  192 
 blockdev.c |   44 ++
 include/block/block.h  |6 +
 qapi/block-core.json   |   60 +++
 tests/qemu-iotests/193 |  241 ++
 tests/qemu-iotests/193.out | 1116 
 tests/qemu-iotests/group   |1 +
 7 files changed, 1660 insertions(+)
 create mode 100755 tests/qemu-iotests/193
 create mode 100644 tests/qemu-iotests/193.out


You may want to look at using scripts/git.orderfile, to rearrange your
patch so that interface changes (.json, .h) occur before implementation
(.c).  For now, I'm just focusing on the interface:


Thanks for the tip, I will use it from now on!




+++ b/qapi/block-core.json
@@ -3947,3 +3947,63 @@
   'data' : { 'parent': 'str',
  '*child': 'str',
  '*node': 'str' } }
+
+##
+# @block-insert-node:
+#
+# Insert a filter node between a specific edge in the block driver state graph.
+# @parent:  the name of the parent node or device
+# @node:the name of the node to insert under parent
+# @child:   the name of the child of both node and parent


Is this always going to be between two existing nodes, or can this
command also be used to insert at the end of the chain (for example, if
parent or child is omitted)?


If this is used for filter nodes, I suppose only between would make 
sense (for now). Is there a use case for the latter?




+#}
+# <- { 'return': {} }
+#
+##


Missing 'Since: 2.11'.


+{ 'command': 'block-insert-node',
+  'data': { 'parent': 'str',
+ 'child': 'str',
+ 'node': 'str'} }


For now, it looks like you require all arguments, and therefore this is
always insertion in the middle.


+##
+# @block-remove-node:
+#
+# Remove a filter node between two other nodes in the block driver state graph.
+# @parent:  the name of the parent node or device
+# @node:the name of the node to remove from parent
+# @child:   the name of the child of node which will go under parent
+##
+{ 'command': 'block-remove-node',
+  'data': { 'parent': 'str',
+ 'child': 'str',
+ 'node': 'str'} }


Likewise missing 2.11.

Overall I'm not seeing problems with the interface from the UI
perspective, but I have not been paying close attention to your larger
efforts on throttling nodes, so I hope other reviewers will chime in.

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3266
Virtualization:  qemu.org | libvirt.org







signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH v2 1/6] block: skip implicit nodes in snapshots, blockjobs

2017-08-15 Thread Manos Pitsidianakis

On Tue, Aug 15, 2017 at 03:24:38PM +0200, Alberto Garcia wrote:

On Wed 09 Aug 2017 04:02:51 PM CEST, Manos Pitsidianakis wrote:

@@ -2988,6 +3004,9 @@ void qmp_block_stream(bool has_job_id, const char 
*job_id, const char *device,
 return;
 }

+/* Skip implicit filter nodes */
+bs = bdrv_get_first_explicit(bs);
+
 aio_context = bdrv_get_aio_context(bs);
 aio_context_acquire(aio_context);


This change works here because right now the only implicit node that we
could have in practice is the throttle node, but I wonder if this is
good enough for any kind of implicit node in general.


It does feel a bit sloppy but block jobs should work the same with
implicit nodes and without, so all we can do is ignore them.




+static inline BlockDriverState *child_bs(BlockDriverState *bs)
+{
+BdrvChild *child = QLIST_FIRST(>children);
+assert(child && !QLIST_NEXT(child, next));
+return child->bs;
+}


This aborts if the bs has a number of children != 1. That's not
something that I would expect from a function named like that.

Considering that you're only using it in bdrv_get_first_explicit(), why
don't you simply move the code there?


It felt useful to have a function that also returns file->bs (we have 
backing_bs() already) instead of doing backing_bs(bs) ? : file_bs(bs)


The other question is of course whether we can rely for the future on
the assumption that implicit nodes only have one children.


This is only to get either bs->backing or bs->file (we can't have both
anyway). I wanted to document it with something like "Used for filter 
drivers with only one child" which fits with what implicit nodes we have 
so far (mirror, commit, throttle and in the future backup)


signature.asc
Description: PGP signature


[Qemu-devel] [PATCH v2 1/2] block: use internal filter node in backup

2017-08-15 Thread Manos Pitsidianakis
block/backup.c currently uses before write notifiers on the targeted
node. We can create a filter node instead to intercept write requests
for the backup job on the BDS level, instead of the BlockBackend level.

This is part of deprecating before write notifiers, which are hard coded
into the block layer. Block filter drivers are inserted into the graph
only when a feature is needed. This makes the block layer more modular
and reuses the block driver abstraction that is already present.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block.c|  89 +--
 block/backup.c | 207 -
 block/mirror.c |   7 +-
 blockdev.c |   2 +-
 include/block/block.h  |   8 +-
 tests/qemu-iotests/141.out |   2 +-
 6 files changed, 276 insertions(+), 39 deletions(-)

diff --git a/block.c b/block.c
index 2de1c29eb3..81bd51b670 100644
--- a/block.c
+++ b/block.c
@@ -2088,6 +2088,38 @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
 }
 
 /*
+ * Sets the file link of a BDS. A new reference is created; callers
+ * which don't need their own reference any more must call bdrv_unref().
+ */
+void bdrv_set_file(BlockDriverState *bs, BlockDriverState *file_bs,
+   Error **errp)
+{
+if (file_bs) {
+bdrv_ref(file_bs);
+}
+
+if (bs->file) {
+bdrv_unref_child(bs, bs->file);
+}
+
+if (!file_bs) {
+bs->file = NULL;
+goto out;
+}
+
+bs->file = bdrv_attach_child(bs, file_bs, "file", _file,
+ errp);
+if (!bs->file) {
+bdrv_unref(file_bs);
+}
+
+bdrv_refresh_filename(bs);
+
+out:
+bdrv_refresh_limits(bs, NULL);
+}
+
+/*
  * Sets the backing file link of a BDS. A new reference is created; callers
  * which don't need their own reference any more must call bdrv_unref().
  */
@@ -2355,12 +2387,12 @@ static BlockDriverState 
*bdrv_append_temp_snapshot(BlockDriverState *bs,
 goto out;
 }
 
-/* bdrv_append() consumes a strong reference to bs_snapshot
+/* bdrv_append_backing() consumes a strong reference to bs_snapshot
  * (i.e. it will call bdrv_unref() on it) even on error, so in
  * order to be able to return one, we have to increase
  * bs_snapshot's refcount here */
 bdrv_ref(bs_snapshot);
-bdrv_append(bs_snapshot, bs, _err);
+bdrv_append_backing(bs_snapshot, bs, _err);
 if (local_err) {
 error_propagate(errp, local_err);
 bs_snapshot = NULL;
@@ -3142,7 +3174,7 @@ static bool should_update_child(BdrvChild *c, 
BlockDriverState *to)
 return false;
 }
 
-if (c->role == _backing) {
+if (c->role == _backing || c->role == _file) {
 /* If @from is a backing file of @to, ignore the child to avoid
  * creating a loop. We only want to change the pointer of other
  * parents. */
@@ -3213,6 +3245,45 @@ out:
 }
 
 /*
+ * Add new bs node at the top of a BDS chain while the chain is
+ * live, while keeping required fields on the top layer.
+ *
+ * This will modify the BlockDriverState fields, and swap contents
+ * between bs_new and bs_top. Both bs_new and bs_top are modified.
+ *
+ * bs_new must not be attached to a BlockBackend.
+ *
+ * bdrv_append_file() takes ownership of a bs_new reference and unrefs it
+ * because that's what the callers commonly need. bs_new will be referenced by
+ * the old parents of bs_top after bdrv_append_file() returns. If the caller
+ * needs to keep a reference of its own, it must call bdrv_ref().
+ */
+void bdrv_append_file(BlockDriverState *bs_new, BlockDriverState *bs_top,
+  Error **errp)
+{
+Error *local_err = NULL;
+
+bdrv_ref(bs_top);
+bdrv_set_file(bs_new, bs_top, _err);
+if (local_err) {
+error_propagate(errp, local_err);
+bdrv_set_file(bs_new, NULL, _abort);
+goto out;
+}
+bdrv_replace_node(bs_top, bs_new, _err);
+if (local_err) {
+error_propagate(errp, local_err);
+goto out;
+}
+
+/* bs_new is now referenced by its new parents, we don't need the
+ * additional reference any more. */
+out:
+bdrv_unref(bs_top);
+bdrv_unref(bs_new);
+}
+
+/*
  * Add new bs contents at the top of an image chain while the chain is
  * live, while keeping required fields on the top layer.
  *
@@ -3223,13 +3294,13 @@ out:
  *
  * This function does not create any image files.
  *
- * bdrv_append() takes ownership of a bs_new reference and unrefs it because
- * that's what the callers commonly need. bs_new will be referenced by the old
- * parents of bs_top after bdrv_append() returns. If the caller needs to keep a
- * reference of its own, it must call bdrv_ref().
+ * bdrv_append_backing() takes ownership of a bs_new reference and unrefs it
+ * because that's what the callers commonly need. bs_new will be reference

[Qemu-devel] [PATCH v2 2/2] block: add filter driver to block/write-threshold.c

2017-08-15 Thread Manos Pitsidianakis
With runtime insertion and removal of filters, write-threshold.c can
provide more flexible deliveries of BLOCK_WRITE_THRESHOLD events. After
the event trigger, the filter nodes are no longer useful and must be
removed.
The existing write-threshold cannot be easily converted to using the
filter driver, so it is not affected.

This is part of deprecating before write notifiers, which are hard coded
into the block layer. Block filter drivers are inserted into the graph
only when a feature is needed. This makes the block layer more modular
and reuses the block driver abstraction that is already present.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block/qapi.c|   2 +-
 block/write-threshold.c | 264 +++-
 include/block/write-threshold.h |  22 ++--
 qapi/block-core.json|  19 ++-
 tests/test-write-threshold.c|  40 +++---
 5 files changed, 281 insertions(+), 66 deletions(-)

diff --git a/block/qapi.c b/block/qapi.c
index 2be44a6758..fe6cf2eae5 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -122,7 +122,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
 info->group = g_strdup(throttle_group_get_name(tgm));
 }
 
-info->write_threshold = bdrv_write_threshold_get(bs);
+info->write_threshold = bdrv_write_threshold_get_legacy(bs);
 
 bs0 = bs;
 p_image_info = >image;
diff --git a/block/write-threshold.c b/block/write-threshold.c
index 0bd1a01c86..4a67188ea3 100644
--- a/block/write-threshold.c
+++ b/block/write-threshold.c
@@ -2,9 +2,11 @@
  * QEMU System Emulator block write threshold notification
  *
  * Copyright Red Hat, Inc. 2014
+ * Copyright 2017 Manos Pitsidianakis
  *
  * Authors:
  *  Francesco Romani <from...@redhat.com>
+ *  Manos Pitsidianakis <el13...@mail.ntua.gr>
  *
  * This work is licensed under the terms of the GNU LGPL, version 2 or later.
  * See the COPYING.LIB file in the top-level directory.
@@ -19,46 +21,35 @@
 #include "qmp-commands.h"
 
 
-uint64_t bdrv_write_threshold_get(const BlockDriverState *bs)
+uint64_t bdrv_write_threshold_get_legacy(const BlockDriverState *bs)
 {
 return bs->write_threshold_offset;
 }
 
-bool bdrv_write_threshold_is_set(const BlockDriverState *bs)
+bool bdrv_write_threshold_is_set_legacy(const BlockDriverState *bs)
 {
 return bs->write_threshold_offset > 0;
 }
 
-static void write_threshold_disable(BlockDriverState *bs)
+static void write_threshold_disable_legacy(BlockDriverState *bs)
 {
-if (bdrv_write_threshold_is_set(bs)) {
+if (bdrv_write_threshold_is_set_legacy(bs)) {
 notifier_with_return_remove(>write_threshold_notifier);
 bs->write_threshold_offset = 0;
 }
 }
 
-uint64_t bdrv_write_threshold_exceeded(const BlockDriverState *bs,
-   const BdrvTrackedRequest *req)
-{
-if (bdrv_write_threshold_is_set(bs)) {
-if (req->offset > bs->write_threshold_offset) {
-return (req->offset - bs->write_threshold_offset) + req->bytes;
-}
-if ((req->offset + req->bytes) > bs->write_threshold_offset) {
-return (req->offset + req->bytes) - bs->write_threshold_offset;
-}
-}
-return 0;
-}
-
 static int coroutine_fn before_write_notify(NotifierWithReturn *notifier,
 void *opaque)
 {
 BdrvTrackedRequest *req = opaque;
 BlockDriverState *bs = req->bs;
 uint64_t amount = 0;
+uint64_t threshold = bdrv_write_threshold_get_legacy(bs);
+uint64_t offset = req->offset;
+uint64_t bytes = req->bytes;
 
-amount = bdrv_write_threshold_exceeded(bs, req);
+amount = bdrv_write_threshold_exceeded(threshold, offset, bytes);
 if (amount > 0) {
 qapi_event_send_block_write_threshold(
 bs->node_name,
@@ -67,7 +58,7 @@ static int coroutine_fn 
before_write_notify(NotifierWithReturn *notifier,
 _abort);
 
 /* autodisable to avoid flooding the monitor */
-write_threshold_disable(bs);
+write_threshold_disable_legacy(bs);
 }
 
 return 0; /* should always let other notifiers run */
@@ -79,25 +70,26 @@ static void 
write_threshold_register_notifier(BlockDriverState *bs)
 bdrv_add_before_write_notifier(bs, >write_threshold_notifier);
 }
 
-static void write_threshold_update(BlockDriverState *bs,
-   int64_t threshold_bytes)
+static void write_threshold_update_legacy(BlockDriverState *bs,
+  int64_t threshold_bytes)
 {
 bs->write_threshold_offset = threshold_bytes;
 }
 
-void bdrv_write_threshold_set(BlockDriverState *bs, uint64_t threshold_bytes)
+void bdrv_write_threshold_set_legacy(BlockDriverState *bs,
+ uint64_t threshold_bytes)
 {
-if (bdr

[Qemu-devel] [PATCH v2 0/2] add internal backup job and write-threshold filter drivers

2017-08-15 Thread Manos Pitsidianakis
This is part of my GSOC project, which is refactoring hardcoded block layer
features into filter drivers. Block filter drivers are inserted into the graph
only when a feature is needed. This makes the block layer more modular and
reuses the block driver abstraction that is already present.

Before write notifiers currently have two users:

block/backup.c uses before write notifiers to intercept write requests. This
can be refactored to use the filter driver interface by injecting an implicit
filter node to intercept the write requests and call backup_do_cow().

block/write-threshold.c checks that write requests do not pass a user set
offset and issue an event when they do. A new write-threshold driver can
perform the same function and be added by the user when
block-{insert,remove}-node are introduced. It is not trivial to convert the
existing interface (block-set-write-threshold) to using the filter driver.

v2:
  add motivation in commit messages
  dropped hunk that removed before-write notifiers

Manos Pitsidianakis (2):
  block: use internal filter node in backup
  block: add filter driver to block/write-threshold.c

 block.c |  89 --
 block/backup.c  | 207 +++
 block/mirror.c  |   7 +-
 block/qapi.c|   2 +-
 block/write-threshold.c | 264 +++-
 blockdev.c  |   2 +-
 include/block/block.h   |   8 +-
 include/block/write-threshold.h |  22 ++--
 qapi/block-core.json|  19 ++-
 tests/qemu-iotests/141.out  |   2 +-
 tests/test-write-threshold.c|  40 +++---
 11 files changed, 557 insertions(+), 105 deletions(-)

-- 
2.11.0




Re: [Qemu-devel] [PATCH 1/2] block: use internal filter node in backup

2017-08-15 Thread Manos Pitsidianakis

On Tue, Aug 15, 2017 at 10:44:15AM +0300, Vladimir Sementsov-Ogievskiy wrote:

15.08.2017 09:19, Manos Pitsidianakis wrote:

block/backup.c currently uses before write notifiers on the targeted
node. We can create a filter node instead to intercept write requests
for the backup job on the BDS level, instead of the BlockBackend level.



Hi Manos!

Looks interesting but what is the real benefit of it? It doesn't look 
like it simplifies the code.. Also, is it affect performance?

I think it worth describing in commit message.


The goal is to refactor the block layer into being more modular instead 
of having hard coded features. I don't suspect this will have any kind 
of performance gains, this is a minor change. Before write notifiers are 
not needed if you can intercept the write requests on the way.


signature.asc
Description: PGP signature


[Qemu-devel] [PATCH RFC] block: add block-insert-node QMP command

2017-08-15 Thread Manos Pitsidianakis
block-insert-node and its pair command block-remove-node provide runtime
insertion and removal of filter nodes.

block-insert-node takes a (parent, child) and (node, child) pair of
edges and unrefs the (parent, child) BdrvChild relationship and creates
a new (parent, node) child with the same BdrvChildRole.

This is a different approach than x-blockdev-change which uses the driver
methods bdrv_add_child() and bdrv_del_child(),

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block.c|  192 
 blockdev.c |   44 ++
 include/block/block.h  |6 +
 qapi/block-core.json   |   60 +++
 tests/qemu-iotests/193 |  241 ++
 tests/qemu-iotests/193.out | 1116 
 tests/qemu-iotests/group   |1 +
 7 files changed, 1660 insertions(+)
 create mode 100755 tests/qemu-iotests/193
 create mode 100644 tests/qemu-iotests/193.out

diff --git a/block.c b/block.c
index 81bd51b670..f874aabbfb 100644
--- a/block.c
+++ b/block.c
@@ -930,6 +930,9 @@ static void bdrv_backing_attach(BdrvChild *c)
 parent->backing_blocker);
 bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_STREAM,
 parent->backing_blocker);
+/* Unblock filter node insertion */
+bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_EDGE_MODIFICATION,
+parent->backing_blocker);
 /*
  * We do backup in 3 ways:
  * 1. drive backup
@@ -5036,3 +5039,192 @@ BlockDriverState 
*bdrv_get_first_explicit(BlockDriverState *bs)
 }
 return bs;
 }
+
+
+static inline BdrvChild *bdrv_find_child(BlockDriverState *parent_bs,
+  const char *child_name)
+{
+BdrvChild *child;
+assert(child_name);
+
+QLIST_FOREACH(child, _bs->children, next) {
+if (child->bs && !g_strcmp0(child->bs->node_name, child_name)) {
+return child;
+}
+}
+
+return NULL;
+}
+
+static int check_node_edge(const char *parent, const char *child, Error **errp)
+{
+BlockDriverState *parent_bs, *child_bs;
+parent_bs = bdrv_find_node(parent);
+if (!parent_bs) {
+error_setg(errp, "'%s' not a node name", parent);
+return 1;
+}
+child_bs = bdrv_find_node(child);
+if (!child_bs) {
+error_setg(errp, "'%s' not a node name", child);
+return 1;
+}
+if (!bdrv_find_child(parent_bs, child)) {
+error_setg(errp, "'%s' not a child of '%s'", child, parent);
+return 1;
+}
+if (bdrv_op_is_blocked(parent_bs, BLOCK_OP_TYPE_EDGE_MODIFICATION, errp) ||
+bdrv_op_is_blocked(child_bs, BLOCK_OP_TYPE_EDGE_MODIFICATION, errp)) {
+return 1;
+}
+return 0;
+}
+
+void bdrv_insert_node(const char *parent, const char *child,
+  const char *node, Error **errp)
+{
+BlockBackend *blk;
+BlockDriverState *parent_bs, *node_bs, *child_bs;
+BdrvChild *c;
+const BdrvChildRole *role;
+
+if (check_node_edge(node, child, errp)) {
+return;
+}
+node_bs = bdrv_find_node(node);
+child_bs = bdrv_find_node(child);
+blk = blk_by_name(parent);
+if (blk) {
+/* insert 'node' as root bs of 'parent' device */
+if (!blk_bs(blk)) {
+error_setg(errp, "Device '%s' has no medium", parent);
+return;
+}
+if (blk_bs(blk) != child_bs) {
+error_setg(errp, "'%s' not a child of device '%s'", child, parent);
+return;
+}
+bdrv_drained_begin(child_bs);
+blk_remove_bs(blk);
+blk_insert_bs(blk, node_bs, errp);
+if (!blk_bs(blk)) {
+blk_insert_bs(blk, child_bs, _abort);
+}
+bdrv_drained_end(child_bs);
+return;
+}
+
+/* insert 'node' as child bs of 'parent' node */
+if (check_node_edge(parent, child, errp)) {
+return;
+}
+parent_bs = bdrv_find_node(parent);
+c = bdrv_find_child(parent_bs, child);
+role = c->role;
+assert(role == _file || role == _backing);
+
+bdrv_ref(node_bs);
+
+bdrv_drained_begin(parent_bs);
+bdrv_unref_child(parent_bs, c);
+if (role == _file) {
+parent_bs->file = bdrv_attach_child(parent_bs, node_bs, "file",
+_file, errp);
+if (!parent_bs->file) {
+parent_bs->file = bdrv_attach_child(parent_bs, child_bs, "file",
+_file, _abort);
+goto out;
+}
+} else if (role == _backing) {
+parent_bs->backing = bdrv_attach_child(parent_bs, node_bs, "backing",
+   _backing, errp);
+if (!parent_bs->backing) {
+parent_bs->backing = bdrv_attach_child(parent_bs, child_bs,
+  

[Qemu-devel] [PATCH 2/2] block: add filter driver to block/write-threshold.c

2017-08-15 Thread Manos Pitsidianakis
With runtime insertion and removal of filters, write-threshold.c can
provide more flexible deliveries of BLOCK_WRITE_THRESHOLD events. After
the event trigger, the filter nodes are no longer useful and must be
removed.
The existing write-threshold cannot be easily converted to using the
filter driver, so it is not affected.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block/qapi.c|   2 +-
 block/write-threshold.c | 264 +++-
 include/block/write-threshold.h |  22 ++--
 qapi/block-core.json|  19 ++-
 tests/test-write-threshold.c|  40 +++---
 5 files changed, 281 insertions(+), 66 deletions(-)

diff --git a/block/qapi.c b/block/qapi.c
index 2be44a6758..fe6cf2eae5 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -122,7 +122,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
 info->group = g_strdup(throttle_group_get_name(tgm));
 }
 
-info->write_threshold = bdrv_write_threshold_get(bs);
+info->write_threshold = bdrv_write_threshold_get_legacy(bs);
 
 bs0 = bs;
 p_image_info = >image;
diff --git a/block/write-threshold.c b/block/write-threshold.c
index 0bd1a01c86..4a67188ea3 100644
--- a/block/write-threshold.c
+++ b/block/write-threshold.c
@@ -2,9 +2,11 @@
  * QEMU System Emulator block write threshold notification
  *
  * Copyright Red Hat, Inc. 2014
+ * Copyright 2017 Manos Pitsidianakis
  *
  * Authors:
  *  Francesco Romani <from...@redhat.com>
+ *  Manos Pitsidianakis <el13...@mail.ntua.gr>
  *
  * This work is licensed under the terms of the GNU LGPL, version 2 or later.
  * See the COPYING.LIB file in the top-level directory.
@@ -19,46 +21,35 @@
 #include "qmp-commands.h"
 
 
-uint64_t bdrv_write_threshold_get(const BlockDriverState *bs)
+uint64_t bdrv_write_threshold_get_legacy(const BlockDriverState *bs)
 {
 return bs->write_threshold_offset;
 }
 
-bool bdrv_write_threshold_is_set(const BlockDriverState *bs)
+bool bdrv_write_threshold_is_set_legacy(const BlockDriverState *bs)
 {
 return bs->write_threshold_offset > 0;
 }
 
-static void write_threshold_disable(BlockDriverState *bs)
+static void write_threshold_disable_legacy(BlockDriverState *bs)
 {
-if (bdrv_write_threshold_is_set(bs)) {
+if (bdrv_write_threshold_is_set_legacy(bs)) {
 notifier_with_return_remove(>write_threshold_notifier);
 bs->write_threshold_offset = 0;
 }
 }
 
-uint64_t bdrv_write_threshold_exceeded(const BlockDriverState *bs,
-   const BdrvTrackedRequest *req)
-{
-if (bdrv_write_threshold_is_set(bs)) {
-if (req->offset > bs->write_threshold_offset) {
-return (req->offset - bs->write_threshold_offset) + req->bytes;
-}
-if ((req->offset + req->bytes) > bs->write_threshold_offset) {
-return (req->offset + req->bytes) - bs->write_threshold_offset;
-}
-}
-return 0;
-}
-
 static int coroutine_fn before_write_notify(NotifierWithReturn *notifier,
 void *opaque)
 {
 BdrvTrackedRequest *req = opaque;
 BlockDriverState *bs = req->bs;
 uint64_t amount = 0;
+uint64_t threshold = bdrv_write_threshold_get_legacy(bs);
+uint64_t offset = req->offset;
+uint64_t bytes = req->bytes;
 
-amount = bdrv_write_threshold_exceeded(bs, req);
+amount = bdrv_write_threshold_exceeded(threshold, offset, bytes);
 if (amount > 0) {
 qapi_event_send_block_write_threshold(
 bs->node_name,
@@ -67,7 +58,7 @@ static int coroutine_fn 
before_write_notify(NotifierWithReturn *notifier,
 _abort);
 
 /* autodisable to avoid flooding the monitor */
-write_threshold_disable(bs);
+write_threshold_disable_legacy(bs);
 }
 
 return 0; /* should always let other notifiers run */
@@ -79,25 +70,26 @@ static void 
write_threshold_register_notifier(BlockDriverState *bs)
 bdrv_add_before_write_notifier(bs, >write_threshold_notifier);
 }
 
-static void write_threshold_update(BlockDriverState *bs,
-   int64_t threshold_bytes)
+static void write_threshold_update_legacy(BlockDriverState *bs,
+  int64_t threshold_bytes)
 {
 bs->write_threshold_offset = threshold_bytes;
 }
 
-void bdrv_write_threshold_set(BlockDriverState *bs, uint64_t threshold_bytes)
+void bdrv_write_threshold_set_legacy(BlockDriverState *bs,
+ uint64_t threshold_bytes)
 {
-if (bdrv_write_threshold_is_set(bs)) {
+if (bdrv_write_threshold_is_set_legacy(bs)) {
 if (threshold_bytes > 0) {
-write_threshold_update(bs, threshold_bytes);
+write_threshold_update_legacy(bs, threshold_bytes);
 } else {
-write_threshold_d

[Qemu-devel] [PATCH 1/2] block: use internal filter node in backup

2017-08-15 Thread Manos Pitsidianakis
block/backup.c currently uses before write notifiers on the targeted
node. We can create a filter node instead to intercept write requests
for the backup job on the BDS level, instead of the BlockBackend level.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block.c|  89 +--
 block/backup.c | 207 -
 block/io.c |  10 +--
 block/mirror.c |   4 +-
 blockdev.c |   2 +-
 include/block/block.h  |   8 +-
 tests/qemu-iotests/141.out |   2 +-
 7 files changed, 277 insertions(+), 45 deletions(-)

diff --git a/block.c b/block.c
index 2de1c29eb3..81bd51b670 100644
--- a/block.c
+++ b/block.c
@@ -2088,6 +2088,38 @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
 }
 
 /*
+ * Sets the file link of a BDS. A new reference is created; callers
+ * which don't need their own reference any more must call bdrv_unref().
+ */
+void bdrv_set_file(BlockDriverState *bs, BlockDriverState *file_bs,
+   Error **errp)
+{
+if (file_bs) {
+bdrv_ref(file_bs);
+}
+
+if (bs->file) {
+bdrv_unref_child(bs, bs->file);
+}
+
+if (!file_bs) {
+bs->file = NULL;
+goto out;
+}
+
+bs->file = bdrv_attach_child(bs, file_bs, "file", _file,
+ errp);
+if (!bs->file) {
+bdrv_unref(file_bs);
+}
+
+bdrv_refresh_filename(bs);
+
+out:
+bdrv_refresh_limits(bs, NULL);
+}
+
+/*
  * Sets the backing file link of a BDS. A new reference is created; callers
  * which don't need their own reference any more must call bdrv_unref().
  */
@@ -2355,12 +2387,12 @@ static BlockDriverState 
*bdrv_append_temp_snapshot(BlockDriverState *bs,
 goto out;
 }
 
-/* bdrv_append() consumes a strong reference to bs_snapshot
+/* bdrv_append_backing() consumes a strong reference to bs_snapshot
  * (i.e. it will call bdrv_unref() on it) even on error, so in
  * order to be able to return one, we have to increase
  * bs_snapshot's refcount here */
 bdrv_ref(bs_snapshot);
-bdrv_append(bs_snapshot, bs, _err);
+bdrv_append_backing(bs_snapshot, bs, _err);
 if (local_err) {
 error_propagate(errp, local_err);
 bs_snapshot = NULL;
@@ -3142,7 +3174,7 @@ static bool should_update_child(BdrvChild *c, 
BlockDriverState *to)
 return false;
 }
 
-if (c->role == _backing) {
+if (c->role == _backing || c->role == _file) {
 /* If @from is a backing file of @to, ignore the child to avoid
  * creating a loop. We only want to change the pointer of other
  * parents. */
@@ -3213,6 +3245,45 @@ out:
 }
 
 /*
+ * Add new bs node at the top of a BDS chain while the chain is
+ * live, while keeping required fields on the top layer.
+ *
+ * This will modify the BlockDriverState fields, and swap contents
+ * between bs_new and bs_top. Both bs_new and bs_top are modified.
+ *
+ * bs_new must not be attached to a BlockBackend.
+ *
+ * bdrv_append_file() takes ownership of a bs_new reference and unrefs it
+ * because that's what the callers commonly need. bs_new will be referenced by
+ * the old parents of bs_top after bdrv_append_file() returns. If the caller
+ * needs to keep a reference of its own, it must call bdrv_ref().
+ */
+void bdrv_append_file(BlockDriverState *bs_new, BlockDriverState *bs_top,
+  Error **errp)
+{
+Error *local_err = NULL;
+
+bdrv_ref(bs_top);
+bdrv_set_file(bs_new, bs_top, _err);
+if (local_err) {
+error_propagate(errp, local_err);
+bdrv_set_file(bs_new, NULL, _abort);
+goto out;
+}
+bdrv_replace_node(bs_top, bs_new, _err);
+if (local_err) {
+error_propagate(errp, local_err);
+goto out;
+}
+
+/* bs_new is now referenced by its new parents, we don't need the
+ * additional reference any more. */
+out:
+bdrv_unref(bs_top);
+bdrv_unref(bs_new);
+}
+
+/*
  * Add new bs contents at the top of an image chain while the chain is
  * live, while keeping required fields on the top layer.
  *
@@ -3223,13 +3294,13 @@ out:
  *
  * This function does not create any image files.
  *
- * bdrv_append() takes ownership of a bs_new reference and unrefs it because
- * that's what the callers commonly need. bs_new will be referenced by the old
- * parents of bs_top after bdrv_append() returns. If the caller needs to keep a
- * reference of its own, it must call bdrv_ref().
+ * bdrv_append_backing() takes ownership of a bs_new reference and unrefs it
+ * because that's what the callers commonly need. bs_new will be referenced by
+ * the old parents of bs_top after bdrv_append_backing() returns. If the caller
+ * needs to keep a reference of its own, it must call bdrv_ref().
  */
-void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
-

[Qemu-devel] [PATCH 0/2] add internal backup job and write-threshold filter drivers

2017-08-15 Thread Manos Pitsidianakis
Before write notifiers currently have two users:

block/backup.c uses before write notifiers to intercept write requests. This
can be refactored to use the filter driver interface by injecting an implicit
filter node to intercept the write requests and call backup_do_cow().

block/write-threshold.c checks that write requests do not pass a user set
offset and issue an event when they do. A new write-threshold driver can
perform the same function and be added by the user when
block-{insert,remove}-node are introduced. It is not trivial to convert the
existing interface (block-set-write-threshold) to using the filter driver.

Based-on: <20170809140256.25584-1-el13...@mail.ntua.gr>

Manos Pitsidianakis (2):
  block: use internal filter node in backup
  block: add filter driver to block/write-threshold.c

 block.c |  89 --
 block/backup.c  | 207 +++
 block/io.c  |  10 +-
 block/mirror.c  |   4 +-
 block/qapi.c|   2 +-
 block/write-threshold.c | 264 +++-
 blockdev.c  |   2 +-
 include/block/block.h   |   8 +-
 include/block/write-threshold.h |  22 ++--
 qapi/block-core.json|  19 ++-
 tests/qemu-iotests/141.out  |   2 +-
 tests/test-write-threshold.c|  40 +++---
 12 files changed, 558 insertions(+), 111 deletions(-)

-- 
2.11.0




Re: [Qemu-devel] [PATCH v3 5/7] block: add throttle block filter driver

2017-08-14 Thread Manos Pitsidianakis

On Wed, Aug 09, 2017 at 05:39:42PM +0200, Kevin Wolf wrote:

Am 09.08.2017 um 16:45 hat Alberto Garcia geschrieben:

On Wed 09 Aug 2017 03:42:07 PM CEST, Manos Pitsidianakis wrote:
> On Wed, Aug 09, 2017 at 02:36:20PM +0200, Alberto Garcia wrote:
>>On Wed 09 Aug 2017 11:36:12 AM CEST, Manos Pitsidianakis wrote:
>>> On Tue, Aug 08, 2017 at 05:04:48PM +0200, Alberto Garcia wrote:
>>>>On Tue 08 Aug 2017 04:56:20 PM CEST, Manos Pitsidianakis wrote:
>>>>>>> So basically if we have anonymous groups, we accept limits in the
>>>>>>> driver options but only without a group-name.
>>>>>>
>>>>>>In the commit message you do however have limits and a group name, is
>>>>>>that a mistake?
>>>>>>
>>>>>>-drive driver=throttle,file.filename=foo.qcow2, \
>>>>>>   limits.iops-total=...,throttle-group=bar
>>>>>
>>>>> Sorry this wasn't clear, I'm actually proposing to remove limits from
>>>>> the throttle driver options and only create/config throttle groups via
>>>>> -object/object-add.
>>>>
>>>>Sorry I think it was me who misunderstood :-) Anyway in the new
>>>>command-line API I would be more inclined to have limits defined using
>>>>"-object throttle-group" and -drive would only reference the group id.
>>>>
>>>>I understand that this implies that it wouldn't be possible to create
>>>>anonymous groups (at least not from the command line), is that a
>>>>problem?
>>>
>>> We can accept anonymous groups if a user specifies limits but not a
>>> group name in the throttle driver. (The only case where limits would
>>> be acccepted)
>>
>>Yeah but that's only if we have the limits.iops-total=... options in the
>>throttle driver. If we "remove limits from the throttle driver options
>>and only create/config throttle groups via -object/object-add" we
>>cannot
>>do that.
>
> We can check that groups is not defined at the same time as limits,

I'm not sure if I'm following the conversation anymore :-) let's try to
recap:

  a) Groups are defined like this (with the current patches):

 -object throttle-group,id=foo,x-iops-total=100,x-..

  b) Throttle nodes are defined like this:

 -drive driver=throttle,file.filename=foo.qcow2, \
limits.iops-total=...,throttle-group=bar

  c) Therefore limits can be defined either in (a) or (b)

  d) If we omit throttle-group=... in (b), we would create an anonymous
 group.

  e) The -drive syntax from (b) has the "problem" that it's possible to
 define several nodes with the same throttling group but different
 limits. The last one would win (as the legacy syntax does), but
 that's not something completely straightforward for the end user.

  f) The syntax from (b) also has the problem that there's one more
 place that needs code to parse throttling limits.

  g) We can solve (e) and (f) if we remove the limits.* options
 altogether from the throttling filter. In that case you would need
 to define a throttle-group object and use the throttle-group option
 of the filter node in all cases.

  h) If we remove the limits.* options we cannot have anonymous groups
 anymore (at least not using this API). My question is: is it a
 problem? What would we lose? What benefits do anonymous groups
 bring us?


As I understand it, basically only the convenience of begin able to
specify a limit directly in -drive rather than having to create an
-object and reference its ID.


  i) We can of course maintain the limits.* options, but disallow
 throttle-group when they are present. That way we would allow
 anonymous groups and we would solve the ambiguity problem described
 in (e). My question is: is it worth it?


Maybe not. Depends on how important we consider the convenience feature.


>>> Not creating eponymous throttle groups via the throttle driver means
>>> we don't need throttle_groups anymore, since even anonymous ones
>>> don't need to be accounted for in a list.
>>
>>I don't follow you here, how else do you get a group by its name?
>
> If all eponymous groups are managed by the QOM tree, we should be able
> to iterate over the object root container for all ThrottleGroups just
> like qmp_query_iothreads() in iothread.c

Mmm... can't we actually use the root container now already? (even with
anonymous groups I mean). Why do we need throttle_groups?


Anonymous groups don't have a parent, so they aren't accessible through
the root container.


Anonymous groups wouldn't have to be in any kind of list, since they
shouldn't be access

Re: [Qemu-devel] [PATCH v4 5/7] block: add throttle block filter driver

2017-08-11 Thread Manos Pitsidianakis

On Wed, Aug 09, 2017 at 01:07:32PM +0300, Manos Pitsidianakis wrote:

+static int coroutine_fn throttle_co_preadv(BlockDriverState *bs,
+   uint64_t offset, uint64_t bytes,
+   QEMUIOVector *qiov, int flags)
+{
+
+ThrottleGroupMember *tgm = bs->opaque;
+throttle_group_co_io_limits_intercept(tgm, bytes, false);
+
+return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
+}
+
+static int coroutine_fn throttle_co_pwritev(BlockDriverState *bs,
+uint64_t offset, uint64_t bytes,
+QEMUIOVector *qiov, int flags)
+{
+ThrottleGroupMember *tgm = bs->opaque;
+throttle_group_co_io_limits_intercept(tgm, bytes, true);
+
+return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);

^
Tried some write throttling testing, noticed this. If anyone wants to
test this iteration, change this to bdrv_co_pwritev(), I will correct
this in the next version. (let's pretend this never happened!)


signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH v4 5/7] block: add throttle block filter driver

2017-08-10 Thread Manos Pitsidianakis

On Thu, Aug 10, 2017 at 03:54:02PM +0200, Alberto Garcia wrote:

On Wed 09 Aug 2017 12:07:32 PM CEST, Manos Pitsidianakis wrote:

+/* Extract ThrottleConfig options. Assumes cfg is initialized and will be
+ * checked for validity.
+ *
+ * Returns -1 and sets errp if a burst_length value is over UINT_MAX.
+ */
+static int throttle_extract_options(QemuOpts *opts, ThrottleConfig *cfg,
+Error **errp)
+{
+#define IF_OPT_SET(rvalue, opt_name) \
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX opt_name)) { \
+rvalue = qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX opt_name, 0); }
+
+IF_OPT_SET(cfg->buckets[THROTTLE_BPS_TOTAL].avg, QEMU_OPT_BPS_TOTAL);
+IF_OPT_SET(cfg->buckets[THROTTLE_BPS_READ].avg, QEMU_OPT_BPS_READ);
+IF_OPT_SET(cfg->buckets[THROTTLE_BPS_WRITE].avg, QEMU_OPT_BPS_WRITE);
+IF_OPT_SET(cfg->buckets[THROTTLE_OPS_TOTAL].avg, QEMU_OPT_IOPS_TOTAL);
+IF_OPT_SET(cfg->buckets[THROTTLE_OPS_READ].avg, QEMU_OPT_IOPS_READ);
+IF_OPT_SET(cfg->buckets[THROTTLE_OPS_WRITE].avg, QEMU_OPT_IOPS_WRITE);
+IF_OPT_SET(cfg->buckets[THROTTLE_BPS_TOTAL].max, QEMU_OPT_BPS_TOTAL_MAX);

 [...]

This is all the code that I was saying that we'd save if we don't allow
setting limits here.


+static int throttle_configure_tgm(BlockDriverState *bs,
+  ThrottleGroupMember *tgm,
+  QDict *options, Error **errp)
+{
+int ret;
+ThrottleConfig cfg;
+const char *group_name = NULL;


No need to set it to NULL here.


I know, I do it out of habit!




+Error *local_err = NULL;
+QemuOpts *opts = qemu_opts_create(_opts, NULL, 0, 
_abort);

+
+qemu_opts_absorb_qdict(opts, options, _err);
+if (local_err) {
+error_propagate(errp, local_err);
+goto err;
+}
+
+/* If group_name is NULL, an anonymous group will be created */
+group_name = qemu_opt_get(opts, QEMU_OPT_THROTTLE_GROUP_NAME);
+
+/* Register membership to group with name group_name */
+throttle_group_register_tgm(tgm, group_name, bdrv_get_aio_context(bs));
+
+/* Copy previous configuration */
+throttle_group_get_config(tgm, );
+
+/* Change limits if user has specified them */
+if (throttle_extract_options(opts, , errp) ||
+!throttle_is_valid(, errp)) {
+throttle_group_unregister_tgm(tgm);
+goto err;
+}
+/* Update group configuration */
+throttle_group_config(tgm, );


We'd also spare this, and this function would remain much simpler.


+
+ret = 0;
+goto fin;
+
+err:
+ret = -EINVAL;
+fin:
+qemu_opts_del(opts);
+return ret;
+}


If you set ret = -EINVAL before calling goto err you can simplify this
part as well, but feel free to ignore this suggestion.


+static int throttle_reopen_prepare(BDRVReopenState *reopen_state,
+   BlockReopenQueue *queue, Error **errp)
+{
+ThrottleGroupMember *tgm = NULL;
+
+assert(reopen_state != NULL);
+assert(reopen_state->bs != NULL);
+
+reopen_state->opaque = g_new0(ThrottleGroupMember, 1);
+tgm = reopen_state->opaque;
+
+return throttle_configure_tgm(reopen_state->bs, tgm, reopen_state->options,
+errp);
+}


I would rename 'reopen_state' as 'state' for consistency with the other
two functions.


The function signatures in block_int.h have reopen_state, so maybe for 
consistency I should change the other two to reopen_state as well, 
instead.





+static void throttle_reopen_commit(BDRVReopenState *state)
+{
+ThrottleGroupMember *tgm = state->bs->opaque;
+
+throttle_group_unregister_tgm(tgm);
+g_free(state->bs->opaque);
+state->bs->opaque = state->opaque;
+state->opaque = NULL;
+}


I also find the mixing of state->bs->opaque and tgm a bit confusing.
Here's a suggestion, but feel free to ignore it:


You're right, though it's only a few lines it might require a second 
read. I will rewrite those more clearly, too.


signature.asc
Description: PGP signature


[Qemu-devel] [PATCH v2 4/6] block: remove legacy I/O throttling

2017-08-09 Thread Manos Pitsidianakis
This commit removes all I/O throttling from block/block-backend.c. In
order to support the existing interface, it is changed to use the
block/throttle.c filter driver.

The throttle filter node that is created by the legacy interface is
stored in a 'throttle_node' field in the BlockBackendPublic of the
device. The legacy throttle node is managed by the legacy interface
completely. More advanced configurations with the filter drive are
possible using the QMP API, but these will be ignored by the legacy
interface.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block/block-backend.c   | 133 
 block/qapi.c|  10 +--
 block/throttle.c|   8 +++
 blockdev.c  |  49 +++
 include/block/throttle-groups.h |   1 +
 include/sysemu/block-backend.h  |   6 +-
 tests/test-throttle.c   |  19 +++---
 7 files changed, 146 insertions(+), 80 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index df0200fc49..61983b7393 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -15,6 +15,7 @@
 #include "block/block_int.h"
 #include "block/blockjob.h"
 #include "block/throttle-groups.h"
+#include "qemu/throttle-options.h"
 #include "sysemu/blockdev.h"
 #include "sysemu/sysemu.h"
 #include "qapi-event.h"
@@ -282,7 +283,7 @@ static void blk_delete(BlockBackend *blk)
 assert(!blk->refcnt);
 assert(!blk->name);
 assert(!blk->dev);
-if (blk->public.throttle_group_member.throttle_state) {
+if (blk->public.throttle_node) {
 blk_io_limits_disable(blk);
 }
 if (blk->root) {
@@ -593,13 +594,7 @@ BlockBackend *blk_by_public(BlockBackendPublic *public)
  */
 void blk_remove_bs(BlockBackend *blk)
 {
-ThrottleTimers *tt;
-
 notifier_list_notify(>remove_bs_notifiers, blk);
-if (blk->public.throttle_group_member.throttle_state) {
-tt = >public.throttle_group_member.throttle_timers;
-throttle_timers_detach_aio_context(tt);
-}
 
 blk_update_root_state(blk);
 
@@ -620,12 +615,6 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, 
Error **errp)
 bdrv_ref(bs);
 
 notifier_list_notify(>insert_bs_notifiers, blk);
-if (blk->public.throttle_group_member.throttle_state) {
-throttle_timers_attach_aio_context(
->public.throttle_group_member.throttle_timers,
-bdrv_get_aio_context(bs));
-}
-
 return 0;
 }
 
@@ -983,13 +972,6 @@ int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t 
offset,
 }
 
 bdrv_inc_in_flight(bs);
-
-/* throttling disk I/O */
-if (blk->public.throttle_group_member.throttle_state) {
-
throttle_group_co_io_limits_intercept(>public.throttle_group_member,
-bytes, false);
-}
-
 ret = bdrv_co_preadv(blk->root, offset, bytes, qiov, flags);
 bdrv_dec_in_flight(bs);
 return ret;
@@ -1010,11 +992,6 @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, 
int64_t offset,
 }
 
 bdrv_inc_in_flight(bs);
-/* throttling disk I/O */
-if (blk->public.throttle_group_member.throttle_state) {
-
throttle_group_co_io_limits_intercept(>public.throttle_group_member,
-bytes, true);
-}
 
 if (!blk->enable_write_cache) {
 flags |= BDRV_REQ_FUA;
@@ -1682,16 +1659,9 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB 
*acb)
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
 {
 BlockDriverState *bs = blk_bs(blk);
-ThrottleGroupMember *tgm = >public.throttle_group_member;
 
 if (bs) {
-if (tgm->throttle_state) {
-throttle_group_detach_aio_context(tgm);
-}
 bdrv_set_aio_context(bs, new_context);
-if (tgm->throttle_state) {
-throttle_group_attach_aio_context(tgm, new_context);
-}
 }
 }
 
@@ -1909,45 +1879,98 @@ int blk_commit_all(void)
 /* throttling disk I/O limits */
 void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg)
 {
-throttle_group_config(>public.throttle_group_member, cfg);
+assert(blk->public.throttle_node);
+throttle_group_config(throttle_get_tgm(blk->public.throttle_node), cfg);
 }
 
 void blk_io_limits_disable(BlockBackend *blk)
 {
-assert(blk->public.throttle_group_member.throttle_state);
-bdrv_drained_begin(blk_bs(blk));
-throttle_group_unregister_tgm(>public.throttle_group_member);
-bdrv_drained_end(blk_bs(blk));
+BlockDriverState *bs, *throttle_node;
+
+throttle_node = blk_get_public(blk)->throttle_node;
+
+assert(throttle_node);
+
+bs = throttle_node->file->bs;
+bdrv_drained_begin(bs);
+
+/* Ref throttle_node's child bs to ensure it won't go away */
+bdrv_ref(bs);
+
+bdrv_child_try_set_perm(throttle_node->

[Qemu-devel] [PATCH v2 0/6] block: remove legacy I/O throttling

2017-08-09 Thread Manos Pitsidianakis
This series depends on my other series 'add throttle block driver filter'
currently on v4.

Replacing the current I/O interface means the user will use the same options as
before and QEMU will create a hidden throttle filter node beneath the device's
BlockBackend. 

v2:
  new commit: require job-id when device is a node name
  new commit: remove BlockBackendPublic
  new commit: add dedicated iotest
  cleanup reference counting in block/block-backend.c functions
  add new function to get filter child bs
  take ownership of options in bdrv_new_open_driver()

Manos Pitsidianakis (6):
  block: skip implicit nodes in snapshots, blockjobs
  block: add options parameter to bdrv_new_open_driver()
  block: require job-id when device is a node name
  block: remove legacy I/O throttling
  block: add iotest 191 for legacy throttling interface
  block: remove BlockBackendPublic

 block.c |  26 ++-
 block/block-backend.c   | 152 +++-
 block/commit.c  |   4 +-
 block/mirror.c  |   2 +-
 block/qapi.c|  24 +++
 block/throttle.c|   8 +++
 block/vvfat.c   |   2 +-
 blockdev.c  | 148 +-
 blockjob.c  |  16 ++---
 include/block/block.h   |   2 +-
 include/block/block_int.h   |   9 +++
 include/block/blockjob_int.h|   3 +-
 include/block/throttle-groups.h |   1 +
 include/sysemu/block-backend.h  |  16 +
 tests/qemu-iotests/191  | 138 
 tests/qemu-iotests/191.out  |   5 ++
 tests/qemu-iotests/group|   1 +
 tests/test-blockjob.c   |  10 +--
 tests/test-throttle.c   |  19 ++---
 19 files changed, 440 insertions(+), 146 deletions(-)
 create mode 100644 tests/qemu-iotests/191
 create mode 100644 tests/qemu-iotests/191.out

-- 
2.11.0




[Qemu-devel] [PATCH v2 3/6] block: require job-id when device is a node name

2017-08-09 Thread Manos Pitsidianakis
With implicit filter nodes on the top of the graph it is not possible to
generate job-ids with the name of the device in block_job_create()
anymore, since the job's bs will not be a child_root.

Instead we can require that job-id is not NULL in block_job_create(),
and check that a job-id has been set in the callers of
block_job_create() in blockdev.c. It is more consistent to require an
explicit job-id when the device parameter in the job creation command,
eg

 { "execute": "drive-backup",
   "arguments": { "device": "drive0",
  "sync": "full",
  "target": "backup.img" } }

is not a BlockBackend name, instead of automatically getting it from the
root BS if device is a node name. That information is lost after calling
block_job_create(), so we can do it in its caller instead.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 blockdev.c   | 65 +++-
 blockjob.c   | 16 ---
 include/block/blockjob_int.h |  3 +-
 tests/test-blockjob.c| 10 ++-
 4 files changed, 67 insertions(+), 27 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index fc7b65c3f0..6ffa5b0b04 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3004,6 +3004,16 @@ void qmp_block_stream(bool has_job_id, const char 
*job_id, const char *device,
 return;
 }
 
+/* Always require a job-id when device is a node name */
+if (!has_job_id) {
+if (blk_by_name(device)) {
+job_id = device;
+} else {
+error_setg(errp, "An explicit job ID is required for this node");
+return;
+}
+}
+
 /* Skip implicit filter nodes */
 bs = bdrv_get_first_explicit(bs);
 
@@ -3058,7 +3068,7 @@ void qmp_block_stream(bool has_job_id, const char 
*job_id, const char *device,
 /* backing_file string overrides base bs filename */
 base_name = has_backing_file ? backing_file : base_name;
 
-stream_start(has_job_id ? job_id : NULL, bs, base_bs, base_name,
+stream_start(job_id, bs, base_bs, base_name,
  has_speed ? speed : 0, on_error, _err);
 if (local_err) {
 error_propagate(errp, local_err);
@@ -3117,6 +3127,16 @@ void qmp_block_commit(bool has_job_id, const char 
*job_id, const char *device,
 /* Skip implicit filter nodes */
 bs = bdrv_get_first_explicit(bs);
 
+/* Always require a job-id when device is a node name */
+if (!has_job_id) {
+if (blk_by_name(device)) {
+job_id = device;
+} else {
+error_setg(errp, "An explicit job ID is required for this node");
+return;
+}
+}
+
 aio_context = bdrv_get_aio_context(bs);
 aio_context_acquire(aio_context);
 
@@ -3171,7 +3191,7 @@ void qmp_block_commit(bool has_job_id, const char 
*job_id, const char *device,
  " but 'top' is the active layer");
 goto out;
 }
-commit_active_start(has_job_id ? job_id : NULL, bs, base_bs,
+commit_active_start(job_id, bs, base_bs,
 BLOCK_JOB_DEFAULT, speed, on_error,
 filter_node_name, NULL, NULL, false, _err);
 } else {
@@ -3179,7 +3199,7 @@ void qmp_block_commit(bool has_job_id, const char 
*job_id, const char *device,
 if (bdrv_op_is_blocked(overlay_bs, BLOCK_OP_TYPE_COMMIT_TARGET, errp)) 
{
 goto out;
 }
-commit_start(has_job_id ? job_id : NULL, bs, base_bs, top_bs, speed,
+commit_start(job_id, bs, base_bs, top_bs, speed,
  on_error, has_backing_file ? backing_file : NULL,
  filter_node_name, _err);
 }
@@ -3220,7 +3240,13 @@ static BlockJob *do_drive_backup(DriveBackup *backup, 
BlockJobTxn *txn,
 backup->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
 }
 if (!backup->has_job_id) {
-backup->job_id = NULL;
+/* Always require a job-id when device is a node name */
+if (blk_by_name(backup->device)) {
+backup->job_id = backup->device;
+} else {
+error_setg(errp, "An explicit job ID is required for this node");
+return NULL;
+}
 }
 if (!backup->has_compress) {
 backup->compress = false;
@@ -3366,7 +3392,13 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, 
BlockJobTxn *txn,
 backup->on_target_error = BLOCKDEV_ON_ERROR_REPORT;
 }
 if (!backup->has_job_id) {
-backup->job_id = NULL;
+/* Always require a job-id when device is a node name */
+if (blk_by_name(backup->device)) {
+backup->job_id = backup->device;
+} else {
+error_setg(errp, "An explicit job ID is required for this node");

[Qemu-devel] [PATCH v2 5/6] block: add iotest 191 for legacy throttling interface

2017-08-09 Thread Manos Pitsidianakis
Check that the implicit throttle filter driver node, used for
compatibility with the legacy throttling interface on the BlockBackend
level, works.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 tests/qemu-iotests/191 | 138 +
 tests/qemu-iotests/191.out |   5 ++
 tests/qemu-iotests/group   |   1 +
 3 files changed, 144 insertions(+)
 create mode 100644 tests/qemu-iotests/191
 create mode 100644 tests/qemu-iotests/191.out

diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
new file mode 100644
index 00..82fd0b2fe5
--- /dev/null
+++ b/tests/qemu-iotests/191
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+#
+# Tests that the legacy throttling interface using an implicit throttle filter
+# driver node works
+#
+# Copyright (C) 2017 Manos Pitsidianakis
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import iotests
+
+class TestLegacyThrottling(iotests.QMPTestCase):
+test_img = os.path.join(iotests.test_dir, "test.img")
+target_img = os.path.join(iotests.test_dir, "target.img")
+base_img = os.path.join(iotests.test_dir, "base.img")
+
+def setUp(self):
+iotests.qemu_img("create", "-f", iotests.imgfmt, self.base_img, "1G")
+iotests.qemu_img("create", "-f", iotests.imgfmt, self.test_img, "-b", 
self.base_img)
+iotests.qemu_io("-f", iotests.imgfmt, "-c", "write -P0x5d 1M 128M", 
self.test_img)
+self.vm = iotests.VM().add_drive(self.test_img)
+self.vm.launch()
+
+def tearDown(self):
+self.do_check_throttle_node(expect=True)
+params = {"device": "drive0",
+  "bps": 0,
+  "bps_rd": 0,
+  "bps_wr": 0,
+  "iops": 0,
+  "iops_rd": 0,
+  "iops_wr": 0,
+ }
+"""
+This must remove the implicit throttle_node
+"""
+result = self.vm.qmp("block_set_io_throttle", conv_keys=False,
+ **params)
+self.do_check_throttle_node(expect=False)
+self.vm.shutdown()
+
+def do_test_job(self, cmd, **args):
+params = {"device": "drive0",
+  "bps": 1024,
+  "bps_rd": 0,
+  "bps_wr": 0,
+  "iops": 0,
+  "iops_rd": 0,
+  "iops_wr": 0,
+ }
+result = self.vm.qmp("block_set_io_throttle", conv_keys=False,
+ **params)
+self.assert_qmp(result, "return", {})
+result = self.vm.qmp(cmd, **args)
+self.assert_qmp(result, "return", {})
+result = self.vm.qmp("query-block-jobs")
+self.assert_qmp(result, "return[0]/device", "drive0")
+
+def do_check_throttle_node(self, expect):
+result = self.vm.qmp("query-named-block-nodes")
+for r in result["return"]:
+if r["drv"] == "throttle":
+self.assertTrue(expect)
+return
+if expect:
+""" throttle_node missing! """
+self.assertTrue(False)
+
+def do_check_params(self, file):
+result = self.vm.qmp("query-block")
+self.assert_qmp(result, "return[0]/inserted/bps", 1024)
+self.assert_qmp(result, "return[0]/inserted/drv", iotests.imgfmt)
+self.assert_qmp(result, "return[0]/inserted/file", file)
+
+"""
+Check that query-block reports the correct throttling parameters while
+ignoring the implicit throttle node.
+"""
+def test_query_block(self):
+params = {"device": "drive0",
+  "bps": 1024,
+  "bps_rd": 0,
+  "bps_wr": 0,
+  "iops": 0,
+  "iops_rd": 0

[Qemu-devel] [PATCH v2 1/6] block: skip implicit nodes in snapshots, blockjobs

2017-08-09 Thread Manos Pitsidianakis
Implicit filter nodes added at the top of nodes can interfere with block
jobs. This is not a problem when they are added by other jobs since
adding another job will issue a QERR_DEVICE_IN_USE, but it can happen in
the next commit which introduces an implicitly created throttle filter
node below BlockBackend, which we want to be skipped during automatic
operations on the graph since the user does not necessarily know about
their existence.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block.c   | 10 ++
 block/qapi.c  | 14 +-
 blockdev.c| 34 ++
 include/block/block_int.h |  9 +
 4 files changed, 58 insertions(+), 9 deletions(-)

diff --git a/block.c b/block.c
index 3615a6809e..e35d546c08 100644
--- a/block.c
+++ b/block.c
@@ -4945,3 +4945,13 @@ bool bdrv_can_store_new_dirty_bitmap(BlockDriverState 
*bs, const char *name,
 
 return drv->bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp);
 }
+
+/* Get first explicit node down a bs chain. */
+BlockDriverState *bdrv_get_first_explicit(BlockDriverState *bs)
+{
+while (bs && bs->drv && bs->implicit) {
+bs = child_bs(bs);
+assert(bs);
+}
+return bs;
+}
diff --git a/block/qapi.c b/block/qapi.c
index 7fa2437923..847b044d13 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -147,9 +147,8 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
 
 /* Skip automatically inserted nodes that the user isn't aware of for
  * query-block (blk != NULL), but not for query-named-block-nodes */
-while (blk && bs0->drv && bs0->implicit) {
-bs0 = backing_bs(bs0);
-assert(bs0);
+if (blk) {
+bs0 = bdrv_get_first_explicit(bs0);
 }
 }
 
@@ -336,9 +335,7 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo 
**p_info,
 char *qdev;
 
 /* Skip automatically inserted nodes that the user isn't aware of */
-while (bs && bs->drv && bs->implicit) {
-bs = backing_bs(bs);
-}
+bs = bdrv_get_first_explicit(bs);
 
 info->device = g_strdup(blk_name(blk));
 info->type = g_strdup("unknown");
@@ -465,9 +462,8 @@ static BlockStats *bdrv_query_bds_stats(BlockDriverState 
*bs,
 /* Skip automatically inserted nodes that the user isn't aware of in
  * a BlockBackend-level command. Stay at the exact node for a node-level
  * command. */
-while (blk_level && bs->drv && bs->implicit) {
-bs = backing_bs(bs);
-assert(bs);
+if (blk_level) {
+bs = bdrv_get_first_explicit(bs);
 }
 
 if (bdrv_get_node_name(bs)[0]) {
diff --git a/blockdev.c b/blockdev.c
index 23475abb72..fc7b65c3f0 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1300,6 +1300,10 @@ SnapshotInfo 
*qmp_blockdev_snapshot_delete_internal_sync(const char *device,
 if (!bs) {
 return NULL;
 }
+
+/* Skip implicit filter nodes */
+bs = bdrv_get_first_explicit(bs);
+
 aio_context = bdrv_get_aio_context(bs);
 aio_context_acquire(aio_context);
 
@@ -1508,6 +1512,9 @@ static void internal_snapshot_prepare(BlkActionState 
*common,
 return;
 }
 
+/* Skip implicit filter nodes */
+bs = bdrv_get_first_explicit(bs);
+
 /* AioContext is released in .clean() */
 state->aio_context = bdrv_get_aio_context(bs);
 aio_context_acquire(state->aio_context);
@@ -1664,6 +1671,9 @@ static void external_snapshot_prepare(BlkActionState 
*common,
 return;
 }
 
+/* Skip implicit filter nodes */
+state->old_bs = bdrv_get_first_explicit(state->old_bs);
+
 /* Acquire AioContext now so any threads operating on old_bs stop */
 state->aio_context = bdrv_get_aio_context(state->old_bs);
 aio_context_acquire(state->aio_context);
@@ -1844,6 +1854,9 @@ static void drive_backup_prepare(BlkActionState *common, 
Error **errp)
 return;
 }
 
+/* Skip implicit filter nodes */
+bs = bdrv_get_first_explicit(bs);
+
 /* AioContext is released in .clean() */
 state->aio_context = bdrv_get_aio_context(bs);
 aio_context_acquire(state->aio_context);
@@ -1908,6 +1921,9 @@ static void blockdev_backup_prepare(BlkActionState 
*common, Error **errp)
 return;
 }
 
+/* Skip implicit filter nodes */
+bs = bdrv_get_first_explicit(bs);
+
 target = bdrv_lookup_bs(backup->target, backup->target, errp);
 if (!target) {
 return;
@@ -2988,6 +3004,9 @@ void qmp_block_stream(bool has_job_id, const char 
*job_id, const char *device,
 return;
 }
 
+/* Skip implicit filter nodes */
+bs = bdrv_get_first_explicit(bs);
+
 aio_context = bdrv_get_aio_context(bs);
 aio_context_acquire(aio_context);
 
@@ -3095,6 +3114,9 @@ void qmp_block_commit(bool has_job

[Qemu-devel] [PATCH v2 2/6] block: add options parameter to bdrv_new_open_driver()

2017-08-09 Thread Manos Pitsidianakis
Allow passing a QDict *options parameter to bdrv_new_open_driver() so
that it can be used if a driver needs it upon creation. The previous
behaviour (empty bs->options and bs->explicit_options) remains when
options is NULL.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block.c   | 16 +---
 block/commit.c|  4 ++--
 block/mirror.c|  2 +-
 block/vvfat.c |  2 +-
 include/block/block.h |  2 +-
 5 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/block.c b/block.c
index e35d546c08..2de1c29eb3 100644
--- a/block.c
+++ b/block.c
@@ -1153,16 +1153,26 @@ open_failed:
 return ret;
 }
 
+/*
+ * If options is not NULL, its ownership is transferred to the block layer. The
+ * caller must use QINCREF() if they wish to keep ownership.
+ */
 BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
-   int flags, Error **errp)
+   int flags, QDict *options, Error **errp)
 {
 BlockDriverState *bs;
 int ret;
 
 bs = bdrv_new();
 bs->open_flags = flags;
-bs->explicit_options = qdict_new();
-bs->options = qdict_new();
+if (options) {
+bs->explicit_options = qdict_clone_shallow(options);
+bs->options = qdict_clone_shallow(options);
+QDECREF(options);
+} else {
+bs->explicit_options = qdict_new();
+bs->options = qdict_new();
+}
 bs->opaque = NULL;
 
 update_options_from_flags(bs->options, flags);
diff --git a/block/commit.c b/block/commit.c
index c7857c3321..539e23c3f8 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -342,7 +342,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
 /* Insert commit_top block node above top, so we can block consistent read
  * on the backing chain below it */
 commit_top_bs = bdrv_new_open_driver(_commit_top, filter_node_name, 0,
- errp);
+ NULL, errp);
 if (commit_top_bs == NULL) {
 goto fail;
 }
@@ -494,7 +494,7 @@ int bdrv_commit(BlockDriverState *bs)
 backing_file_bs = backing_bs(bs);
 
 commit_top_bs = bdrv_new_open_driver(_commit_top, NULL, BDRV_O_RDWR,
- _err);
+ NULL, _err);
 if (commit_top_bs == NULL) {
 error_report_err(local_err);
 goto ro_cleanup;
diff --git a/block/mirror.c b/block/mirror.c
index c9a6a3ca86..e1a160e6ea 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -1164,7 +1164,7 @@ static void mirror_start_job(const char *job_id, 
BlockDriverState *bs,
  * reads on the top, while disabling it in the intermediate nodes, and make
  * the backing chain writable. */
 mirror_top_bs = bdrv_new_open_driver(_mirror_top, filter_node_name,
- BDRV_O_RDWR, errp);
+ BDRV_O_RDWR, NULL, errp);
 if (mirror_top_bs == NULL) {
 return;
 }
diff --git a/block/vvfat.c b/block/vvfat.c
index a9e207f7f0..6c59473baf 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -3194,7 +3194,7 @@ static int enable_write_target(BlockDriverState *bs, 
Error **errp)
 #endif
 
 backing = bdrv_new_open_driver(_write_target, NULL, 
BDRV_O_ALLOW_RDWR,
-   _abort);
+   NULL, _abort);
 *(void**) backing->opaque = s;
 
 bdrv_set_backing_hd(s->bs, backing, _abort);
diff --git a/include/block/block.h b/include/block/block.h
index ab80195378..d1f03cb48b 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -263,7 +263,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict 
*parent_options,
 BlockDriverState *bdrv_open(const char *filename, const char *reference,
 QDict *options, int flags, Error **errp);
 BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
-   int flags, Error **errp);
+   int flags, QDict *options, Error 
**errp);
 BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
 BlockDriverState *bs,
 QDict *options, int flags);
-- 
2.11.0




[Qemu-devel] [PATCH v2 6/6] block: remove BlockBackendPublic

2017-08-09 Thread Manos Pitsidianakis
All BlockBackend level throttling (via the implicit throttle filter node) is
done in block/block-backend.c and block/throttle-groups.c doesn't know
about BlockBackends anymore. Since BlockBackendPublic is not needed anymore, 
remove it.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block/block-backend.c  | 43 +++---
 block/qapi.c   |  4 ++--
 blockdev.c |  6 +++---
 include/sysemu/block-backend.h | 12 +---
 4 files changed, 25 insertions(+), 40 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 61983b7393..05f6e67222 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -36,7 +36,10 @@ struct BlockBackend {
 DriveInfo *legacy_dinfo;/* null unless created by drive_new() */
 QTAILQ_ENTRY(BlockBackend) link; /* for block_backends */
 QTAILQ_ENTRY(BlockBackend) monitor_link; /* for monitor_block_backends */
-BlockBackendPublic public;
+
+/* implicit throttle filter node for backwards compatibility with legacy
+ * throttling commands */
+BlockDriverState *throttle_node;
 
 void *dev;  /* attached device model, if any */
 bool legacy_dev;/* true if dev is not a DeviceState */
@@ -283,7 +286,7 @@ static void blk_delete(BlockBackend *blk)
 assert(!blk->refcnt);
 assert(!blk->name);
 assert(!blk->dev);
-if (blk->public.throttle_node) {
+if (blk->throttle_node) {
 blk_io_limits_disable(blk);
 }
 if (blk->root) {
@@ -574,19 +577,11 @@ BlockBackend *blk_by_legacy_dinfo(DriveInfo *dinfo)
 }
 
 /*
- * Returns a pointer to the publicly accessible fields of @blk.
+ * Returns the throttle_node field of @blk.
  */
-BlockBackendPublic *blk_get_public(BlockBackend *blk)
+BlockDriverState *blk_get_throttle_node(BlockBackend *blk)
 {
-return >public;
-}
-
-/*
- * Returns a BlockBackend given the associated @public fields.
- */
-BlockBackend *blk_by_public(BlockBackendPublic *public)
-{
-return container_of(public, BlockBackend, public);
+return blk->throttle_node;
 }
 
 /*
@@ -1879,15 +1874,15 @@ int blk_commit_all(void)
 /* throttling disk I/O limits */
 void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg)
 {
-assert(blk->public.throttle_node);
-throttle_group_config(throttle_get_tgm(blk->public.throttle_node), cfg);
+assert(blk->throttle_node);
+throttle_group_config(throttle_get_tgm(blk->throttle_node), cfg);
 }
 
 void blk_io_limits_disable(BlockBackend *blk)
 {
 BlockDriverState *bs, *throttle_node;
 
-throttle_node = blk_get_public(blk)->throttle_node;
+throttle_node = blk->throttle_node;
 
 assert(throttle_node);
 
@@ -1903,7 +1898,7 @@ void blk_io_limits_disable(BlockBackend *blk)
  * blk, at this point it might have more than one parent, so use
  * bdrv_replace_node(). This destroys throttle_node */
 bdrv_replace_node(throttle_node, bs, _abort);
-blk_get_public(blk)->throttle_node = NULL;
+blk->throttle_node = NULL;
 
 bdrv_unref(bs);
 bdrv_drained_end(bs);
@@ -1944,7 +1939,7 @@ void blk_io_limits_enable(BlockBackend *blk, const char 
*group,  Error **errp)
 
 end:
 bdrv_drained_end(bs);
-blk_get_public(blk)->throttle_node = throttle_node;
+blk->throttle_node = throttle_node;
 }
 
 void blk_io_limits_update_group(BlockBackend *blk, const char *group, Error 
**errp)
@@ -1952,11 +1947,11 @@ void blk_io_limits_update_group(BlockBackend *blk, 
const char *group, Error **er
 ThrottleGroupMember *tgm;
 
 /* this BB is not part of any group */
-if (!blk->public.throttle_node) {
+if (!blk->throttle_node) {
 return;
 }
 
-tgm = throttle_get_tgm(blk->public.throttle_node);
+tgm = throttle_get_tgm(blk->throttle_node);
 /* this BB is a part of the same group than the one we want */
 if (!g_strcmp0(throttle_group_get_name(tgm),
group)) {
@@ -1981,8 +1976,8 @@ static void blk_root_drained_begin(BdrvChild *child)
 
 /* Note that blk->root may not be accessible here yet if we are just
  * attaching to a BlockDriverState that is drained. Use child instead. */
-if (blk->public.throttle_node) {
-tgm = throttle_get_tgm(blk->public.throttle_node);
+if (blk->throttle_node) {
+tgm = throttle_get_tgm(blk->throttle_node);
 if (atomic_fetch_inc(>io_limits_disabled) == 0) {
 throttle_group_restart_tgm(tgm);
 }
@@ -1995,8 +1990,8 @@ static void blk_root_drained_end(BdrvChild *child)
 BlockBackend *blk = child->opaque;
 assert(blk->quiesce_counter);
 
-if (blk->public.throttle_node) {
-tgm = throttle_get_tgm(blk->public.throttle_node);
+if (blk->throttle_node) {
+tgm = throttle_get_tgm(blk->throttle_node);
 assert(tgm->io_li

Re: [Qemu-devel] [PATCH v3 5/7] block: add throttle block filter driver

2017-08-09 Thread Manos Pitsidianakis

On Wed, Aug 09, 2017 at 02:36:20PM +0200, Alberto Garcia wrote:

On Wed 09 Aug 2017 11:36:12 AM CEST, Manos Pitsidianakis wrote:

On Tue, Aug 08, 2017 at 05:04:48PM +0200, Alberto Garcia wrote:

On Tue 08 Aug 2017 04:56:20 PM CEST, Manos Pitsidianakis wrote:

So basically if we have anonymous groups, we accept limits in the
driver options but only without a group-name.


In the commit message you do however have limits and a group name, is
that a mistake?

   -drive driver=throttle,file.filename=foo.qcow2, \
  limits.iops-total=...,throttle-group=bar


Sorry this wasn't clear, I'm actually proposing to remove limits from
the throttle driver options and only create/config throttle groups via
-object/object-add.


Sorry I think it was me who misunderstood :-) Anyway in the new
command-line API I would be more inclined to have limits defined using
"-object throttle-group" and -drive would only reference the group id.

I understand that this implies that it wouldn't be possible to create
anonymous groups (at least not from the command line), is that a
problem?


We can accept anonymous groups if a user specifies limits but not a
group name in the throttle driver. (The only case where limits would
be acccepted)


Yeah but that's only if we have the limits.iops-total=... options in the
throttle driver. If we "remove limits from the throttle driver options
and only create/config throttle groups via -object/object-add" we 
cannot

do that.


We can check that groups is not defined at the same time as limits,



Not creating eponymous throttle groups via the throttle driver means
we don't need throttle_groups anymore, since even anonymous ones don't
need to be accounted for in a list.


I don't follow you here, how else do you get a group by its name?


If all eponymous groups are managed by the QOM tree, we should be able 
to iterate over the object root container for all ThrottleGroups just 
like qmp_query_iothreads() in iothread.c


signature.asc
Description: PGP signature


[Qemu-devel] [PATCH v4 4/7] block: convert ThrottleGroup to object with QOM

2017-08-09 Thread Manos Pitsidianakis
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 throttle-group,id=foo,x-iops-total=100,x-..
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": "throttle-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 <el13...@mail.ntua.gr>
---
v4 major changes:
  removed throttle_groups_lock
  changed reference counting of ThrottleGroup objects
Notes:
Note: I tested Markus Armbruster's patch in 
<87wp7fghi9@dusky.pond.sub.org>
on master and I can use this syntax successfuly:
-object '{ "qom-type" : "throttle-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 | 421 
 include/block/throttle-groups.h |   3 +
 include/qemu/throttle-options.h |  59 --
 include/qemu/throttle.h |   3 +
 qapi/block-core.json|  48 +
 tests/test-throttle.c   |   1 +
 util/throttle.c | 151 ++
 7 files changed, 626 insertions(+), 60 deletions(-)

diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index f711a3dc62..751e86c676 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,12 +75,11 @@ typedef struct ThrottleGroup {
 bool any_timer_armed[2];
 QEMUClockType clock_type;
 
-/* These two are protected by the global throttle_groups_lock */
-unsigned refcount;
+/* This field is protected by the global QEMU mutex */
 QTAILQ_ENTRY(ThrottleGroup) list;
 } ThrottleGroup;
 
-static QemuMutex throttle_groups_lock;
+/* This is protected by the global QEMU mutex */
 static QTAILQ_HEAD(, ThrottleGroup) throttle_groups =
 QTAILQ_HEAD_INITIALIZER(throttle_groups);
 
@@ -77,7 +88,11 @@ 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
+ * This function edits throttle_groups and must be called under the global
+ * mutex.
+ *
+ * @name: the name of t

[Qemu-devel] [PATCH v4 5/7] block: add throttle block filter driver

2017-08-09 Thread Manos Pitsidianakis
block/throttle.c uses existing I/O throttle infrastructure inside a
block filter driver. I/O operations are intercepted in the filter's
read/write coroutines, and referred to block/throttle-groups.c

The driver can be used with the syntax
-drive driver=throttle,file.filename=foo.qcow2, \
limits.iops-total=...,throttle-group=bar

The configuration flags and their semantics are identical to the
hardcoded throttling ones.

A node can be created referring to an existing group, and will overwrite
its limits if any are specified, otherwise they are retained.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block/Makefile.objs |   1 +
 block/throttle.c| 315 
 include/qemu/throttle-options.h |   1 +
 3 files changed, 317 insertions(+)
 create mode 100644 block/throttle.c

diff --git a/block/Makefile.objs b/block/Makefile.objs
index 2aaede4ae1..6eaf78a046 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -25,6 +25,7 @@ block-obj-y += accounting.o dirty-bitmap.o
 block-obj-y += write-threshold.o
 block-obj-y += backup.o
 block-obj-$(CONFIG_REPLICATION) += replication.o
+block-obj-y += throttle.o
 
 block-obj-y += crypto.o
 
diff --git a/block/throttle.c b/block/throttle.c
new file mode 100644
index 00..3e6cb1de7b
--- /dev/null
+++ b/block/throttle.c
@@ -0,0 +1,315 @@
+/*
+ * QEMU block throttling filter driver infrastructure
+ *
+ * Copyright (c) 2017 Manos Pitsidianakis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "block/throttle-groups.h"
+#include "qemu/throttle-options.h"
+#include "qapi/error.h"
+
+#undef THROTTLE_OPT_PREFIX
+#define THROTTLE_OPT_PREFIX "limits."
+static QemuOptsList throttle_opts = {
+.name = "throttle",
+.head = QTAILQ_HEAD_INITIALIZER(throttle_opts.head),
+.desc = {
+THROTTLE_OPTS,
+{
+.name = QEMU_OPT_THROTTLE_GROUP_NAME,
+.type = QEMU_OPT_STRING,
+.help = "throttle group name",
+},
+{ /* end of list */ }
+},
+};
+
+/* Extract ThrottleConfig options. Assumes cfg is initialized and will be
+ * checked for validity.
+ *
+ * Returns -1 and sets errp if a burst_length value is over UINT_MAX.
+ */
+static int throttle_extract_options(QemuOpts *opts, ThrottleConfig *cfg,
+Error **errp)
+{
+#define IF_OPT_SET(rvalue, opt_name) \
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX opt_name)) { \
+rvalue = qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX opt_name, 0); }
+
+IF_OPT_SET(cfg->buckets[THROTTLE_BPS_TOTAL].avg, QEMU_OPT_BPS_TOTAL);
+IF_OPT_SET(cfg->buckets[THROTTLE_BPS_READ].avg, QEMU_OPT_BPS_READ);
+IF_OPT_SET(cfg->buckets[THROTTLE_BPS_WRITE].avg, QEMU_OPT_BPS_WRITE);
+IF_OPT_SET(cfg->buckets[THROTTLE_OPS_TOTAL].avg, QEMU_OPT_IOPS_TOTAL);
+IF_OPT_SET(cfg->buckets[THROTTLE_OPS_READ].avg, QEMU_OPT_IOPS_READ);
+IF_OPT_SET(cfg->buckets[THROTTLE_OPS_WRITE].avg, QEMU_OPT_IOPS_WRITE);
+IF_OPT_SET(cfg->buckets[THROTTLE_BPS_TOTAL].max, QEMU_OPT_BPS_TOTAL_MAX);
+IF_OPT_SET(cfg->buckets[THROTTLE_BPS_READ].max, QEMU_OPT_BPS_READ_MAX);
+IF_OPT_SET(cfg->buckets[THROTTLE_BPS_WRITE].max, QEMU_OPT_BPS_WRITE_MAX);
+IF_OPT_SET(cfg->buckets[THROTTLE_OPS_TOTAL].max, QEMU_OPT_IOPS_TOTAL_MAX);
+IF_OPT_SET(cfg->buckets[THROTTLE_OPS_READ].max, QEMU_OPT_IOPS_READ_MAX);
+IF_OPT_SET(cfg->buckets[THROTTLE_OPS_WRITE].max, QEMU_OPT_IOPS_WRITE_MAX);
+IF_OPT_SET(cfg->op_size, QEMU_OPT_IOPS_SIZE);
+
+#define IF_OPT_UINT_SET(rvalue, opt_name) \
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX opt_name)) { \
+if (qemu_opt_get_number(opts,  \
+THROTTLE_OPT_PREFIX opt_name, 1) > UINT_MAX) { \
+error_setg(errp, "%s value must be in the range [0, %u]", \
+   THROTTLE_OPT_PREFIX opt_name, UINT_MAX); \
+return -1; \
+} \
+rvalue = qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX opt_name, 1); \
+}
+
+IF_OPT_UINT_SET(cfg->buckets[THROTTLE_BPS_TOTAL].burst_length,
+QEMU_OPT_BPS_TOTAL_MAX_LENGTH);
+IF_OPT_UINT_SET(cfg->buckets[THROTTLE_BP

[Qemu-devel] [PATCH v4 3/7] block: tidy ThrottleGroupMember initializations

2017-08-09 Thread Manos Pitsidianakis
Move the CoMutex and CoQueue inits inside throttle_group_register_tgm()
which is called whenever a ThrottleGroupMember is initialized. There's
no need for them to be separate.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block/block-backend.c   | 3 ---
 block/throttle-groups.c | 3 +++
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 6687a90660..df0200fc49 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -215,9 +215,6 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
 blk->shared_perm = shared_perm;
 blk_set_enable_write_cache(blk, true);
 
-qemu_co_mutex_init(>public.throttle_group_member.throttled_reqs_lock);
-qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[0]);
-qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[1]);
 block_acct_init(>stats);
 
 notifier_list_init(>remove_bs_notifiers);
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index a979e86243..f711a3dc62 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -508,6 +508,9 @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm,
  read_timer_cb,
  write_timer_cb,
  tgm);
+qemu_co_mutex_init(>throttled_reqs_lock);
+qemu_co_queue_init(>throttled_reqs[0]);
+qemu_co_queue_init(>throttled_reqs[1]);
 
 qemu_mutex_unlock(>lock);
 }
-- 
2.11.0




[Qemu-devel] [PATCH v4 2/7] block: add aio_context field in ThrottleGroupMember

2017-08-09 Thread Manos Pitsidianakis
timer_cb() needs to know about the current Aio context of the throttle
request that is woken up. In order to make ThrottleGroupMember backend
agnostic, this information is stored in an aio_context field instead of
accessing it from BlockBackend.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block/block-backend.c   | 15 +-
 block/throttle-groups.c | 38 -
 include/block/throttle-groups.h |  7 -
 tests/test-throttle.c   | 63 +
 4 files changed, 70 insertions(+), 53 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index bde6948d0e..6687a90660 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1685,17 +1685,15 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB 
*acb)
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
 {
 BlockDriverState *bs = blk_bs(blk);
-ThrottleTimers *tt;
+ThrottleGroupMember *tgm = >public.throttle_group_member;
 
 if (bs) {
-if (blk->public.throttle_group_member.throttle_state) {
-tt = >public.throttle_group_member.throttle_timers;
-throttle_timers_detach_aio_context(tt);
+if (tgm->throttle_state) {
+throttle_group_detach_aio_context(tgm);
 }
 bdrv_set_aio_context(bs, new_context);
-if (blk->public.throttle_group_member.throttle_state) {
-tt = >public.throttle_group_member.throttle_timers;
-throttle_timers_attach_aio_context(tt, new_context);
+if (tgm->throttle_state) {
+throttle_group_attach_aio_context(tgm, new_context);
 }
 }
 }
@@ -1929,7 +1927,8 @@ void blk_io_limits_disable(BlockBackend *blk)
 void blk_io_limits_enable(BlockBackend *blk, const char *group)
 {
 assert(!blk->public.throttle_group_member.throttle_state);
-throttle_group_register_tgm(>public.throttle_group_member, group);
+throttle_group_register_tgm(>public.throttle_group_member,
+group, blk_get_aio_context(blk));
 }
 
 void blk_io_limits_update_group(BlockBackend *blk, const char *group)
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index c8ed16ddf8..3b07b25f39 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -391,9 +391,6 @@ static void coroutine_fn 
throttle_group_restart_queue_entry(void *opaque)
 
 static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool 
is_write)
 {
-BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic,
-throttle_group_member);
-BlockBackend *blk = blk_by_public(blkp);
 Coroutine *co;
 RestartData rd = {
 .tgm = tgm,
@@ -401,7 +398,7 @@ static void 
throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write
 };
 
 co = qemu_coroutine_create(throttle_group_restart_queue_entry, );
-aio_co_enter(blk_get_aio_context(blk), co);
+aio_co_enter(tgm->aio_context, co);
 }
 
 void throttle_group_restart_tgm(ThrottleGroupMember *tgm)
@@ -449,13 +446,11 @@ void throttle_group_get_config(ThrottleGroupMember *tgm, 
ThrottleConfig *cfg)
 /* ThrottleTimers callback. This wakes up a request that was waiting
  * because it had been throttled.
  *
- * @blk:   the BlockBackend whose request had been throttled
+ * @tgm:   the ThrottleGroupMember whose request had been throttled
  * @is_write:  the type of operation (read/write)
  */
-static void timer_cb(BlockBackend *blk, bool is_write)
+static void timer_cb(ThrottleGroupMember *tgm, bool is_write)
 {
-BlockBackendPublic *blkp = blk_get_public(blk);
-ThrottleGroupMember *tgm = >throttle_group_member;
 ThrottleState *ts = tgm->throttle_state;
 ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
 
@@ -484,18 +479,18 @@ static void write_timer_cb(void *opaque)
  *
  * @tgm:   the ThrottleGroupMember to insert
  * @groupname: the name of the group
+ * @ctx:   the AioContext to use
  */
 void throttle_group_register_tgm(ThrottleGroupMember *tgm,
- const char *groupname)
+ const char *groupname,
+ AioContext *ctx)
 {
 int i;
-BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic,
-throttle_group_member);
-BlockBackend *blk = blk_by_public(blkp);
 ThrottleState *ts = throttle_group_incref(groupname);
 ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
 
 tgm->throttle_state = ts;
+tgm->aio_context = ctx;
 
 qemu_mutex_lock(>lock);
 /* If the ThrottleGroup is new set this ThrottleGroupMember as the token */
@@ -508,11 +503,11 @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm,
 QLIST_INSERT_HEAD(>

[Qemu-devel] [PATCH v4 7/7] block: add throttle block filter driver interface tests

2017-08-09 Thread Manos Pitsidianakis
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 tests/qemu-iotests/184 | 310 +
 tests/qemu-iotests/184.out | 422 +
 tests/qemu-iotests/group   |   1 +
 3 files changed, 733 insertions(+)
 create mode 100755 tests/qemu-iotests/184
 create mode 100644 tests/qemu-iotests/184.out

diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
new file mode 100755
index 00..5c11d1123d
--- /dev/null
+++ b/tests/qemu-iotests/184
@@ -0,0 +1,310 @@
+#!/bin/bash
+#
+# Test I/O throttle block filter driver interface
+#
+# Copyright (C) 2017 Manos Pitsidianakis
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner="Manos Pitsidianakis"
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1   # failure is the default!
+
+_cleanup()
+{
+_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+function do_run_qemu()
+{
+echo Testing: "$@" | _filter_imgfmt
+$QEMU -nographic -qmp-pretty stdio -serial none "$@"
+echo
+}
+
+function run_qemu()
+{
+do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
+  | _filter_qemu_io | _filter_generated_node_ids
+}
+
+_make_test_img 64M
+test_throttle=$($QEMU_IMG --help|grep throttle)
+[ "$test_throttle" = "" ] && _supported_fmt throttle
+
+echo
+echo "== checking interface =="
+
+run_qemu <

[Qemu-devel] [PATCH v4 6/7] block: add BlockDevOptionsThrottle to QAPI

2017-08-09 Thread Manos Pitsidianakis
This is needed to configure throttle filter driver nodes with QAPI.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 qapi/block-core.json | 22 +-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 0bdc69aa5f..12fd749a94 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -,6 +,7 @@
 # Drivers that are supported in block device operations.
 #
 # @vxhs: Since 2.10
+# @throttle: Since 2.11
 #
 # Since: 2.9
 ##
@@ -2231,7 +2232,7 @@
 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
 'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
 'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
-'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
+'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
 
 ##
 # @BlockdevOptionsFile:
@@ -3095,6 +3096,24 @@
 '*tls-creds': 'str' } }
 
 ##
+# @BlockdevOptionsThrottle:
+#
+# Driver specific block device options for the throttle driver
+#
+# @throttle-group:   the name of the throttle-group object to use. It will be
+#created if it doesn't already exist. If not specified, an
+#anonymous group will be created, which cannot be
+#referenced by other throttle nodes.
+# @file: reference to or definition of the data source block device
+# @limits:   ThrottleLimits options
+# Since: 2.11
+##
+{ 'struct': 'BlockdevOptionsThrottle',
+  'data': { '*throttle-group': 'str',
+'file' : 'BlockdevRef',
+'*limits' : 'ThrottleLimits'
+ } }
+##
 # @BlockdevOptions:
 #
 # Options for creating a block device.  Many options are available for all
@@ -3155,6 +3174,7 @@
   'replication':'BlockdevOptionsReplication',
   'sheepdog':   'BlockdevOptionsSheepdog',
   'ssh':'BlockdevOptionsSsh',
+  'throttle':   'BlockdevOptionsThrottle',
   'vdi':'BlockdevOptionsGenericFormat',
   'vhdx':   'BlockdevOptionsGenericFormat',
   'vmdk':   'BlockdevOptionsGenericCOWFormat',
-- 
2.11.0




[Qemu-devel] [PATCH v4 1/7] block: move ThrottleGroup membership to ThrottleGroupMember

2017-08-09 Thread Manos Pitsidianakis
This commit eliminates the 1:1 relationship between BlockBackend and
throttle group state.  Users will be able to create multiple throttle
nodes, each with its own throttle group state, in the future.  The
throttle group state cannot be per-BlockBackend anymore, it must be
per-throttle node. This is done by gathering ThrottleGroup membership
details from BlockBackendPublic into ThrottleGroupMember and refactoring
existing code to use the structure.

Reviewed-by: Alberto Garcia <be...@igalia.com>
Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block/block-backend.c   |  66 +
 block/qapi.c|   8 +-
 block/throttle-groups.c | 288 
 blockdev.c  |   4 +-
 include/block/throttle-groups.h |  39 +-
 include/sysemu/block-backend.h  |  20 +--
 tests/test-throttle.c   |  53 
 7 files changed, 252 insertions(+), 226 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 968438c149..bde6948d0e 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -215,9 +215,9 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
 blk->shared_perm = shared_perm;
 blk_set_enable_write_cache(blk, true);
 
-qemu_co_mutex_init(>public.throttled_reqs_lock);
-qemu_co_queue_init(>public.throttled_reqs[0]);
-qemu_co_queue_init(>public.throttled_reqs[1]);
+qemu_co_mutex_init(>public.throttle_group_member.throttled_reqs_lock);
+qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[0]);
+qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[1]);
 block_acct_init(>stats);
 
 notifier_list_init(>remove_bs_notifiers);
@@ -285,7 +285,7 @@ static void blk_delete(BlockBackend *blk)
 assert(!blk->refcnt);
 assert(!blk->name);
 assert(!blk->dev);
-if (blk->public.throttle_state) {
+if (blk->public.throttle_group_member.throttle_state) {
 blk_io_limits_disable(blk);
 }
 if (blk->root) {
@@ -596,9 +596,12 @@ BlockBackend *blk_by_public(BlockBackendPublic *public)
  */
 void blk_remove_bs(BlockBackend *blk)
 {
+ThrottleTimers *tt;
+
 notifier_list_notify(>remove_bs_notifiers, blk);
-if (blk->public.throttle_state) {
-throttle_timers_detach_aio_context(>public.throttle_timers);
+if (blk->public.throttle_group_member.throttle_state) {
+tt = >public.throttle_group_member.throttle_timers;
+throttle_timers_detach_aio_context(tt);
 }
 
 blk_update_root_state(blk);
@@ -620,9 +623,10 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, 
Error **errp)
 bdrv_ref(bs);
 
 notifier_list_notify(>insert_bs_notifiers, blk);
-if (blk->public.throttle_state) {
+if (blk->public.throttle_group_member.throttle_state) {
 throttle_timers_attach_aio_context(
->public.throttle_timers, bdrv_get_aio_context(bs));
+>public.throttle_group_member.throttle_timers,
+bdrv_get_aio_context(bs));
 }
 
 return 0;
@@ -984,8 +988,9 @@ int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t 
offset,
 bdrv_inc_in_flight(bs);
 
 /* throttling disk I/O */
-if (blk->public.throttle_state) {
-throttle_group_co_io_limits_intercept(blk, bytes, false);
+if (blk->public.throttle_group_member.throttle_state) {
+
throttle_group_co_io_limits_intercept(>public.throttle_group_member,
+bytes, false);
 }
 
 ret = bdrv_co_preadv(blk->root, offset, bytes, qiov, flags);
@@ -1008,10 +1013,10 @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, 
int64_t offset,
 }
 
 bdrv_inc_in_flight(bs);
-
 /* throttling disk I/O */
-if (blk->public.throttle_state) {
-throttle_group_co_io_limits_intercept(blk, bytes, true);
+if (blk->public.throttle_group_member.throttle_state) {
+
throttle_group_co_io_limits_intercept(>public.throttle_group_member,
+bytes, true);
 }
 
 if (!blk->enable_write_cache) {
@@ -1680,15 +1685,17 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB 
*acb)
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
 {
 BlockDriverState *bs = blk_bs(blk);
+ThrottleTimers *tt;
 
 if (bs) {
-if (blk->public.throttle_state) {
-throttle_timers_detach_aio_context(>public.throttle_timers);
+if (blk->public.throttle_group_member.throttle_state) {
+tt = >public.throttle_group_member.throttle_timers;
+throttle_timers_detach_aio_context(tt);
 }
 bdrv_set_aio_context(bs, new_context);
-if (blk->public.throttle_state) {
-throttle_timers_attach_aio_context(>public.throttle_timers,
-  

[Qemu-devel] [PATCH v4 0/7] add throttle block driver filter

2017-08-09 Thread Manos Pitsidianakis
This series adds a throttle block driver filter. Currently throttling is done
at the BlockBackend level. Using block driver interfaces we can move the
throttling to any point in the BDS graph using a throttle node which uses the
existing throttling code. This allows for potentially more complex
configurations (throttling at any point in the graph, chained filters)

v4:
  fix suggestions in block/throttle.c
  fix suggestions in block/throttle_groups.c
  add doc note in BlockDevOptionsThrottle
  
v3:
  fix style error in 'add aio_context field in ThrottleGroupMember'

v2:
  change QOM throttle group object name
  print valid ranges for uint on error
  move frees in throttle_group_obj_finalize()
  split throttle_group_{set,get}()
  add throttle_recurse_is_first_non_filter()

Manos Pitsidianakis (7):
  block: move ThrottleGroup membership to ThrottleGroupMember
  block: add aio_context field in ThrottleGroupMember
  block: tidy ThrottleGroupMember initializations
  block: convert ThrottleGroup to object with QOM
  block: add throttle block filter driver
  block: add BlockDevOptionsThrottle to QAPI
  block: add throttle block filter driver interface tests

 block/Makefile.objs |   1 +
 block/block-backend.c   |  62 ++--
 block/qapi.c|   8 +-
 block/throttle-groups.c | 730 +---
 block/throttle.c| 315 +
 blockdev.c  |   4 +-
 include/block/throttle-groups.h |  47 ++-
 include/qemu/throttle-options.h |  60 ++--
 include/qemu/throttle.h |   3 +
 include/sysemu/block-backend.h  |  20 +-
 qapi/block-core.json|  70 +++-
 tests/qemu-iotests/184  | 310 +
 tests/qemu-iotests/184.out  | 422 +++
 tests/qemu-iotests/group|   1 +
 tests/test-throttle.c   | 111 +++---
 util/throttle.c | 151 +
 16 files changed, 1995 insertions(+), 320 deletions(-)
 create mode 100644 block/throttle.c
 create mode 100755 tests/qemu-iotests/184
 create mode 100644 tests/qemu-iotests/184.out

-- 
2.11.0




Re: [Qemu-devel] [PATCH v3 5/7] block: add throttle block filter driver

2017-08-09 Thread Manos Pitsidianakis

On Tue, Aug 08, 2017 at 05:04:48PM +0200, Alberto Garcia wrote:

On Tue 08 Aug 2017 04:56:20 PM CEST, Manos Pitsidianakis wrote:

So basically if we have anonymous groups, we accept limits in the
driver options but only without a group-name.


In the commit message you do however have limits and a group name, is
that a mistake?

   -drive driver=throttle,file.filename=foo.qcow2, \
  limits.iops-total=...,throttle-group=bar


Sorry this wasn't clear, I'm actually proposing to remove limits from
the throttle driver options and only create/config throttle groups via
-object/object-add.


Sorry I think it was me who misunderstood :-) Anyway in the new
command-line API I would be more inclined to have limits defined using
"-object throttle-group" and -drive would only reference the group id.

I understand that this implies that it wouldn't be possible to create
anonymous groups (at least not from the command line), is that a
problem?



We can accept anonymous groups if a user specifies limits but not a 
group name in the throttle driver. (The only case where limits would be 
acccepted)


Not creating eponymous throttle groups via the throttle driver means we 
don't need throttle_groups anymore, since even anonymous ones don't need 
to be accounted for in a list. I will send a new revision for this 
series but I can make this change in a later patch if everyone agrees.


signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH v3 5/7] block: add throttle block filter driver

2017-08-08 Thread Manos Pitsidianakis

On Tue, Aug 08, 2017 at 04:53:08PM +0200, Alberto Garcia wrote:

On Tue 08 Aug 2017 03:45:44 PM CEST, Manos Pitsidianakis wrote:

On Tue, Aug 08, 2017 at 03:13:36PM +0200, Alberto Garcia wrote:

On Mon 31 Jul 2017 11:54:41 AM CEST, Manos Pitsidianakis wrote:

block/throttle.c uses existing I/O throttle infrastructure inside a
block filter driver. I/O operations are intercepted in the filter's
read/write coroutines, and referred to block/throttle-groups.c

The driver can be used with the syntax
-drive driver=throttle,file.filename=foo.qcow2, \
limits.iops-total=...,throttle-group=bar


Sorry for not having noticed this earlier, but can't you define the
throttling group (and its limits) using -object throttle-group ... as
shown in the previous patch, and simply reference it here? Or would we
have two alternative ways of setting the throttling limits?

What happens if you have many -drive lines each one with a different set
of limits but with the same throttling group?


The limits of the last one to be processed will win.


That's what the current throttling API does, and I tend to agree that
it's not completely straightforward (a few people have asked me the same
question since this feature is available).

If we're going to add a new API we could eliminate this ambiguity. After
all the previous -drive throttling.iops-total=... would still be
available, wouldn't it?


Indeed, it already is.




So basically if we have anonymous groups, we accept limits in the
driver options but only without a group-name.


In the commit message you do however have limits and a group name, is
that a mistake?

   -drive driver=throttle,file.filename=foo.qcow2, \
  limits.iops-total=...,throttle-group=bar



Sorry this wasn't clear, I'm actually proposing to remove limits from 
the throttle driver options and only create/config throttle groups via 
-object/object-add.


signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH v3 5/7] block: add throttle block filter driver

2017-08-08 Thread Manos Pitsidianakis

On Tue, Aug 08, 2017 at 03:13:36PM +0200, Alberto Garcia wrote:

On Mon 31 Jul 2017 11:54:41 AM CEST, Manos Pitsidianakis wrote:

block/throttle.c uses existing I/O throttle infrastructure inside a
block filter driver. I/O operations are intercepted in the filter's
read/write coroutines, and referred to block/throttle-groups.c

The driver can be used with the syntax
-drive driver=throttle,file.filename=foo.qcow2, \
limits.iops-total=...,throttle-group=bar


Sorry for not having noticed this earlier, but can't you define the
throttling group (and its limits) using -object throttle-group ... as
shown in the previous patch, and simply reference it here? Or would we
have two alternative ways of setting the throttling limits?

What happens if you have many -drive lines each one with a different set
of limits but with the same throttling group?


The limits of the last one to be processed will win. Quoting a reply I 
made to Kevin on the interface test patch:



You're right, I missed this. The test result shows that this command
succeeds. Do we really want to allow other nodes to be affected with a
blockdev-add? Wouldn't it be cleaner to just forbid the combination of
limits and throtte-group?


So basically only anonymous, immutable groups can be created through the 
driver then. All other shared group configurations must be explicitly 
created with an -object / object-add syntax. I think this is a neat 
separation and compromise if we allow anonymous groups. If not, we can 
ignore limits on the throttle driver.


So basically if we have anonymous groups, we accept limits in the driver 
options but only without a group-name. Without anonymous groups, we 
remove limits from the driver options and only use the 
object-add/-object commands to create throttle groups. Does this sound 
like a good idea? It will be more verbose for the human user. One 
advantage: all throttle groups can then be managed through 
qom-set/qom-get since they are owned by the qom tree.


signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH v3 5/7] block: add throttle block filter driver

2017-08-03 Thread Manos Pitsidianakis

On Thu, Aug 03, 2017 at 06:58:30AM -0500, Eric Blake wrote:

On 08/03/2017 03:07 AM, Kevin Wolf wrote:

Am 31.07.2017 um 11:54 hat Manos Pitsidianakis geschrieben:

block/throttle.c uses existing I/O throttle infrastructure inside a
block filter driver. I/O operations are intercepted in the filter's
read/write coroutines, and referred to block/throttle-groups.c

The driver can be used with the syntax
-drive driver=throttle,file.filename=foo.qcow2, \
limits.iops-total=...,throttle-group=bar

The configuration flags and their semantics are identical to the
hardcoded throttling ones.

A node can be created referring to an existing group, and will overwrite
its limits if any are specified, otherwise they are retained.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---



+
+.is_filter  =   true,
+};


What about .bdrv_co_get_block_status?


And if so, do you want my byte-based block status to go in first?  (Our
two series conflict, so we need to pick who needs to rebase on top of
the other).


No problem. My patch is in Kevin's branch for 2.11.  Feel free to merge 
first if needed, I can rebase my patch if you do. 


signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH v3 7/7] block: add throttle block filter driver interface tests

2017-08-03 Thread Manos Pitsidianakis

On Thu, Aug 03, 2017 at 03:32:58PM +0200, Kevin Wolf wrote:

Am 03.08.2017 um 15:24 hat Manos Pitsidianakis geschrieben:

On Thu, Aug 03, 2017 at 10:07:50AM +0200, Kevin Wolf wrote:
> Am 31.07.2017 um 11:54 hat Manos Pitsidianakis geschrieben:
> > Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
>
> I would add at least two more cases:
>
> * Both limits and throttle-group are given in blockdev-add
This exists in the "property changes in ThrottleGroup" section,


You're right, I missed this. The test result shows that this command
succeeds. Do we really want to allow other nodes to be affected with a
blockdev-add? Wouldn't it be cleaner to just forbid the combination of
limits and throtte-group?


So basically only anonymous, immutable groups can be created through the 
driver then. All other shared group configurations must be explicitly 
created with an -object / object-add syntax. I think this is a neat 
separation and compromise if we allow anonymous groups. If not, we can 
ignore limits on the throttle driver.




> * limits and throttle-group are both missing
this creates an anonymous group with no limits. Should we fail at this case?


I'm not sure, you could argue either way. But there should be a test to
check that the semantics won't change.

If we're going with Stefan's suggestion that anonymous groups shouldn't
exist, then the question is moot anyway.


> It would also be nice to test that query-block reflects the new throttle
> group limits correctly when they are changed after the fact.

This belongs to the remove legacy patch, since query-block displays the
legacy limits.


Ok, fair enough.

Kevin





signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH v3 7/7] block: add throttle block filter driver interface tests

2017-08-03 Thread Manos Pitsidianakis

On Thu, Aug 03, 2017 at 10:07:50AM +0200, Kevin Wolf wrote:

Am 31.07.2017 um 11:54 hat Manos Pitsidianakis geschrieben:

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>


I would add at least two more cases:

* Both limits and throttle-group are given in blockdev-add

This exists in the "property changes in ThrottleGroup" section,


* limits and throttle-group are both missing
this creates an anonymous group with no limits. Should we fail at this 
case? 


It would also be nice to test that query-block reflects the new throttle
group limits correctly when they are changed after the fact.


This belongs to the remove legacy patch, since query-block displays the 
legacy limits.


signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH v3 4/7] block: convert ThrottleGroup to object with QOM

2017-08-03 Thread Manos Pitsidianakis

On Thu, Aug 03, 2017 at 01:17:01PM +0200, Kevin Wolf wrote:

Am 03.08.2017 um 12:53 hat Stefan Hajnoczi geschrieben:

On Thu, Aug 03, 2017 at 10:08:01AM +0200, Kevin Wolf wrote:
> Am 02.08.2017 um 12:57 hat Manos Pitsidianakis geschrieben:
> > On Wed, Aug 02, 2017 at 11:39:22AM +0100, Stefan Hajnoczi wrote:
> > > On Tue, Aug 01, 2017 at 07:49:33PM +0300, Manos Pitsidianakis wrote:
> > > > On Tue, Aug 01, 2017 at 04:47:03PM +0100, Stefan Hajnoczi wrote:
> > > > > On Mon, Jul 31, 2017 at 12:54:40PM +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 throttle-group,id=foo,x-iops-total=100,x-..
> > > > > > 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": "throttle-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).
> > > > >
> > > > > blockdev.c automatically assigns -drive id= to the group name if
> > > > > throttling.group= wasn't given.  So who will use anonymous 
single-drive
> > > > > mode?
> > > >
> > > > Manual filter nodes. It's possible to not pass a group name value and 
the
> > > > resulting group will be anonymous. Are you suggesting to move this 
change to
> > > > the throttle filter patch?
> > >
> > > What is the use case?  Human users will stick to the legacy syntax
> > > because it's convenient.  Management tools will use the filter
> > > explicitly in the future, and it's easy for them to choose a name.
> > >
> > > Unless there is a need for this case I'd prefer to make the group name
> > > mandatory.  That way there are less code paths to worry about.
> >
> > I think Kevin requested this though I don't really remember the use case.
>
> There is no legacy syntax for putting a throttle node anywhere but at
> the root of a BlockBackend. If you want to throttle e.g. only a specific
> backing

Re: [Qemu-devel] [PATCH v3 5/7] block: add throttle block filter driver

2017-08-03 Thread Manos Pitsidianakis

On Thu, Aug 03, 2017 at 10:07:41AM +0200, Kevin Wolf wrote:

Am 31.07.2017 um 11:54 hat Manos Pitsidianakis geschrieben:

+/* Extract ThrottleConfig options. Assumes cfg is initialized and will be
+ * checked for validity.
+ */
+static int throttle_extract_options(QemuOpts *opts, ThrottleConfig *cfg,
+ Error **errp)
+{
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL)) {
+cfg->buckets[THROTTLE_BPS_TOTAL].avg =
+qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL,
+0);
+}
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ)) {
+cfg->buckets[THROTTLE_BPS_READ].avg  =
+qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ,
+0);
+}
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE)) {
+cfg->buckets[THROTTLE_BPS_WRITE].avg =
+qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE,
+0);
+}
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL)) {
+cfg->buckets[THROTTLE_OPS_TOTAL].avg =
+qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL,
+0);
+}
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ)) {
+cfg->buckets[THROTTLE_OPS_READ].avg =
+qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ,
+0);
+}
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE)) {
+cfg->buckets[THROTTLE_OPS_WRITE].avg =
+qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE,
+0);
+}
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX)) {
+cfg->buckets[THROTTLE_BPS_TOTAL].max =
+qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX
+QEMU_OPT_BPS_TOTAL_MAX, 0);
+}
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX)) {
+cfg->buckets[THROTTLE_BPS_READ].max  =
+qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX
+QEMU_OPT_BPS_READ_MAX, 0);
+}
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX)) {
+cfg->buckets[THROTTLE_BPS_WRITE].max =
+qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX
+QEMU_OPT_BPS_WRITE_MAX, 0);
+}
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL_MAX)) {
+cfg->buckets[THROTTLE_OPS_TOTAL].max =
+qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX
+QEMU_OPT_IOPS_TOTAL_MAX, 0);
+}
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ_MAX)) {
+cfg->buckets[THROTTLE_OPS_READ].max =
+qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX
+QEMU_OPT_IOPS_READ_MAX, 0);
+}
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE_MAX)) {
+cfg->buckets[THROTTLE_OPS_WRITE].max =
+qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX
+QEMU_OPT_IOPS_WRITE_MAX, 0);
+}
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX_LENGTH)) 
{
+if (qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX
+QEMU_OPT_BPS_TOTAL_MAX_LENGTH, 1) > UINT_MAX) {
+error_setg(errp, "%s value must be in the range [0, %u]",
+   THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX_LENGTH,
+   UINT_MAX);
+return -1;
+}
+cfg->buckets[THROTTLE_BPS_TOTAL].burst_length =
+qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX
+QEMU_OPT_BPS_TOTAL_MAX_LENGTH, 1);
+}
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX_LENGTH)) {
+if (qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX
+QEMU_OPT_BPS_READ_MAX_LENGTH, 1) > UINT_MAX) {
+error_setg(errp, "%s must be in the range [0, %u]",
+   THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX_LENGTH,
+   UINT_MAX);
+return -1;
+}
+cfg->buckets[THROTTLE_BPS_READ].burst_length  =
+qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX
+QEMU_OPT_BPS_READ_MAX_LENGTH, 1);
+}
+if (qemu_opt_get(opts, THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX_LENGTH)) 
{
+if (qemu_opt_get_number(opts, THROTTLE_OPT_PREFIX
+QEMU_OPT_BPS_WRITE_MAX_LENGTH, 1) > UINT_MAX) {
+error_setg(errp, "%s must be in the range [0, %u]",
+   THROTTLE_OPT_PREFIX QEMU_OP

Re: [Qemu-devel] [PATCH 3/3] block: remove legacy I/O throttling

2017-08-02 Thread Manos Pitsidianakis

On Wed, Aug 02, 2017 at 12:33:19PM +0200, Kevin Wolf wrote:

Am 02.08.2017 um 12:07 hat Stefan Hajnoczi geschrieben:

On Tue, Aug 01, 2017 at 04:49:07PM +0300, Manos Pitsidianakis wrote:
> diff --git a/block.c b/block.c
> index 9ebdba28b0..c6aad25286 100644
> --- a/block.c
> +++ b/block.c
> @@ -1975,6 +1975,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState 
*child_bs,
>  child = g_new(BdrvChild, 1);
>  *child = (BdrvChild) {
>  .bs = NULL,
> +.parent_bs  = NULL,
>  .name   = g_strdup(child_name),
>  .role   = child_role,
>  .perm   = perm,
> @@ -2009,6 +2010,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState 
*parent_bs,
>  if (child == NULL) {
>  return NULL;
>  }
> +child->parent_bs = parent_bs;
>
>  QLIST_INSERT_HEAD(_bs->children, child, next);
>  return child;
> @@ -3729,6 +3731,12 @@ const char *bdrv_get_parent_name(const 
BlockDriverState *bs)
>  return name;
>  }
>  }
> +if (c->parent_bs && c->parent_bs->implicit) {
> +name = bdrv_get_parent_name(c->parent_bs);
> +if (name && *name) {
> +return name;
> +}
> +}
>  }
>
>  return NULL;

This should be a separate patch.

Who updates parent_bs if the parent is changed (e.g.
bdrv_replace_node())?

We already have bs->parents.  Why is BdrvChild->parent_bs needed?


I haven't look at the whole patch yet, but BdrvChild->parent_bs is a
thing that intentionally doesn't exist. A node simply has no business
knowing its parents - which may or may not be BlockDriverStates (the
obvious example where they aren't BDSes are BlockBackends, but block
jobs own some BdrvChild objects, too).

Usually the replacement is a BdrvChildRole callback.

Kevin


I think accessing the parent bs is necessary for the reasons I specified 
in my reply to Stefan. Will a callback that returns BdrvChild->opaque 
(parent_bs) for child_file and child_backing be okay?




signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH v3 4/7] block: convert ThrottleGroup to object with QOM

2017-08-02 Thread Manos Pitsidianakis

On Wed, Aug 02, 2017 at 11:39:22AM +0100, Stefan Hajnoczi wrote:

On Tue, Aug 01, 2017 at 07:49:33PM +0300, Manos Pitsidianakis wrote:

On Tue, Aug 01, 2017 at 04:47:03PM +0100, Stefan Hajnoczi wrote:
> On Mon, Jul 31, 2017 at 12:54:40PM +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 throttle-group,id=foo,x-iops-total=100,x-..
> > 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": "throttle-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).
>
> blockdev.c automatically assigns -drive id= to the group name if
> throttling.group= wasn't given.  So who will use anonymous single-drive
> mode?

Manual filter nodes. It's possible to not pass a group name value and the
resulting group will be anonymous. Are you suggesting to move this change to
the throttle filter patch?


What is the use case?  Human users will stick to the legacy syntax
because it's convenient.  Management tools will use the filter
explicitly in the future, and it's easy for them to choose a name.

Unless there is a need for this case I'd prefer to make the group name
mandatory.  That way there are less code paths to worry about.


I think Kevin requested this though I don't really remember the use 
case.



> > @@ -87,32 +99,30 @@ ThrottleState *throttle_group_incref(const char *name)
> >
> >  qemu_mutex_lock(_groups_lock);
> >
> > -/* Look for an existing group with that name */
> > -QTAILQ_FOREACH(iter, _groups, list) {
> > -if (!strcmp(name, iter->name)) {
> > -tg = iter;
> > -break;
> > +if (name) {
> > +/* Look for an existing group with that name */
> > +QTAILQ_FOREACH(iter, _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(>lock);
> > -throttle_init(>ts);
> > -QLIST_INIT(>head);
> > -
> > -QTAILQ_INSERT_TAIL(_groups, tg, list);
> > +throttle_group_obj_complete((UserCreatable *)tg, _abort);
> >  }
> >
> > -tg->refcount++;
> > +qemu_mutex_lock(>l

Re: [Qemu-devel] [PATCH 3/3] block: remove legacy I/O throttling

2017-08-02 Thread Manos Pitsidianakis

On Wed, Aug 02, 2017 at 11:07:24AM +0100, Stefan Hajnoczi wrote:

On Tue, Aug 01, 2017 at 04:49:07PM +0300, Manos Pitsidianakis wrote:

diff --git a/block.c b/block.c
index 9ebdba28b0..c6aad25286 100644
--- a/block.c
+++ b/block.c
@@ -1975,6 +1975,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState 
*child_bs,
 child = g_new(BdrvChild, 1);
 *child = (BdrvChild) {
 .bs = NULL,
+.parent_bs  = NULL,
 .name   = g_strdup(child_name),
 .role   = child_role,
 .perm   = perm,
@@ -2009,6 +2010,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
 if (child == NULL) {
 return NULL;
 }
+child->parent_bs = parent_bs;

 QLIST_INSERT_HEAD(_bs->children, child, next);
 return child;
@@ -3729,6 +3731,12 @@ const char *bdrv_get_parent_name(const BlockDriverState 
*bs)
 return name;
 }
 }
+if (c->parent_bs && c->parent_bs->implicit) {
+name = bdrv_get_parent_name(c->parent_bs);
+if (name && *name) {
+return name;
+}
+}
 }

 return NULL;


This should be a separate patch.

Who updates parent_bs if the parent is changed (e.g.
bdrv_replace_node())?

We already have bs->parents.  Why is BdrvChild->parent_bs needed?



If I haven't misunderstood this, BdrvChild holds only the child part of 
the parent-child relationship and there's no way to access a parent from 
bs->parents. bdrv_replace_node() will thus only replace the child part 
in BdrvChild from the aspect of the parent. In the old child bs's 
perspective, one of the nodes of bs->parents is removed and in the new 
child bs's perspective a new node in bs->parents was inserted. parent_bs 
thus remains immutable.


child->parent_bs is needed in this patch because in jobs if a job-ID is 
not specified the parent name is used, but this fails if the parent is 
an implicit node instead of BlockBackend and causes a regression 
(certain job setups suddenly need an explicit job ID instead of just 
working).



-void blk_io_limits_disable(BlockBackend *blk)
+void blk_io_limits_disable(BlockBackend *blk, Error **errp)
 {
-assert(blk->public.throttle_group_member.throttle_state);
-bdrv_drained_begin(blk_bs(blk));


Is it safe to drop drained_begin?  We must ensure that no I/O requests
run during this function.


Thanks, I will put it back in.


-throttle_group_unregister_tgm(>public.throttle_group_member);
-bdrv_drained_end(blk_bs(blk));
+BlockDriverState *bs, *throttle_node;
+
+throttle_node = blk_get_public(blk)->throttle_node;


Is blk_get_public() still necessary?  Perhaps we can do away with the
concept of the public struct now.  It doesn't need to be done in this
patch though.


I can include a patch to move throttle_node to BlockBackend and remove 
all BlockBackendPublic code, is that okay?





+
+assert(throttle_node && throttle_node->refcnt == 1);


Are you sure the throttle_node->refcnt == 1 assertion holds?  For
example, does the built-in NBD server have a reference to the throttle
node if nbd-server-add is called after throttling has been enabled?

Since we have the blk->throttle_node pointer we know we're the owner.
Others may be using the node too but we may choose to remove it at any
time.


Hm.. If that's possible I guess we want the removal to be visible to the 
nbd server too. I will use bdrv_replace_node() instead.


signature.asc
Description: PGP signature


Re: [Qemu-devel] [PATCH v3 4/7] block: convert ThrottleGroup to object with QOM

2017-08-01 Thread Manos Pitsidianakis

On Tue, Aug 01, 2017 at 04:47:03PM +0100, Stefan Hajnoczi wrote:

On Mon, Jul 31, 2017 at 12:54:40PM +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 throttle-group,id=foo,x-iops-total=100,x-..
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": "throttle-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).


blockdev.c automatically assigns -drive id= to the group name if
throttling.group= wasn't given.  So who will use anonymous single-drive
mode?


Manual filter nodes. It's possible to not pass a group name value and 
the resulting group will be anonymous. Are you suggesting to move this 
change to the throttle filter patch?



Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
Notes:
Note: I tested Markus Armbruster's patch in 
<87wp7fghi9@dusky.pond.sub.org>
on master and I can use this syntax successfuly:
-object '{ "qom-type" : "throttle-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 | 402 
 include/block/throttle-groups.h |   3 +
 include/qemu/throttle-options.h |  59 --
 include/qemu/throttle.h |   3 +
 qapi/block-core.json|  48 +
 tests/test-throttle.c   |   1 +
 util/throttle.c | 151 +++
 7 files changed, 617 insertions(+), 50 deletions(-)

diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index f711a3dc62..b9c5036e44 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
  * cr

Re: [Qemu-devel] [RFC] block-insert-node and block-job-delete

2017-08-01 Thread Manos Pitsidianakis

On Tue, Aug 01, 2017 at 03:50:36PM +0200, Kevin Wolf wrote:

Am 31.07.2017 um 19:30 hat Manos Pitsidianakis geschrieben:

On Fri, Jul 28, 2017 at 02:08:43PM +0200, Kevin Wolf wrote:
> Am 27.07.2017 um 12:07 hat Stefan Hajnoczi geschrieben:
> > On Wed, Jul 26, 2017 at 09:23:20PM +0300, Manos Pitsidianakis wrote:
> > > On Wed, Jul 26, 2017 at 04:12:21PM +0100, Stefan Hajnoczi wrote:
> > > > On Wed, Jul 26, 2017 at 05:19:24PM +0300, Manos Pitsidianakis wrote:
> > > > > This proposal follows a discussion we had with Kevin and Stefan on 
filter
> > > > > node management.
> > > > >
> > > > > With block filter drivers arises a need to configure filter nodes on 
runtime
> > > > > with QMP on live graphs. A problem with doing live graph 
modifications is
> > > > > that some block jobs modify the graph when they are done and don't 
operate
> > > > > under any synchronisation, resulting in a race condition if we try to 
insert
> > > > > a filter node in the place of an existing edge.
> > > >
> > > > But maybe you are thinking about higher level race conditions between
> > > > QMP commands.  Can you give an example of the race?
> > >
> > > Exactly, synchronisation between the QMP/user actions. Here's an example,
> > > correct me if I'm wrong:
> > >
> > > User issues a block-commit to this tree to commit A onto B:
> > >BB -> A -> B
> > >
> > > This inserts the dummy mirror node at the top since this is a mirror job
> > > (active commit)
> > >BB -> dummy -> A -> B
> > >
> > > User wants to add a filter node F below the BB. First we create the node:
> > >BB -> dummy -> A -> B
> > >   F /
> > >
> > > Commit finishes before we do block-insert-node, dummy and A is removed 
from
> > > the BB's chain, mirror_exit calls bdrv_replace_node()
> > >
> > >BB > B
> > >F -> /
> > >
> > > Now inserting F under BB will error since dummy does not exist any more.
> >
> > I see the diagrams but the flow isn't clear without the user's QMP
> > commands.
> >
> > F is created using blockdev-add?  What are the parameters and how does
> > it know about dummy?  I think this is an interesting question in itself
> > because dummy is a transient internal node that QMP users don't
> > necessarily know about.
>
> We can expect that users of block-insert-node also know about block job
> filter nodes, simply because the former is newer than the latter.
>
> (I also don't like the name "dummy", this makes it sound like it's not
> really a proper node. In reality, there is little reason to treat it
> specially.)
>
> > What is the full block-insert-node command?
> >
> > > The proposal doesn't guard against the following:
> > > User issues a block-commit to this tree to commit B onto C:
> > >BB -> A -> B -> C
> > >
> > > The dummy node (commit's top bs is A):
> > >BB -> A -> dummy -> B -> C
> > >
> > > blockdev-add of a filter we wish to eventually be between A and C:
> > >BB -> A -> dummy -> B -> C
> > > F/
> > >
> > > if commit finishes before we issue block-insert-node (commit_complete()
> > > calls bdrv_set_backing_hd() which only touches A)
> > >BB -> A --> C
> > >   F -> dummy -> B /
> > >resulting in error when issuing block-insert-node,
> > >
> > > else if we set the job to manual-delete and insert F:
> > >BB -> A -> F -> dummy -> B -> C
> > > deleting the job will result in F being lost since the job's top bs wasn't
> > > updated.
> >
> > manual-delete is a solution for block jobs.  The write threshold
> > feature is a plain QMP command that in the future will create a
> > transient internal node (before write notifier).
>
> Yes, that becomes a legacy QMP command then. The new way is blockdev-add
> and block-insert-node for write threshold, too.
>
> Apart from that, a write threshold node never disappears by itself, it
> is only inserted or removed in the context of a QMP command. That makes
> it a lot less dangerous than automatic block completion.
>
> > I'm not sure it makes sense to turn the write threshold feature into a
> > block job.  I guess it could work, but it seems a little unnatural and
> > maybe there will be other features

[Qemu-devel] [PATCH 3/3] block: remove legacy I/O throttling

2017-08-01 Thread Manos Pitsidianakis
This commit removes all I/O throttling from block/block-backend.c. In
order to support the existing interface, it is changed to use the
block/throttle.c filter driver.

The throttle filter node that is created by the legacy interface is
stored in a 'throttle_node' field in the BlockBackendPublic of the
device. The legacy throttle node is managed by the legacy interface
completely. More advanced configurations with the filter drive are
possible using the QMP API, but these will be ignored by the legacy
interface.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block.c |   8 +++
 block/block-backend.c   | 149 +---
 block/qapi.c|  14 ++--
 block/throttle.c|   8 +++
 blockdev.c  |  55 +++
 include/block/block_int.h   |  13 
 include/block/throttle-groups.h |   2 +
 include/sysemu/block-backend.h  |   8 +--
 tests/test-throttle.c   |  15 ++--
 9 files changed, 186 insertions(+), 86 deletions(-)

diff --git a/block.c b/block.c
index 9ebdba28b0..c6aad25286 100644
--- a/block.c
+++ b/block.c
@@ -1975,6 +1975,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState 
*child_bs,
 child = g_new(BdrvChild, 1);
 *child = (BdrvChild) {
 .bs = NULL,
+.parent_bs  = NULL,
 .name   = g_strdup(child_name),
 .role   = child_role,
 .perm   = perm,
@@ -2009,6 +2010,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
 if (child == NULL) {
 return NULL;
 }
+child->parent_bs = parent_bs;
 
 QLIST_INSERT_HEAD(_bs->children, child, next);
 return child;
@@ -3729,6 +3731,12 @@ const char *bdrv_get_parent_name(const BlockDriverState 
*bs)
 return name;
 }
 }
+if (c->parent_bs && c->parent_bs->implicit) {
+name = bdrv_get_parent_name(c->parent_bs);
+if (name && *name) {
+return name;
+}
+}
 }
 
 return NULL;
diff --git a/block/block-backend.c b/block/block-backend.c
index df0200fc49..45f45efee9 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -15,6 +15,7 @@
 #include "block/block_int.h"
 #include "block/blockjob.h"
 #include "block/throttle-groups.h"
+#include "qemu/throttle-options.h"
 #include "sysemu/blockdev.h"
 #include "sysemu/sysemu.h"
 #include "qapi-event.h"
@@ -282,8 +283,8 @@ static void blk_delete(BlockBackend *blk)
 assert(!blk->refcnt);
 assert(!blk->name);
 assert(!blk->dev);
-if (blk->public.throttle_group_member.throttle_state) {
-blk_io_limits_disable(blk);
+if (blk->public.throttle_node) {
+blk_io_limits_disable(blk, _abort);
 }
 if (blk->root) {
 blk_remove_bs(blk);
@@ -593,13 +594,7 @@ BlockBackend *blk_by_public(BlockBackendPublic *public)
  */
 void blk_remove_bs(BlockBackend *blk)
 {
-ThrottleTimers *tt;
-
 notifier_list_notify(>remove_bs_notifiers, blk);
-if (blk->public.throttle_group_member.throttle_state) {
-tt = >public.throttle_group_member.throttle_timers;
-throttle_timers_detach_aio_context(tt);
-}
 
 blk_update_root_state(blk);
 
@@ -620,12 +615,6 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, 
Error **errp)
 bdrv_ref(bs);
 
 notifier_list_notify(>insert_bs_notifiers, blk);
-if (blk->public.throttle_group_member.throttle_state) {
-throttle_timers_attach_aio_context(
->public.throttle_group_member.throttle_timers,
-bdrv_get_aio_context(bs));
-}
-
 return 0;
 }
 
@@ -983,13 +972,6 @@ int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t 
offset,
 }
 
 bdrv_inc_in_flight(bs);
-
-/* throttling disk I/O */
-if (blk->public.throttle_group_member.throttle_state) {
-
throttle_group_co_io_limits_intercept(>public.throttle_group_member,
-bytes, false);
-}
-
 ret = bdrv_co_preadv(blk->root, offset, bytes, qiov, flags);
 bdrv_dec_in_flight(bs);
 return ret;
@@ -1010,11 +992,6 @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, 
int64_t offset,
 }
 
 bdrv_inc_in_flight(bs);
-/* throttling disk I/O */
-if (blk->public.throttle_group_member.throttle_state) {
-
throttle_group_co_io_limits_intercept(>public.throttle_group_member,
-bytes, true);
-}
 
 if (!blk->enable_write_cache) {
 flags |= BDRV_REQ_FUA;
@@ -1682,16 +1659,9 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB 
*acb)
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
 {
 BlockDriverState *bs = blk_bs(blk);
-ThrottleGroupMember *tgm = >public.throttle_group_mem

[Qemu-devel] [PATCH 0/3] block: remove legacy I/O throttling

2017-08-01 Thread Manos Pitsidianakis
This series depends on my other series 'add throttle block driver filter'
currently on v3, which as the name suggests adds a throttle filter driver.

Replacing the current I/O interface means the user will use the same options as
before and QEMU will create a hidden throttle filter node beneath the device's
BlockBackend. 

Manos Pitsidianakis (3):
  block: add options parameter to bdrv_new_open_driver()
  block: skip implicit nodes in snapshots, blockjobs
  block: remove legacy I/O throttling

 block.c |  41 ++-
 block/block-backend.c   | 149 +---
 block/commit.c  |   4 +-
 block/mirror.c  |   2 +-
 block/qapi.c|  14 ++--
 block/throttle.c|   8 +++
 block/vvfat.c   |   2 +-
 blockdev.c  |  67 ++
 include/block/block.h   |   2 +-
 include/block/block_int.h   |  15 
 include/block/throttle-groups.h |   2 +
 include/sysemu/block-backend.h  |   8 +--
 tests/test-throttle.c   |  15 ++--
 13 files changed, 235 insertions(+), 94 deletions(-)

-- 
2.11.0




[Qemu-devel] [PATCH 1/3] block: add options parameter to bdrv_new_open_driver()

2017-08-01 Thread Manos Pitsidianakis
Allow passing a QDict *options parameter to bdrv_new_open_driver() so
that it can be used if a driver needs it upon creation. The previous
behaviour (empty bs->options and bs->explicit_options) remains when
options is NULL.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block.c   | 16 +---
 block/commit.c|  4 ++--
 block/mirror.c|  2 +-
 block/vvfat.c |  2 +-
 include/block/block.h |  2 +-
 5 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/block.c b/block.c
index 37e72b7a96..886a457ab0 100644
--- a/block.c
+++ b/block.c
@@ -1149,16 +1149,26 @@ free_and_fail:
 return ret;
 }
 
+/*
+ * If options is not NULL it is cloned (which adds another reference to the
+ * option entries). If the call to bdrv_new_open_driver() is successful, the
+ * caller should unref options to pass ownership.
+ * */
 BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
-   int flags, Error **errp)
+   int flags, QDict *options, Error **errp)
 {
 BlockDriverState *bs;
 int ret;
 
 bs = bdrv_new();
 bs->open_flags = flags;
-bs->explicit_options = qdict_new();
-bs->options = qdict_new();
+if (options) {
+bs->explicit_options = qdict_clone_shallow(options);
+bs->options = qdict_clone_shallow(options);
+} else {
+bs->explicit_options = qdict_new();
+bs->options = qdict_new();
+}
 bs->opaque = NULL;
 
 update_options_from_flags(bs->options, flags);
diff --git a/block/commit.c b/block/commit.c
index c7857c3321..539e23c3f8 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -342,7 +342,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
 /* Insert commit_top block node above top, so we can block consistent read
  * on the backing chain below it */
 commit_top_bs = bdrv_new_open_driver(_commit_top, filter_node_name, 0,
- errp);
+ NULL, errp);
 if (commit_top_bs == NULL) {
 goto fail;
 }
@@ -494,7 +494,7 @@ int bdrv_commit(BlockDriverState *bs)
 backing_file_bs = backing_bs(bs);
 
 commit_top_bs = bdrv_new_open_driver(_commit_top, NULL, BDRV_O_RDWR,
- _err);
+ NULL, _err);
 if (commit_top_bs == NULL) {
 error_report_err(local_err);
 goto ro_cleanup;
diff --git a/block/mirror.c b/block/mirror.c
index c9a6a3ca86..e1a160e6ea 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -1164,7 +1164,7 @@ static void mirror_start_job(const char *job_id, 
BlockDriverState *bs,
  * reads on the top, while disabling it in the intermediate nodes, and make
  * the backing chain writable. */
 mirror_top_bs = bdrv_new_open_driver(_mirror_top, filter_node_name,
- BDRV_O_RDWR, errp);
+ BDRV_O_RDWR, NULL, errp);
 if (mirror_top_bs == NULL) {
 return;
 }
diff --git a/block/vvfat.c b/block/vvfat.c
index a9e207f7f0..6c59473baf 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -3194,7 +3194,7 @@ static int enable_write_target(BlockDriverState *bs, 
Error **errp)
 #endif
 
 backing = bdrv_new_open_driver(_write_target, NULL, 
BDRV_O_ALLOW_RDWR,
-   _abort);
+   NULL, _abort);
 *(void**) backing->opaque = s;
 
 bdrv_set_backing_hd(s->bs, backing, _abort);
diff --git a/include/block/block.h b/include/block/block.h
index 34770bb33a..020289a37d 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -263,7 +263,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict 
*parent_options,
 BlockDriverState *bdrv_open(const char *filename, const char *reference,
 QDict *options, int flags, Error **errp);
 BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
-   int flags, Error **errp);
+   int flags, QDict *options, Error 
**errp);
 BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
 BlockDriverState *bs,
 QDict *options, int flags);
-- 
2.11.0




[Qemu-devel] [PATCH 2/3] block: skip implicit nodes in snapshots, blockjobs

2017-08-01 Thread Manos Pitsidianakis
Implicit filter nodes added at the top of nodes can interfere with block
jobs. This is not a problem when they are added by other jobs since
adding another job will issue a QERR_DEVICE_IN_USE, but it can happen in
the next commit which introduces an implicitly created throttle filter
node below BlockBackend, which we want to be skipped during automatic
operations on the graph since the user does not necessarily know about
their existence.

Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block.c   | 17 +
 blockdev.c| 12 
 include/block/block_int.h |  2 ++
 3 files changed, 31 insertions(+)

diff --git a/block.c b/block.c
index 886a457ab0..9ebdba28b0 100644
--- a/block.c
+++ b/block.c
@@ -4947,3 +4947,20 @@ bool bdrv_can_store_new_dirty_bitmap(BlockDriverState 
*bs, const char *name,
 
 return drv->bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp);
 }
+
+/* Get first non-implicit node down a bs chain. */
+BlockDriverState *bdrv_get_first_non_implicit(BlockDriverState *bs)
+{
+if (!bs) {
+return NULL;
+}
+
+if (!bs->implicit) {
+return bs;
+}
+
+/* at this point bs is implicit and must have a child */
+assert(bs->file);
+
+return bdrv_get_first_non_implicit(bs->file->bs);
+}
diff --git a/blockdev.c b/blockdev.c
index 23475abb72..d903a23786 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1664,6 +1664,9 @@ static void external_snapshot_prepare(BlkActionState 
*common,
 return;
 }
 
+/* Skip implicit filter nodes */
+state->old_bs = bdrv_get_first_non_implicit(state->old_bs);
+
 /* Acquire AioContext now so any threads operating on old_bs stop */
 state->aio_context = bdrv_get_aio_context(state->old_bs);
 aio_context_acquire(state->aio_context);
@@ -3095,6 +3098,9 @@ void qmp_block_commit(bool has_job_id, const char 
*job_id, const char *device,
 return;
 }
 
+/* Skip implicit filter nodes */
+bs = bdrv_get_first_non_implicit(bs);
+
 aio_context = bdrv_get_aio_context(bs);
 aio_context_acquire(aio_context);
 
@@ -3209,6 +3215,9 @@ static BlockJob *do_drive_backup(DriveBackup *backup, 
BlockJobTxn *txn,
 return NULL;
 }
 
+/* Skip implicit filter nodes */
+bs = bdrv_get_first_non_implicit(bs);
+
 aio_context = bdrv_get_aio_context(bs);
 aio_context_acquire(aio_context);
 
@@ -3484,6 +3493,9 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
 return;
 }
 
+/* Skip implicit filter nodes */
+bs = bdrv_get_first_non_implicit(bs);
+
 aio_context = bdrv_get_aio_context(bs);
 aio_context_acquire(aio_context);
 
diff --git a/include/block/block_int.h b/include/block/block_int.h
index d4f4ea7584..9eeae490f0 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -981,4 +981,6 @@ void bdrv_dec_in_flight(BlockDriverState *bs);
 
 void blockdev_close_all_bdrv_states(void);
 
+BlockDriverState *bdrv_get_first_non_implicit(BlockDriverState *bs);
+
 #endif /* BLOCK_INT_H */
-- 
2.11.0




Re: [Qemu-devel] [RFC] block-insert-node and block-job-delete

2017-07-31 Thread Manos Pitsidianakis

On Fri, Jul 28, 2017 at 02:08:43PM +0200, Kevin Wolf wrote:

Am 27.07.2017 um 12:07 hat Stefan Hajnoczi geschrieben:

On Wed, Jul 26, 2017 at 09:23:20PM +0300, Manos Pitsidianakis wrote:
> On Wed, Jul 26, 2017 at 04:12:21PM +0100, Stefan Hajnoczi wrote:
> > On Wed, Jul 26, 2017 at 05:19:24PM +0300, Manos Pitsidianakis wrote:
> > > This proposal follows a discussion we had with Kevin and Stefan on filter
> > > node management.
> > >
> > > With block filter drivers arises a need to configure filter nodes on 
runtime
> > > with QMP on live graphs. A problem with doing live graph modifications is
> > > that some block jobs modify the graph when they are done and don't operate
> > > under any synchronisation, resulting in a race condition if we try to 
insert
> > > a filter node in the place of an existing edge.
> >
> > But maybe you are thinking about higher level race conditions between
> > QMP commands.  Can you give an example of the race?
>
> Exactly, synchronisation between the QMP/user actions. Here's an example,
> correct me if I'm wrong:
>
> User issues a block-commit to this tree to commit A onto B:
>BB -> A -> B
>
> This inserts the dummy mirror node at the top since this is a mirror job
> (active commit)
>BB -> dummy -> A -> B
>
> User wants to add a filter node F below the BB. First we create the node:
>BB -> dummy -> A -> B
>   F /
>
> Commit finishes before we do block-insert-node, dummy and A is removed from
> the BB's chain, mirror_exit calls bdrv_replace_node()
>
>BB > B
>F -> /
>
> Now inserting F under BB will error since dummy does not exist any more.

I see the diagrams but the flow isn't clear without the user's QMP
commands.

F is created using blockdev-add?  What are the parameters and how does
it know about dummy?  I think this is an interesting question in itself
because dummy is a transient internal node that QMP users don't
necessarily know about.


We can expect that users of block-insert-node also know about block job
filter nodes, simply because the former is newer than the latter.

(I also don't like the name "dummy", this makes it sound like it's not
really a proper node. In reality, there is little reason to treat it
specially.)


What is the full block-insert-node command?

> The proposal doesn't guard against the following:
> User issues a block-commit to this tree to commit B onto C:
>BB -> A -> B -> C
>
> The dummy node (commit's top bs is A):
>BB -> A -> dummy -> B -> C
>
> blockdev-add of a filter we wish to eventually be between A and C:
>BB -> A -> dummy -> B -> C
> F/
>
> if commit finishes before we issue block-insert-node (commit_complete()
> calls bdrv_set_backing_hd() which only touches A)
>BB -> A --> C
>   F -> dummy -> B /
>resulting in error when issuing block-insert-node,
>
> else if we set the job to manual-delete and insert F:
>BB -> A -> F -> dummy -> B -> C
> deleting the job will result in F being lost since the job's top bs wasn't
> updated.

manual-delete is a solution for block jobs.  The write threshold
feature is a plain QMP command that in the future will create a
transient internal node (before write notifier).


Yes, that becomes a legacy QMP command then. The new way is blockdev-add
and block-insert-node for write threshold, too.

Apart from that, a write threshold node never disappears by itself, it
is only inserted or removed in the context of a QMP command. That makes
it a lot less dangerous than automatic block completion.


I'm not sure it makes sense to turn the write threshold feature into a
block job.  I guess it could work, but it seems a little unnatural and
maybe there will be other features that use transient internal nodes.


Yeah, no reason to do so. Just a manually created filter node.



Can you explain what you have in mind? The current workflow is using 
block-set-write-threshold on the targetted bs. If we want write 
threshold to be on node level we would want a new filter driver so that 
it can take options special to write-threshold. Unless we make the 
notify filter be a write threshold by default, and when using it 
internally by the backup job, disable the threshold and add our backup 
notifier to the node's list. Of course the current write threshold code 
could be refactored into a new driver so that it doesn't have to rely on 
notifiers.


The way I've currently done the conversion is to add an implicit filter 
when enabling the threshold, just like in backup jobs.


signature.asc
Description: PGP signature


[Qemu-devel] [PATCH v3 1/7] block: move ThrottleGroup membership to ThrottleGroupMember

2017-07-31 Thread Manos Pitsidianakis
This commit eliminates the 1:1 relationship between BlockBackend and
throttle group state.  Users will be able to create multiple throttle
nodes, each with its own throttle group state, in the future.  The
throttle group state cannot be per-BlockBackend anymore, it must be
per-throttle node. This is done by gathering ThrottleGroup membership
details from BlockBackendPublic into ThrottleGroupMember and refactoring
existing code to use the structure.

Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com>
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 block/block-backend.c   |  66 +
 block/qapi.c|   8 +-
 block/throttle-groups.c | 288 
 blockdev.c  |   4 +-
 include/block/throttle-groups.h |  39 +-
 include/sysemu/block-backend.h  |  20 +--
 tests/test-throttle.c   |  53 
 7 files changed, 252 insertions(+), 226 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 968438c149..bde6948d0e 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -215,9 +215,9 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
 blk->shared_perm = shared_perm;
 blk_set_enable_write_cache(blk, true);
 
-qemu_co_mutex_init(>public.throttled_reqs_lock);
-qemu_co_queue_init(>public.throttled_reqs[0]);
-qemu_co_queue_init(>public.throttled_reqs[1]);
+qemu_co_mutex_init(>public.throttle_group_member.throttled_reqs_lock);
+qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[0]);
+qemu_co_queue_init(>public.throttle_group_member.throttled_reqs[1]);
 block_acct_init(>stats);
 
 notifier_list_init(>remove_bs_notifiers);
@@ -285,7 +285,7 @@ static void blk_delete(BlockBackend *blk)
 assert(!blk->refcnt);
 assert(!blk->name);
 assert(!blk->dev);
-if (blk->public.throttle_state) {
+if (blk->public.throttle_group_member.throttle_state) {
 blk_io_limits_disable(blk);
 }
 if (blk->root) {
@@ -596,9 +596,12 @@ BlockBackend *blk_by_public(BlockBackendPublic *public)
  */
 void blk_remove_bs(BlockBackend *blk)
 {
+ThrottleTimers *tt;
+
 notifier_list_notify(>remove_bs_notifiers, blk);
-if (blk->public.throttle_state) {
-throttle_timers_detach_aio_context(>public.throttle_timers);
+if (blk->public.throttle_group_member.throttle_state) {
+tt = >public.throttle_group_member.throttle_timers;
+throttle_timers_detach_aio_context(tt);
 }
 
 blk_update_root_state(blk);
@@ -620,9 +623,10 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, 
Error **errp)
 bdrv_ref(bs);
 
 notifier_list_notify(>insert_bs_notifiers, blk);
-if (blk->public.throttle_state) {
+if (blk->public.throttle_group_member.throttle_state) {
 throttle_timers_attach_aio_context(
->public.throttle_timers, bdrv_get_aio_context(bs));
+>public.throttle_group_member.throttle_timers,
+bdrv_get_aio_context(bs));
 }
 
 return 0;
@@ -984,8 +988,9 @@ int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t 
offset,
 bdrv_inc_in_flight(bs);
 
 /* throttling disk I/O */
-if (blk->public.throttle_state) {
-throttle_group_co_io_limits_intercept(blk, bytes, false);
+if (blk->public.throttle_group_member.throttle_state) {
+
throttle_group_co_io_limits_intercept(>public.throttle_group_member,
+bytes, false);
 }
 
 ret = bdrv_co_preadv(blk->root, offset, bytes, qiov, flags);
@@ -1008,10 +1013,10 @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, 
int64_t offset,
 }
 
 bdrv_inc_in_flight(bs);
-
 /* throttling disk I/O */
-if (blk->public.throttle_state) {
-throttle_group_co_io_limits_intercept(blk, bytes, true);
+if (blk->public.throttle_group_member.throttle_state) {
+
throttle_group_co_io_limits_intercept(>public.throttle_group_member,
+bytes, true);
 }
 
 if (!blk->enable_write_cache) {
@@ -1680,15 +1685,17 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB 
*acb)
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
 {
 BlockDriverState *bs = blk_bs(blk);
+ThrottleTimers *tt;
 
 if (bs) {
-if (blk->public.throttle_state) {
-throttle_timers_detach_aio_context(>public.throttle_timers);
+if (blk->public.throttle_group_member.throttle_state) {
+tt = >public.throttle_group_member.throttle_timers;
+throttle_timers_detach_aio_context(tt);
 }
 bdrv_set_aio_context(bs, new_context);
-if (blk->public.throttle_state) {
-throttle_timers_attach_aio_context(>public.throttle_timers,
-   new_context);

[Qemu-devel] [PATCH v3 7/7] block: add throttle block filter driver interface tests

2017-07-31 Thread Manos Pitsidianakis
Signed-off-by: Manos Pitsidianakis <el13...@mail.ntua.gr>
---
 tests/qemu-iotests/184 | 237 +
 tests/qemu-iotests/184.out | 319 +
 tests/qemu-iotests/group   |   1 +
 3 files changed, 557 insertions(+)
 create mode 100755 tests/qemu-iotests/184
 create mode 100644 tests/qemu-iotests/184.out

diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
new file mode 100755
index 00..c3f3f2b7ca
--- /dev/null
+++ b/tests/qemu-iotests/184
@@ -0,0 +1,237 @@
+#!/bin/bash
+#
+# Test I/O throttle block filter driver interface
+#
+# Copyright (C) 2017 Manos Pitsidianakis
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner="Manos Pitsidianakis"
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1   # failure is the default!
+
+_cleanup()
+{
+_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt raw
+_supported_proto file
+_supported_os Linux
+
+function do_run_qemu()
+{
+echo Testing: "$@" | _filter_imgfmt
+$QEMU -nographic -qmp-pretty stdio -serial none "$@"
+echo
+}
+
+function run_qemu()
+{
+do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
+  | _filter_qemu_io | _filter_generated_node_ids
+}
+
+_make_test_img 64M
+test_throttle=$($QEMU_IMG --help|grep throttle)
+[ "$test_throttle" = "" ] && _supported_fmt throttle
+
+echo
+echo "== checking interface =="
+
+run_qemu <

[Qemu-devel] [PATCH v3 4/7] block: convert ThrottleGroup to object with QOM

2017-07-31 Thread Manos Pitsidianakis
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 throttle-group,id=foo,x-iops-total=100,x-..
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": "throttle-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 <el13...@mail.ntua.gr>
---
Notes:
Note: I tested Markus Armbruster's patch in 
<87wp7fghi9@dusky.pond.sub.org>
on master and I can use this syntax successfuly:
-object '{ "qom-type" : "throttle-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 | 402 
 include/block/throttle-groups.h |   3 +
 include/qemu/throttle-options.h |  59 --
 include/qemu/throttle.h |   3 +
 qapi/block-core.json|  48 +
 tests/test-throttle.c   |   1 +
 util/throttle.c | 151 +++
 7 files changed, 617 insertions(+), 50 deletions(-)

diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index f711a3dc62..b9c5036e44 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(_groups_lock);
 
-/* Look for an existing group with that name */
-QTAILQ_FOREACH(iter

<    1   2   3   4   5   6   7   >