@@ -2186,6 +2186,23 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
aio_context_release(aio_context);
}
+static void do_child_add(const char *device, QDict *opts, Error **errp)
+{
+ BlockDriverState *bs;
+ Error *local_err = NULL;
+
+ bs = bdrv_lookup_bs(device, device, &local_err);
+ if (!bs) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ bdrv_add_child(bs, opts, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ }
+}
+
void qmp_block_resize(bool has_device, const char *device,
bool has_node_name, const char *node_name,
int64_t size, Error **errp)
@@ -3096,6 +3113,68 @@ fail:
qmp_output_visitor_cleanup(ov);
}
+void qmp_child_add(const char *device, BlockdevOptionsChild *options,
+ Error **errp)
+{
+ QmpOutputVisitor *ov = qmp_output_visitor_new();
+ QObject *obj;
+ QDict *qdict;
+ Error *local_err = NULL;
+
+ if (options->child->has_id || options->child->has_discard ||
+ options->child->has_cache || options->child->has_aio ||
+ options->child->has_rerror || options->child->has_werror ||
+ options->child->has_read_only || options->child->has_detect_zeroes) {
+ error_setg(errp, "id, discard, cache, aio, rerror, werror, readonly"
+ " and detect_zeroes cann't be used for child-add");
+ goto fail;
+ }
+
+ visit_type_BlockdevOptionsChild(qmp_output_get_visitor(ov),
+ &options, NULL, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto fail;
+ }
+
+ obj = qmp_output_get_qobject(ov);
+ qdict = qobject_to_qdict(obj);
+
+ qdict_flatten(qdict);
+
+ do_child_add(device, qdict, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto fail;
+ }
+
+fail:
+ qmp_output_visitor_cleanup(ov);
+}
+
+void qmp_child_del(const char *parent, const char *child, Error **errp)
+{
+ BlockDriverState *parent_bs, *child_bs;
+ Error *local_err = NULL;
+
+ parent_bs = bdrv_lookup_bs(parent, parent, &local_err);
+ if (!parent_bs) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ child_bs = bdrv_lookup_bs(child, child, &local_err);
+ if (!child_bs) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ bdrv_del_child(parent_bs, child_bs, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ }
+}
+
BlockJobInfoList *qmp_query_block_jobs(Error **errp)
{
BlockJobInfoList *head = NULL, **p_next = &head;
@@ -2122,3 +2122,35 @@
##
{ 'command': 'block-set-write-threshold',
'data': { 'node-name': 'str', 'write-threshold': 'uint64' } }
+
+{
+ 'struct': 'BlockdevOptionsChild',
+ 'data': { 'child': 'BlockdevOptions'} }
+
+##
+# @child-add
+#
+# Add a new child to quorum. This is useful to fix a broken quorum child.
+#
+# @device: graph node name or id which the child will be added to.
+#
+# @options: the options to create child BDS.
+#
+# Since: 2.5
+##
+{ 'command': 'child-add',
+ 'data' : { 'device': 'str', 'options': 'BlockdevOptionsChild' } }
+
+##
+# @child-del
+#
+# Remove a child from quorum. This is useful to fix a broken quorum child.
+#
+# @parent: graph node name or id from which the child will removed.
+#
+# @child: graph node name that will be removed.
+#
+# Since: 2.5
+##
+{ 'command': 'child-del',
+ 'data' : { 'parent': 'str', 'child': 'str' } }
@@ -3872,6 +3872,73 @@ Example (2):
EQMP
{
+ .name = "child-add",
+ .args_type = "device:B,options:q",
+ .mhandler.cmd_new = qmp_marshal_input_child_add,
+ },
+
+SQMP
+child-add
+------------
+
+Add a child to a quorum node.
+
+This command is still a work in progress. It doesn't support all
+block drivers. Stay away from it unless you want it to help with
+its development.
+
+Arguments:
+
+- "device": the quorum's id or node name
+- "options": the new child options
+
+Example:
+
+-> { "execute": "child-add",
+ "arguments": {
+ "device": "disk1",
+ "options" : {
+ "child": {
+ "driver": "qcow2",
+ "file": {
+ "driver": "file",
+ "filename": "test.qcow2"
+ },
+ "node-name": "new_node"
+ }
+ }
+ }
+<- { "return": {} }
+
+EQMP
+
+ {
+ .name = "child-del",
+ .args_type = "parent:B,child:B",
+ .mhandler.cmd_new = qmp_marshal_input_child_del,
+ },
+
+SQMP
+child-del
+------------
+
+Delete a child from a quorum node. It can be used to remove a broken
+quorum child.
+
+Arguments:
+
+- "parent": the quorum's id or node name
+- "child": the child node-name which will be removed
+
+Example:
+
+-> { "execute": "child-del",
+ "arguments": { "parent": "disk1", "child": "new_node" } }
+<- { "return": {} }
+
+EQMP
+
+ {
.name = "query-named-block-nodes",
.args_type = "",
.mhandler.cmd_new = qmp_marshal_input_query_named_block_nodes,