On 21.02.2017 15:58, Kevin Wolf wrote: > In many cases, the required permissions of one node on its children > depends on what its parents require from it. For example, the raw format *depend > or most filter drivers only need to request consistent reads if that's > something that one of their parents wants. > > In order to achieve this, this patch introduces two new BlockDriver > callbacks. The first one lets drivers first check (recursively) whether > the requested permissions can be set; the second one actually sets the > new permission bitmask. > > Also add helper functions that drivers can use in their implementation > of the callbacks to update their permissions on a specific child. > > Signed-off-by: Kevin Wolf > --- > block.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++ > include/block/block_int.h | 61 ++++++++++++++++ > 2 files changed, 237 insertions(+) > > diff --git a/block.c b/block.c > index d9f2267..2a86781 100644 > --- a/block.c > +++ b/block.c > @@ -1326,11 +1326,145 @@ static int bdrv_fill_options(QDict **options, const char *filename, [...] > +/* > + * Notifies drivers that after a previous bdrv_check_perm() call, the > + * permission update is not performed and any preparations made for it (e.g. > + * taken file locks) need to be undone. > + * > + * This function recursively notifies all child nodes. > + */ > +static void bdrv_abort_perm_update(BlockDriverState *bs) > +{ > + BlockDriver *drv = bs->drv; > + BdrvChild *c; > + > + if (!drv) { > + return; > + } > + > + if (drv->bdrv_abort_perm_update) { > + drv->bdrv_abort_perm_update(bs); > + } > + > + QLIST_FOREACH(c, &bs->children, next) { > + bdrv_abort_perm_update(c->bs); Could use bdrv_child_abort_perm_update(c) just for symmetry with bdrv_check_perm() (which uses bdrv_child_check_perm() to recurse). > + } > +} > + [...] > @@ -1353,8 +1487,47 @@ static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm, > error_setg(errp, "Conflicts with %s", user ?: "another operation"); > return -EPERM; > } > + > + cumulative_perms |= c->perm; > + cumulative_shared_perms &= c->shared_perm; > + } > + > + return bdrv_check_perm(bs, cumulative_perms, cumulative_shared_perms, errp); > +} > + > +/* Needs to be followed by a call to either bdrv_set_perm() or > + * bdrv_abort_perm_update(). */ *"bdrv_child_set_perm() or bdrv_child_abort_perm_update()"? (Doesn't really matter, but it makes for nicer symmetry.) > +int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared, > + Error **errp) > +{ > + return bdrv_check_update_perm(c->bs, perm, shared, c, errp); > +} [...] > @@ -1390,6 +1565,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, > > ret = bdrv_check_update_perm(child_bs, perm, shared_perm, NULL, errp); > if (ret < 0) { > + bdrv_abort_perm_update(child_bs); > return NULL; > } > This function doesn't call bdrv_set_perm(). Intentional? Max [...]