diff mbox

[for-2.5,v2,5/6] qmp: add monitor command to add/remove a child

Message ID 1439279489-13338-6-git-send-email-wency@cn.fujitsu.com
State New
Headers show

Commit Message

Wen Congyang Aug. 11, 2015, 7:51 a.m. UTC
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
Signed-off-by: Gonglei <arei.gonglei@huawei.com>
---
 blockdev.c           | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 qapi/block-core.json | 40 ++++++++++++++++++++++++++
 qmp-commands.hx      | 67 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 186 insertions(+)

Comments

Eric Blake Aug. 31, 2015, 7:04 p.m. UTC | #1
On 08/11/2015 01:51 AM, Wen Congyang wrote:
> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
> Signed-off-by: Gonglei <arei.gonglei@huawei.com>
> ---
>  blockdev.c           | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  qapi/block-core.json | 40 ++++++++++++++++++++++++++
>  qmp-commands.hx      | 67 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 186 insertions(+)
> 

> +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");

s/cann't/can't/

If they can't be used, then why not write the qapi so that they can't
even be provided?  On the other hand, why can't they be used?  Can't you
specify some of these options separately for different quorum children
when first creating a quorum, in which case you'd want to be able to do
likewise when adding a new member to the quorum?

> +++ b/qapi/block-core.json
> @@ -2122,3 +2122,43 @@
>  ##
>  { 'command': 'block-set-write-threshold',
>    'data': { 'node-name': 'str', 'write-threshold': 'uint64' } }
> +
> +##
> +# @BlockdevOptionsChild
> +#
> +# Driver specific block device options for child block device.
> +#
> +# Since: 2.5
> +##
> +{ 'struct': 'BlockdevOptionsChild',
> +  'data': { 'child': 'BlockdevOptions' } }

Do you need this struct?  It causes extra nesting on the wire...

> +
> +##
> +# @child-add
> +#
> +# Add a new child to the parent BDS. Currently only the Quorum driver
> +# implements this feature. 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' } }

...Consider if you just did:

{ 'command': 'child-add',
  'data': { 'device', 'str', 'child': 'BlockdevOptions' } }

> 
> +
> +##
> +# @child-del
> +#
> +# Remove a child from the parent BDS. Currently only the Quorum driver
> +# implements this feature. This is useful to fix a broken quorum child.

Might also be worth mentioning that you can't remove a child if it would
bring the quorum below its threshold.

> +++ b/qmp-commands.hx

> +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.

Maybe we should name it 'x-child-add' for now, so that we aren't baking
ourselves into a corner.

