Message ID | 1442907862-21376-2-git-send-email-wency@cn.fujitsu.com |
---|---|
State | New |
Headers | show |
On Tue 22 Sep 2015 09:44:19 AM CEST, Wen Congyang <wency@cn.fujitsu.com> wrote: > In some cases, we want to take a quorum child offline, and take > another child online. > > 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> > Reviewed-by: Eric Blake <eblake@redhat.com> > +void bdrv_add_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, > + Error **errp) > +{ > + > + if (!parent_bs->drv || !parent_bs->drv->bdrv_add_child) { > + error_setg(errp, "The BDS %s doesn't support adding a child", > + bdrv_get_device_or_node_name(parent_bs)); > + return; > + } > + > + if (!QLIST_EMPTY(&child_bs->parents)) { > + error_setg(errp, "The BDS %s already has parent", > + child_bs->node_name); I think there's one 'a' missing: "The BDS %s already has a parent". I also don't think we should use "BDS" in error messages, that's an acronym for the name of a C data type, not something that the user is supposed to know about. I suggest using 'Node' instead. Otherwise the patch looks good to me, thanks! Berto
On 22.09.2015 09:44, Wen Congyang wrote: > In some cases, we want to take a quorum child offline, and take > another child online. > > 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> > Reviewed-by: Eric Blake <eblake@redhat.com> > --- > block.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ > include/block/block.h | 5 +++++ > include/block/block_int.h | 5 +++++ > 3 files changed, 60 insertions(+) > > diff --git a/block.c b/block.c > index e815d73..1b25e43 100644 > --- a/block.c > +++ b/block.c > @@ -4265,3 +4265,53 @@ BlockAcctStats *bdrv_get_stats(BlockDriverState *bs) > { > return &bs->stats; > } > + > +/* > + * Hot add/remove a BDS's child. So the user can take a child offline when > + * it is broken and take a new child online > + */ > +void bdrv_add_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, > + Error **errp) > +{ > + > + if (!parent_bs->drv || !parent_bs->drv->bdrv_add_child) { > + error_setg(errp, "The BDS %s doesn't support adding a child", > + bdrv_get_device_or_node_name(parent_bs)); > + return; > + } > + > + if (!QLIST_EMPTY(&child_bs->parents)) { > + error_setg(errp, "The BDS %s already has parent", > + child_bs->node_name); > + return; > + } > + > + parent_bs->drv->bdrv_add_child(parent_bs, child_bs, errp); > +} > + > +void bdrv_del_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, > + Error **errp) > +{ > + BdrvChild *child; > + > + if (!parent_bs->drv || !parent_bs->drv->bdrv_del_child) { > + error_setg(errp, "The BDS %s doesn't support removing a child", > + bdrv_get_device_or_node_name(parent_bs)); > + return; > + } > + > + QLIST_FOREACH(child, &parent_bs->children, next) { > + if (child->bs == child_bs) { > + break; > + } > + } > + > + if (!child) { > + error_setg(errp, "BDS %s is not a child of %s", > + bdrv_get_device_or_node_name(child_bs), > + bdrv_get_device_or_node_name(parent_bs)); > + return; > + } > + > + parent_bs->drv->bdrv_del_child(parent_bs, child_bs, errp); How about we make this (BlockDriver.bdrv_del_child()) take a BdrvChild instead of a BDS? We could even make bdrv_del_child() as a whole take a BdrvChild parameter, but I don't suppose that would help much. Max > +} > diff --git a/include/block/block.h b/include/block/block.h > index ef67353..665c56f 100644 > --- a/include/block/block.h > +++ b/include/block/block.h > @@ -616,4 +616,9 @@ void bdrv_flush_io_queue(BlockDriverState *bs); > > BlockAcctStats *bdrv_get_stats(BlockDriverState *bs); > > +void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, > + Error **errp); > +void bdrv_del_child(BlockDriverState *parent, BlockDriverState *child, > + Error **errp); > + > #endif > diff --git a/include/block/block_int.h b/include/block/block_int.h > index 2f2c47b..64cbc55 100644 > --- a/include/block/block_int.h > +++ b/include/block/block_int.h > @@ -288,6 +288,11 @@ struct BlockDriver { > */ > int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo); > > + void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, > + Error **errp); > + void (*bdrv_del_child)(BlockDriverState *parent, BlockDriverState *child, > + Error **errp); > + > QLIST_ENTRY(BlockDriver) list; > }; > >
* Wen Congyang (wency@cn.fujitsu.com) wrote: > In some cases, we want to take a quorum child offline, and take > another child online. Hi, Have you checked the output of 'info block' after adding/deleting a child? I'm using one of your older worlds (from a few months ago) and I found I had to add a bdrv_refresh_filename(bs); to get the output of 'info block' to show the new child. I don't see it in this version. Dave > > 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> > Reviewed-by: Eric Blake <eblake@redhat.com> > --- > block.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ > include/block/block.h | 5 +++++ > include/block/block_int.h | 5 +++++ > 3 files changed, 60 insertions(+) > > diff --git a/block.c b/block.c > index e815d73..1b25e43 100644 > --- a/block.c > +++ b/block.c > @@ -4265,3 +4265,53 @@ BlockAcctStats *bdrv_get_stats(BlockDriverState *bs) > { > return &bs->stats; > } > + > +/* > + * Hot add/remove a BDS's child. So the user can take a child offline when > + * it is broken and take a new child online > + */ > +void bdrv_add_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, > + Error **errp) > +{ > + > + if (!parent_bs->drv || !parent_bs->drv->bdrv_add_child) { > + error_setg(errp, "The BDS %s doesn't support adding a child", > + bdrv_get_device_or_node_name(parent_bs)); > + return; > + } > + > + if (!QLIST_EMPTY(&child_bs->parents)) { > + error_setg(errp, "The BDS %s already has parent", > + child_bs->node_name); > + return; > + } > + > + parent_bs->drv->bdrv_add_child(parent_bs, child_bs, errp); > +} > + > +void bdrv_del_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, > + Error **errp) > +{ > + BdrvChild *child; > + > + if (!parent_bs->drv || !parent_bs->drv->bdrv_del_child) { > + error_setg(errp, "The BDS %s doesn't support removing a child", > + bdrv_get_device_or_node_name(parent_bs)); > + return; > + } > + > + QLIST_FOREACH(child, &parent_bs->children, next) { > + if (child->bs == child_bs) { > + break; > + } > + } > + > + if (!child) { > + error_setg(errp, "BDS %s is not a child of %s", > + bdrv_get_device_or_node_name(child_bs), > + bdrv_get_device_or_node_name(parent_bs)); > + return; > + } > + > + parent_bs->drv->bdrv_del_child(parent_bs, child_bs, errp); > +} > diff --git a/include/block/block.h b/include/block/block.h > index ef67353..665c56f 100644 > --- a/include/block/block.h > +++ b/include/block/block.h > @@ -616,4 +616,9 @@ void bdrv_flush_io_queue(BlockDriverState *bs); > > BlockAcctStats *bdrv_get_stats(BlockDriverState *bs); > > +void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, > + Error **errp); > +void bdrv_del_child(BlockDriverState *parent, BlockDriverState *child, > + Error **errp); > + > #endif > diff --git a/include/block/block_int.h b/include/block/block_int.h > index 2f2c47b..64cbc55 100644 > --- a/include/block/block_int.h > +++ b/include/block/block_int.h > @@ -288,6 +288,11 @@ struct BlockDriver { > */ > int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo); > > + void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, > + Error **errp); > + void (*bdrv_del_child)(BlockDriverState *parent, BlockDriverState *child, > + Error **errp); > + > QLIST_ENTRY(BlockDriver) list; > }; > > -- > 2.4.3 > -- Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
On 10/08/2015 03:00 AM, Dr. David Alan Gilbert wrote: > * Wen Congyang (wency@cn.fujitsu.com) wrote: >> In some cases, we want to take a quorum child offline, and take >> another child online. > > Hi, > Have you checked the output of 'info block' after adding/deleting a child? > I'm using one of your older worlds (from a few months ago) and I found I had > to add a > > bdrv_refresh_filename(bs); > > to get the output of 'info block' to show the new child. > I don't see it in this version. Max sent a patch series to drop BDS.filename, so I don't call bdrv_refresh_filename() here. If the BDS is not the top BDS, 'info block' still shows the wrong child. Thanks Wen Congyang > > Dave > > >> >> 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> >> Reviewed-by: Eric Blake <eblake@redhat.com> >> --- >> block.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ >> include/block/block.h | 5 +++++ >> include/block/block_int.h | 5 +++++ >> 3 files changed, 60 insertions(+) >> >> diff --git a/block.c b/block.c >> index e815d73..1b25e43 100644 >> --- a/block.c >> +++ b/block.c >> @@ -4265,3 +4265,53 @@ BlockAcctStats *bdrv_get_stats(BlockDriverState *bs) >> { >> return &bs->stats; >> } >> + >> +/* >> + * Hot add/remove a BDS's child. So the user can take a child offline when >> + * it is broken and take a new child online >> + */ >> +void bdrv_add_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, >> + Error **errp) >> +{ >> + >> + if (!parent_bs->drv || !parent_bs->drv->bdrv_add_child) { >> + error_setg(errp, "The BDS %s doesn't support adding a child", >> + bdrv_get_device_or_node_name(parent_bs)); >> + return; >> + } >> + >> + if (!QLIST_EMPTY(&child_bs->parents)) { >> + error_setg(errp, "The BDS %s already has parent", >> + child_bs->node_name); >> + return; >> + } >> + >> + parent_bs->drv->bdrv_add_child(parent_bs, child_bs, errp); >> +} >> + >> +void bdrv_del_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, >> + Error **errp) >> +{ >> + BdrvChild *child; >> + >> + if (!parent_bs->drv || !parent_bs->drv->bdrv_del_child) { >> + error_setg(errp, "The BDS %s doesn't support removing a child", >> + bdrv_get_device_or_node_name(parent_bs)); >> + return; >> + } >> + >> + QLIST_FOREACH(child, &parent_bs->children, next) { >> + if (child->bs == child_bs) { >> + break; >> + } >> + } >> + >> + if (!child) { >> + error_setg(errp, "BDS %s is not a child of %s", >> + bdrv_get_device_or_node_name(child_bs), >> + bdrv_get_device_or_node_name(parent_bs)); >> + return; >> + } >> + >> + parent_bs->drv->bdrv_del_child(parent_bs, child_bs, errp); >> +} >> diff --git a/include/block/block.h b/include/block/block.h >> index ef67353..665c56f 100644 >> --- a/include/block/block.h >> +++ b/include/block/block.h >> @@ -616,4 +616,9 @@ void bdrv_flush_io_queue(BlockDriverState *bs); >> >> BlockAcctStats *bdrv_get_stats(BlockDriverState *bs); >> >> +void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, >> + Error **errp); >> +void bdrv_del_child(BlockDriverState *parent, BlockDriverState *child, >> + Error **errp); >> + >> #endif >> diff --git a/include/block/block_int.h b/include/block/block_int.h >> index 2f2c47b..64cbc55 100644 >> --- a/include/block/block_int.h >> +++ b/include/block/block_int.h >> @@ -288,6 +288,11 @@ struct BlockDriver { >> */ >> int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo); >> >> + void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, >> + Error **errp); >> + void (*bdrv_del_child)(BlockDriverState *parent, BlockDriverState *child, >> + Error **errp); >> + >> QLIST_ENTRY(BlockDriver) list; >> }; >> >> -- >> 2.4.3 >> > -- > Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK > . >
On 10/07/2015 09:35 PM, Alberto Garcia wrote: > On Tue 22 Sep 2015 09:44:19 AM CEST, Wen Congyang <wency@cn.fujitsu.com> wrote: >> In some cases, we want to take a quorum child offline, and take >> another child online. >> >> 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> >> Reviewed-by: Eric Blake <eblake@redhat.com> > >> +void bdrv_add_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, >> + Error **errp) >> +{ >> + >> + if (!parent_bs->drv || !parent_bs->drv->bdrv_add_child) { >> + error_setg(errp, "The BDS %s doesn't support adding a child", >> + bdrv_get_device_or_node_name(parent_bs)); >> + return; >> + } >> + >> + if (!QLIST_EMPTY(&child_bs->parents)) { >> + error_setg(errp, "The BDS %s already has parent", >> + child_bs->node_name); > > I think there's one 'a' missing: > > "The BDS %s already has a parent". > > I also don't think we should use "BDS" in error messages, that's an > acronym for the name of a C data type, not something that the user is > supposed to know about. > > I suggest using 'Node' instead. > > Otherwise the patch looks good to me, thanks! OK, I will fix it in the next version Thanks Wen Congyang > > Berto > . >
On 10/08/2015 02:33 AM, Max Reitz wrote: > On 22.09.2015 09:44, Wen Congyang wrote: >> In some cases, we want to take a quorum child offline, and take >> another child online. >> >> 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> >> Reviewed-by: Eric Blake <eblake@redhat.com> >> --- >> block.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ >> include/block/block.h | 5 +++++ >> include/block/block_int.h | 5 +++++ >> 3 files changed, 60 insertions(+) >> >> diff --git a/block.c b/block.c >> index e815d73..1b25e43 100644 >> --- a/block.c >> +++ b/block.c >> @@ -4265,3 +4265,53 @@ BlockAcctStats *bdrv_get_stats(BlockDriverState *bs) >> { >> return &bs->stats; >> } >> + >> +/* >> + * Hot add/remove a BDS's child. So the user can take a child offline when >> + * it is broken and take a new child online >> + */ >> +void bdrv_add_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, >> + Error **errp) >> +{ >> + >> + if (!parent_bs->drv || !parent_bs->drv->bdrv_add_child) { >> + error_setg(errp, "The BDS %s doesn't support adding a child", >> + bdrv_get_device_or_node_name(parent_bs)); >> + return; >> + } >> + >> + if (!QLIST_EMPTY(&child_bs->parents)) { >> + error_setg(errp, "The BDS %s already has parent", >> + child_bs->node_name); >> + return; >> + } >> + >> + parent_bs->drv->bdrv_add_child(parent_bs, child_bs, errp); >> +} >> + >> +void bdrv_del_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, >> + Error **errp) >> +{ >> + BdrvChild *child; >> + >> + if (!parent_bs->drv || !parent_bs->drv->bdrv_del_child) { >> + error_setg(errp, "The BDS %s doesn't support removing a child", >> + bdrv_get_device_or_node_name(parent_bs)); >> + return; >> + } >> + >> + QLIST_FOREACH(child, &parent_bs->children, next) { >> + if (child->bs == child_bs) { >> + break; >> + } >> + } >> + >> + if (!child) { >> + error_setg(errp, "BDS %s is not a child of %s", >> + bdrv_get_device_or_node_name(child_bs), >> + bdrv_get_device_or_node_name(parent_bs)); >> + return; >> + } >> + >> + parent_bs->drv->bdrv_del_child(parent_bs, child_bs, errp); > > How about we make this (BlockDriver.bdrv_del_child()) take a BdrvChild > instead of a BDS? We could even make bdrv_del_child() as a whole take a > BdrvChild parameter, but I don't suppose that would help much. bdrv_add_child() takes a BDS, so I use BDS here. Thanks Wen Congyang > > Max > >> +} >> diff --git a/include/block/block.h b/include/block/block.h >> index ef67353..665c56f 100644 >> --- a/include/block/block.h >> +++ b/include/block/block.h >> @@ -616,4 +616,9 @@ void bdrv_flush_io_queue(BlockDriverState *bs); >> >> BlockAcctStats *bdrv_get_stats(BlockDriverState *bs); >> >> +void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, >> + Error **errp); >> +void bdrv_del_child(BlockDriverState *parent, BlockDriverState *child, >> + Error **errp); >> + >> #endif >> diff --git a/include/block/block_int.h b/include/block/block_int.h >> index 2f2c47b..64cbc55 100644 >> --- a/include/block/block_int.h >> +++ b/include/block/block_int.h >> @@ -288,6 +288,11 @@ struct BlockDriver { >> */ >> int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo); >> >> + void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, >> + Error **errp); >> + void (*bdrv_del_child)(BlockDriverState *parent, BlockDriverState *child, >> + Error **errp); >> + >> QLIST_ENTRY(BlockDriver) list; >> }; >> >> > >
* Wen Congyang (wency@cn.fujitsu.com) wrote: > On 10/08/2015 03:00 AM, Dr. David Alan Gilbert wrote: > > * Wen Congyang (wency@cn.fujitsu.com) wrote: > >> In some cases, we want to take a quorum child offline, and take > >> another child online. > > > > Hi, > > Have you checked the output of 'info block' after adding/deleting a child? > > I'm using one of your older worlds (from a few months ago) and I found I had > > to add a > > > > bdrv_refresh_filename(bs); > > > > to get the output of 'info block' to show the new child. > > I don't see it in this version. > > Max sent a patch series to drop BDS.filename, so I don't call bdrv_refresh_filename() > here. If the BDS is not the top BDS, 'info block' still shows the wrong child. Ah, so I guess you can just implement the exact_filename() function and that will get it right? Dave > > Thanks > Wen Congyang > > > > > Dave > > > > > >> > >> 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> > >> Reviewed-by: Eric Blake <eblake@redhat.com> > >> --- > >> block.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ > >> include/block/block.h | 5 +++++ > >> include/block/block_int.h | 5 +++++ > >> 3 files changed, 60 insertions(+) > >> > >> diff --git a/block.c b/block.c > >> index e815d73..1b25e43 100644 > >> --- a/block.c > >> +++ b/block.c > >> @@ -4265,3 +4265,53 @@ BlockAcctStats *bdrv_get_stats(BlockDriverState *bs) > >> { > >> return &bs->stats; > >> } > >> + > >> +/* > >> + * Hot add/remove a BDS's child. So the user can take a child offline when > >> + * it is broken and take a new child online > >> + */ > >> +void bdrv_add_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, > >> + Error **errp) > >> +{ > >> + > >> + if (!parent_bs->drv || !parent_bs->drv->bdrv_add_child) { > >> + error_setg(errp, "The BDS %s doesn't support adding a child", > >> + bdrv_get_device_or_node_name(parent_bs)); > >> + return; > >> + } > >> + > >> + if (!QLIST_EMPTY(&child_bs->parents)) { > >> + error_setg(errp, "The BDS %s already has parent", > >> + child_bs->node_name); > >> + return; > >> + } > >> + > >> + parent_bs->drv->bdrv_add_child(parent_bs, child_bs, errp); > >> +} > >> + > >> +void bdrv_del_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, > >> + Error **errp) > >> +{ > >> + BdrvChild *child; > >> + > >> + if (!parent_bs->drv || !parent_bs->drv->bdrv_del_child) { > >> + error_setg(errp, "The BDS %s doesn't support removing a child", > >> + bdrv_get_device_or_node_name(parent_bs)); > >> + return; > >> + } > >> + > >> + QLIST_FOREACH(child, &parent_bs->children, next) { > >> + if (child->bs == child_bs) { > >> + break; > >> + } > >> + } > >> + > >> + if (!child) { > >> + error_setg(errp, "BDS %s is not a child of %s", > >> + bdrv_get_device_or_node_name(child_bs), > >> + bdrv_get_device_or_node_name(parent_bs)); > >> + return; > >> + } > >> + > >> + parent_bs->drv->bdrv_del_child(parent_bs, child_bs, errp); > >> +} > >> diff --git a/include/block/block.h b/include/block/block.h > >> index ef67353..665c56f 100644 > >> --- a/include/block/block.h > >> +++ b/include/block/block.h > >> @@ -616,4 +616,9 @@ void bdrv_flush_io_queue(BlockDriverState *bs); > >> > >> BlockAcctStats *bdrv_get_stats(BlockDriverState *bs); > >> > >> +void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, > >> + Error **errp); > >> +void bdrv_del_child(BlockDriverState *parent, BlockDriverState *child, > >> + Error **errp); > >> + > >> #endif > >> diff --git a/include/block/block_int.h b/include/block/block_int.h > >> index 2f2c47b..64cbc55 100644 > >> --- a/include/block/block_int.h > >> +++ b/include/block/block_int.h > >> @@ -288,6 +288,11 @@ struct BlockDriver { > >> */ > >> int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo); > >> > >> + void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, > >> + Error **errp); > >> + void (*bdrv_del_child)(BlockDriverState *parent, BlockDriverState *child, > >> + Error **errp); > >> + > >> QLIST_ENTRY(BlockDriver) list; > >> }; > >> > >> -- > >> 2.4.3 > >> > > -- > > Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK > > . > > > -- Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
diff --git a/block.c b/block.c index e815d73..1b25e43 100644 --- a/block.c +++ b/block.c @@ -4265,3 +4265,53 @@ BlockAcctStats *bdrv_get_stats(BlockDriverState *bs) { return &bs->stats; } + +/* + * Hot add/remove a BDS's child. So the user can take a child offline when + * it is broken and take a new child online + */ +void bdrv_add_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, + Error **errp) +{ + + if (!parent_bs->drv || !parent_bs->drv->bdrv_add_child) { + error_setg(errp, "The BDS %s doesn't support adding a child", + bdrv_get_device_or_node_name(parent_bs)); + return; + } + + if (!QLIST_EMPTY(&child_bs->parents)) { + error_setg(errp, "The BDS %s already has parent", + child_bs->node_name); + return; + } + + parent_bs->drv->bdrv_add_child(parent_bs, child_bs, errp); +} + +void bdrv_del_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, + Error **errp) +{ + BdrvChild *child; + + if (!parent_bs->drv || !parent_bs->drv->bdrv_del_child) { + error_setg(errp, "The BDS %s doesn't support removing a child", + bdrv_get_device_or_node_name(parent_bs)); + return; + } + + QLIST_FOREACH(child, &parent_bs->children, next) { + if (child->bs == child_bs) { + break; + } + } + + if (!child) { + error_setg(errp, "BDS %s is not a child of %s", + bdrv_get_device_or_node_name(child_bs), + bdrv_get_device_or_node_name(parent_bs)); + return; + } + + parent_bs->drv->bdrv_del_child(parent_bs, child_bs, errp); +} diff --git a/include/block/block.h b/include/block/block.h index ef67353..665c56f 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -616,4 +616,9 @@ void bdrv_flush_io_queue(BlockDriverState *bs); BlockAcctStats *bdrv_get_stats(BlockDriverState *bs); +void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, + Error **errp); +void bdrv_del_child(BlockDriverState *parent, BlockDriverState *child, + Error **errp); + #endif diff --git a/include/block/block_int.h b/include/block/block_int.h index 2f2c47b..64cbc55 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -288,6 +288,11 @@ struct BlockDriver { */ int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo); + void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, + Error **errp); + void (*bdrv_del_child)(BlockDriverState *parent, BlockDriverState *child, + Error **errp); + QLIST_ENTRY(BlockDriver) list; };