> +
> +Arguments:
> +
> +- "device": the quorum's id or node name
> +- "options": the new child options
> +
> +Example:
> +
> +-> { "execute": "child-add",
> +    "arguments": {
> +        "device": "disk1",
> +        "options" : {
> +            "child": {

...the simper command idea above would reduce one layer of {} nesting here.
Wen Congyang Sept. 1, 2015, 12:55 a.m. UTC | #2
On 09/01/2015 03:04 AM, Eric Blake wrote:
> On 08/11/2015 01:51 AM, Wen Congyang wrote:
>> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
>> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
>> Signed-off-by: Gonglei <arei.gonglei@huawei.com>
>> ---
>>  blockdev.c           | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  qapi/block-core.json | 40 ++++++++++++++++++++++++++
>>  qmp-commands.hx      | 67 ++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 186 insertions(+)
>>
> 
>> +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");
> 
> s/cann't/can't/
> 
> If they can't be used, then why not write the qapi so that they can't
> even be provided?  On the other hand, why can't they be used?  Can't you
> specify some of these options separately for different quorum children
> when first creating a quorum, in which case you'd want to be able to do
> likewise when adding a new member to the quorum?

IIUC, it is just top BDS's option, and it is not be used by the hot-added
child. The hot-added child will use its parent flags.

> 
>> +++ b/qapi/block-core.json
>> @@ -2122,3 +2122,43 @@
>>  ##
>>  { 'command': 'block-set-write-threshold',
>>    'data': { 'node-name': 'str', 'write-threshold': 'uint64' } }
>> +
>> +##
>> +# @BlockdevOptionsChild
>> +#
>> +# Driver specific block device options for child block device.
>> +#
>> +# Since: 2.5
>> +##
>> +{ 'struct': 'BlockdevOptionsChild',
>> +  'data': { 'child': 'BlockdevOptions' } }
> 
> Do you need this struct?  It causes extra nesting on the wire...
> 
>> +
>> +##
>> +# @child-add
>> +#
>> +# Add a new child to the parent BDS. Currently only the Quorum driver
>> +# implements this feature. 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' } }
> 
> ...Consider if you just did:
> 
> { 'command': 'child-add',
>   'data': { 'device', 'str', 'child': 'BlockdevOptions' } }

OK, I will try it.

> 
>>
>> +
>> +##
>> +# @child-del
>> +#
>> +# Remove a child from the parent BDS. Currently only the Quorum driver
>> +# implements this feature. This is useful to fix a broken quorum child.
> 
> Might also be worth mentioning that you can't remove a child if it would
> bring the quorum below its threshold.
> 
>> +++ b/qmp-commands.hx
> 
>> +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.
> 
> Maybe we should name it 'x-child-add' for now, so that we aren't baking
> ourselves into a corner.

Do you mean the command name should be x-child-add? It is OK.

> 
>> +
>> +Arguments:
>> +
>> +- "device": the quorum's id or node name
>> +- "options": the new child options
>> +
>> +Example:
>> +
>> +-> { "execute": "child-add",
>> +    "arguments": {
>> +        "device": "disk1",
>> +        "options" : {
>> +            "child": {
> 
> ...the simper command idea above would reduce one layer of {} nesting here.
> 

Yes, I will try it.

Thanks
Wen Congyang
Wen Congyang Sept. 1, 2015, 5:51 a.m. UTC | #3
On 09/01/2015 03:04 AM, Eric Blake wrote:
> On 08/11/2015 01:51 AM, Wen Congyang wrote:
>> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
>> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
>> Signed-off-by: Gonglei <arei.gonglei@huawei.com>
>> ---
>>  blockdev.c           | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  qapi/block-core.json | 40 ++++++++++++++++++++++++++
>>  qmp-commands.hx      | 67 ++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 186 insertions(+)
>>
> 
>> +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");
> 
> s/cann't/can't/
> 
> If they can't be used, then why not write the qapi so that they can't
> even be provided?  On the other hand, why can't they be used?  Can't you
> specify some of these options separately for different quorum children
> when first creating a quorum, in which case you'd want to be able to do
> likewise when adding a new member to the quorum?
> 
>> +++ b/qapi/block-core.json
>> @@ -2122,3 +2122,43 @@
>>  ##
>>  { 'command': 'block-set-write-threshold',
>>    'data': { 'node-name': 'str', 'write-threshold': 'uint64' } }
>> +
>> +##
>> +# @BlockdevOptionsChild
>> +#
>> +# Driver specific block device options for child block device.
>> +#
>> +# Since: 2.5
>> +##
>> +{ 'struct': 'BlockdevOptionsChild',
>> +  'data': { 'child': 'BlockdevOptions' } }
> 
> Do you need this struct?  It causes extra nesting on the wire...
> 
>> +
>> +##
>> +# @child-add
>> +#
>> +# Add a new child to the parent BDS. Currently only the Quorum driver
>> +# implements this feature. 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' } }
> 
> ...Consider if you just did:
> 
> { 'command': 'child-add',
>   'data': { 'device', 'str', 'child': 'BlockdevOptions' } }
> 
>>
>> +
>> +##
>> +# @child-del
>> +#
>> +# Remove a child from the parent BDS. Currently only the Quorum driver
>> +# implements this feature. This is useful to fix a broken quorum child.
> 
> Might also be worth mentioning that you can't remove a child if it would
> bring the quorum below its threshold.
> 
>> +++ b/qmp-commands.hx
> 
>> +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.
> 
> Maybe we should name it 'x-child-add' for now, so that we aren't baking
> ourselves into a corner.
> 
>> +
>> +Arguments:
>> +
>> +- "device": the quorum's id or node name
>> +- "options": the new child options
>> +
>> +Example:
>> +
>> +-> { "execute": "child-add",
>> +    "arguments": {
>> +        "device": "disk1",
>> +        "options" : {
>> +            "child": {
> 
> ...the simper command idea above would reduce one layer of {} nesting here.
> 

When we open a child BDS, the options for child BDS must have the same prefix, such as
file.xxx, x-image.xxx, ... For hot-added child BDS, the prefix is "child“. If we don't
use "options" here, the prefix "child" will be eaten in qmp_marshal_input_x_child_add().
I am investigating how to solve it. Any suggestion is welcome.

Thanks
Wen Congyang
Eric Blake Sept. 1, 2015, 3:34 p.m. UTC | #4
On 08/31/2015 06:55 PM, Wen Congyang wrote:

>>> +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.
>>
>> Maybe we should name it 'x-child-add' for now, so that we aren't baking
>> ourselves into a corner.
> 
> Do you mean the command name should be x-child-add? It is OK.

Use of the 'x-' prefix means a command is experimental and may change or
be withdrawn.  It gives us a way to test if an interface is useful
without committing to that interface long term.  We've still got time
before 2.5 to get blockdev-add working everywhere, in which case I think
we are better off using blockdev-add to create a new unattached BDS and
then have this command pass the node name to be made the new child,
rather than all the options for opening the child from scratch.
Wen Congyang Sept. 2, 2015, 1:25 a.m. UTC | #5
On 09/01/2015 11:34 PM, Eric Blake wrote:
> On 08/31/2015 06:55 PM, Wen Congyang wrote:
> 
>>>> +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.
>>>
>>> Maybe we should name it 'x-child-add' for now, so that we aren't baking
>>> ourselves into a corner.
>>
>> Do you mean the command name should be x-child-add? It is OK.
> 
> Use of the 'x-' prefix means a command is experimental and may change or
> be withdrawn.  It gives us a way to test if an interface is useful
> without committing to that interface long term.  We've still got time
> before 2.5 to get blockdev-add working everywhere, in which case I think
> we are better off using blockdev-add to create a new unattached BDS and
> then have this command pass the node name to be made the new child,
> rather than all the options for opening the child from scratch.
> 

Good idea. The unattached BDS created by the command blockdev-add always
have BB. So it may be used by the device created by the command device_add
later. So I think we should have an API to check it. What about the following
patches?
http://lists.nongnu.org/archive/html/qemu-devel/2015-07/msg01591.html
http://lists.nongnu.org/archive/html/qemu-devel/2015-07/msg01590.html

Thanks
Wen Congyang
Eric Blake Sept. 2, 2015, 3 p.m. UTC | #6
On 09/01/2015 07:25 PM, Wen Congyang wrote:
> On 09/01/2015 11:34 PM, Eric Blake wrote:
>> On 08/31/2015 06:55 PM, Wen Congyang wrote:
>>
>>>>> +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.
>>>>
>>>> Maybe we should name it 'x-child-add' for now, so that we aren't baking
>>>> ourselves into a corner.
>>>
>>> Do you mean the command name should be x-child-add? It is OK.
>>
>> Use of the 'x-' prefix means a command is experimental and may change or
>> be withdrawn.  It gives us a way to test if an interface is useful
>> without committing to that interface long term.  We've still got time
>> before 2.5 to get blockdev-add working everywhere, in which case I think
>> we are better off using blockdev-add to create a new unattached BDS and
>> then have this command pass the node name to be made the new child,
>> rather than all the options for opening the child from scratch.
>>
> 
> Good idea. The unattached BDS created by the command blockdev-add always
> have BB. So it may be used by the device created by the command device_add
> later.

We recently discussed (although the current documentation of
BlockdevOptionsBase sounds like it hasn't been merged yet) the idea of
enhancing blockdev-add to control whether a BB is created alongside a BDS.

Remember, blockdev-add can be used to create a chain.  When originally
implemented, we documented that 'id' must be present on the top of the
chain, and absent everywhere else, and that 'node-name' was optional
everywhere.  The 'id' became associated with the BB at the top level,
and the optional node-names allow you to then manipulate other BDS.  But
the proposal at hand is that we would allow 'id' to be optional at the
top level (at which point 'node-name' is required, because we have to
have SOME way to refer to the BDS); and when that happens, we end up
creating a BDS that is not associated with any BB yet.  Similarly, it is
possible to create a BB that does not yet have a BDS yet (think an empty
cdrom drive); so it then becomes possible to associate a BDS to a BB as
a separate step.

[/me goes searching]
Ah - we are waiting for Max's patches to land:
https://lists.gnu.org/archive/html/qemu-devel/2015-07/msg04201.html
in particular patch 02/38:
https://lists.gnu.org/archive/html/qemu-devel/2015-07/msg04204.html

Once we have that, then we can indeed create a BDS without a BB, and it
is then that you can plug your unconnected BDS into a quorum.  So I'd
recommend helping review Max's series, and base your actions on top of
his (I really do think it is a better approach to separate BDS creation
from chain manipulation, and your add/remove a child is about chain
manipulation and does not need to be creating BDS).

> So I think we should have an API to check it. What about the following
> patches?
> http://lists.nongnu.org/archive/html/qemu-devel/2015-07/msg01591.html
> http://lists.nongnu.org/archive/html/qemu-devel/2015-07/msg01590.html

I haven't looked at them yet, but really like Max's approach for
separating BDS from BB by treating BB without BDS as an empty media
case, and BDS without a BB as something that can then be manipulated to
be associated with another BDS or BB.
Wen Congyang Sept. 7, 2015, 3:55 a.m. UTC | #7
On 09/02/2015 11:00 PM, Eric Blake wrote:
> On 09/01/2015 07:25 PM, Wen Congyang wrote:
>> On 09/01/2015 11:34 PM, Eric Blake wrote:
>>> On 08/31/2015 06:55 PM, Wen Congyang wrote:
>>>
>>>>>> +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.
>>>>>
>>>>> Maybe we should name it 'x-child-add' for now, so that we aren't baking
>>>>> ourselves into a corner.
>>>>
>>>> Do you mean the command name should be x-child-add? It is OK.
>>>
>>> Use of the 'x-' prefix means a command is experimental and may change or
>>> be withdrawn.  It gives us a way to test if an interface is useful
>>> without committing to that interface long term.  We've still got time
>>> before 2.5 to get blockdev-add working everywhere, in which case I think
>>> we are better off using blockdev-add to create a new unattached BDS and
>>> then have this command pass the node name to be made the new child,
>>> rather than all the options for opening the child from scratch.
>>>
>>
>> Good idea. The unattached BDS created by the command blockdev-add always
>> have BB. So it may be used by the device created by the command device_add
>> later.
> 
> We recently discussed (although the current documentation of
> BlockdevOptionsBase sounds like it hasn't been merged yet) the idea of
> enhancing blockdev-add to control whether a BB is created alongside a BDS.
> 
> Remember, blockdev-add can be used to create a chain.  When originally
> implemented, we documented that 'id' must be present on the top of the
> chain, and absent everywhere else, and that 'node-name' was optional
> everywhere.  The 'id' became associated with the BB at the top level,
> and the optional node-names allow you to then manipulate other BDS.  But
> the proposal at hand is that we would allow 'id' to be optional at the
> top level (at which point 'node-name' is required, because we have to
> have SOME way to refer to the BDS); and when that happens, we end up
> creating a BDS that is not associated with any BB yet.  Similarly, it is
> possible to create a BB that does not yet have a BDS yet (think an empty
> cdrom drive); so it then becomes possible to associate a BDS to a BB as
> a separate step.
> 
> [/me goes searching]
> Ah - we are waiting for Max's patches to land:
> https://lists.gnu.org/archive/html/qemu-devel/2015-07/msg04201.html
> in particular patch 02/38:
> https://lists.gnu.org/archive/html/qemu-devel/2015-07/msg04204.html
> 
> Once we have that, then we can indeed create a BDS without a BB, and it
> is then that you can plug your unconnected BDS into a quorum.  So I'd
> recommend helping review Max's series, and base your actions on top of
> his (I really do think it is a better approach to separate BDS creation
> from chain manipulation, and your add/remove a child is about chain
> manipulation and does not need to be creating BDS).
> 
>> So I think we should have an API to check it. What about the following
>> patches?
>> http://lists.nongnu.org/archive/html/qemu-devel/2015-07/msg01591.html
>> http://lists.nongnu.org/archive/html/qemu-devel/2015-07/msg01590.html
> 
> I haven't looked at them yet, but really like Max's approach for
> separating BDS from BB by treating BB without BDS as an empty media
> case, and BDS without a BB as something that can then be manipulated to
> be associated with another BDS or BB.

Do you mean we can create a top BDS without BB by the command line -drive
in the future?

Thanks
Wen Congyang
Eric Blake Sept. 8, 2015, 3:53 p.m. UTC | #8
On 09/06/2015 09:55 PM, Wen Congyang wrote:
>> I haven't looked at them yet, but really like Max's approach for
>> separating BDS from BB by treating BB without BDS as an empty media
>> case, and BDS without a BB as something that can then be manipulated to
>> be associated with another BDS or BB.
> 
> Do you mean we can create a top BDS without BB by the command line -drive
> in the future?

Not quite. -drive means create a BB. But it should be possible to create
a BDS without a BB from the command line, to match what blockdev-add can
do in QMP.
diff mbox

Patch

diff --git a/blockdev.c b/blockdev.c
index 62a4586..df40e92 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -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;
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 3ed8114..50292b9 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2122,3 +2122,43 @@ 
 ##
 { 'command': 'block-set-write-threshold',
   'data': { 'node-name': 'str', 'write-threshold': 'uint64' } }
+
+##
+# @BlockdevOptionsChild
+#
+# Driver specific block device options for child block device.
+#
+# Since: 2.5
+##
+{ 'struct': 'BlockdevOptionsChild',
+  'data': { 'child': 'BlockdevOptions' } }
+
+##
+# @child-add
+#
+# Add a new child to the parent BDS. Currently only the Quorum driver
+# implements this feature. 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 the parent BDS. Currently only the Quorum driver
+# implements this feature. 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' } }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index ba630b1..79a1146 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -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,