qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
To: Max Reitz <mreitz@redhat.com>,
	"qemu-block@nongnu.org" <qemu-block@nongnu.org>
Cc: Kevin Wolf <kwolf@redhat.com>, John Snow <jsnow@redhat.com>,
	"qemu-devel@nongnu.org" <qemu-devel@nongnu.org>
Subject: Re: [PATCH v2 2/4] blkdebug: Allow taking/unsharing permissions
Date: Wed, 25 Sep 2019 10:12:02 +0000	[thread overview]
Message-ID: <a51238ad-bfac-32eb-1b1e-05f526181e07@virtuozzo.com> (raw)
In-Reply-To: <20190923115728.28250-3-mreitz@redhat.com>

23.09.2019 14:57, Max Reitz wrote:
> Sometimes it is useful to be able to add a node to the block graph that
> takes or unshare a certain set of permissions for debugging purposes.
> This patch adds this capability to blkdebug.
> 
> (Note that you cannot make blkdebug release or share permissions that it
> needs to take or cannot share, because this might result in assertion
> failures in the block layer.  But if the blkdebug node has no parents,
> it will not take any permissions and share everything by default, so you
> can then freely choose what permissions to take and share.)
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>   qapi/block-core.json |  14 +++++-
>   block/blkdebug.c     | 106 ++++++++++++++++++++++++++++++++++++++++++-
>   2 files changed, 118 insertions(+), 2 deletions(-)
> 
> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index b5cd00c361..572c5756f1 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -3394,6 +3394,16 @@
>   #
>   # @set-state:       array of state-change descriptions
>   #
> +# @take-child-perms: Permissions to take on @image in addition to what
> +#                    is necessary anyway (which depends on how the
> +#                    blkdebug node is used).  Defaults to none.
> +#                    (since 4.2)
> +#
> +# @unshare-child-perms: Permissions not to share on @image in addition
> +#                       to what cannot be shared anyway (which depends
> +#                       on how the blkdebug node is used).  Defaults
> +#                       to none.  (since 4.2)
> +#
>   # Since: 2.9
>   ##
>   { 'struct': 'BlockdevOptionsBlkdebug',
> @@ -3403,7 +3413,9 @@
>               '*opt-write-zero': 'int32', '*max-write-zero': 'int32',
>               '*opt-discard': 'int32', '*max-discard': 'int32',
>               '*inject-error': ['BlkdebugInjectErrorOptions'],
> -            '*set-state': ['BlkdebugSetStateOptions'] } }
> +            '*set-state': ['BlkdebugSetStateOptions'],
> +            '*take-child-perms': ['BlockPermission'],
> +            '*unshare-child-perms': ['BlockPermission'] } }
>   
>   ##
>   # @BlockdevOptionsBlklogwrites:
> diff --git a/block/blkdebug.c b/block/blkdebug.c
> index 5ae96c52b0..f3c1e4ad7b 100644
> --- a/block/blkdebug.c
> +++ b/block/blkdebug.c
> @@ -28,9 +28,11 @@
>   #include "qemu/cutils.h"
>   #include "qemu/config-file.h"
>   #include "block/block_int.h"
> +#include "block/qdict.h"
>   #include "qemu/module.h"
>   #include "qemu/option.h"
>   #include "qapi/qmp/qdict.h"
> +#include "qapi/qmp/qlist.h"
>   #include "qapi/qmp/qstring.h"
>   #include "sysemu/qtest.h"
>   
> @@ -44,6 +46,9 @@ typedef struct BDRVBlkdebugState {
>       uint64_t opt_discard;
>       uint64_t max_discard;
>   
> +    uint64_t take_child_perms;
> +    uint64_t unshare_child_perms;
> +
>       /* For blkdebug_refresh_filename() */
>       char *config_file;
>   
> @@ -344,6 +349,84 @@ static void blkdebug_parse_filename(const char *filename, QDict *options,
>       qdict_put_str(options, "x-image", filename);
>   }
>   
> +static int blkdebug_parse_perm_list(uint64_t *dest, QDict *options,
> +                                    const char *prefix, Error **errp)
> +{
> +    int ret = 0;
> +    QDict *subqdict = NULL;
> +    QObject *crumpled_subqdict = NULL;
> +    QList *perm_list;
> +    const QListEntry *perm;
> +
> +    qdict_extract_subqdict(options, &subqdict, prefix);
> +    if (!qdict_size(subqdict)) {
> +        goto out;
> +    }
> +
> +    crumpled_subqdict = qdict_crumple(subqdict, errp);
> +    if (!crumpled_subqdict) {
> +        ret = -EINVAL;
> +        goto out;
> +    }
> +
> +    perm_list = qobject_to(QList, crumpled_subqdict);
> +    if (!perm_list) {
> +        /* Omit the trailing . from the prefix */
> +        error_setg(errp, "%.*s expects a list",
> +                   (int)(strlen(prefix) - 1), prefix);
> +        ret = -EINVAL;
> +        goto out;
> +    }
> +
> +    for (perm = qlist_first(perm_list); perm; perm = qlist_next(perm)) {
> +        const char *perm_name;
> +        BlockPermission perm_bit;
> +
> +        perm_name = qstring_get_try_str(qobject_to(QString, perm->value));
> +        if (!perm_name) {
> +            /* Omit the trailing . from the prefix */
> +            error_setg(errp, "%.*s expects a list of enum strings",
> +                       (int)(strlen(prefix) - 1), prefix);
> +            ret = -EINVAL;
> +            goto out;
> +        }
> +
> +        perm_bit = qapi_enum_parse(&BlockPermission_lookup, perm_name,
> +                                   BLOCK_PERMISSION__MAX, errp);
> +        if (perm_bit == BLOCK_PERMISSION__MAX) {
> +            ret = -EINVAL;
> +            goto out;
> +        }
> +
> +        *dest |= UINT64_C(1) << perm_bit;
> +    }


I still think that parsing it all by hand is a bad idea. We already have
functions which does it, why to opencode? The following works for me:

static int blkdebug_parse_perm_list(uint64_t *dest, QDict *options,
                                     const char *prefix, Error **errp)
{
     Error *local_err = NULL;
     Visitor *v = NULL;
     BlockPermissionList *list = NULL, *perm;
     int ret = 0;
     QDict *subqdict = NULL;
     QObject *crumpled_subqdict = NULL;
     uint64_t perm_map[] = {
         [BLOCK_PERMISSION_CONSISTENT_READ] = BLK_PERM_CONSISTENT_READ,
         [BLOCK_PERMISSION_WRITE] = BLK_PERM_WRITE,
         [BLOCK_PERMISSION_WRITE_UNCHANGED] = BLK_PERM_WRITE_UNCHANGED,
         [BLOCK_PERMISSION_RESIZE] = BLK_PERM_RESIZE,
         [BLOCK_PERMISSION_GRAPH_MOD] = BLK_PERM_GRAPH_MOD,
     };

     qdict_extract_subqdict(options, &subqdict, prefix);
     if (!qdict_size(subqdict)) {
         goto out;
     }

     crumpled_subqdict = qdict_crumple(subqdict, errp);
     if (!crumpled_subqdict) {
         ret = -EINVAL;
         goto out;
     }

     v = qobject_input_visitor_new(QOBJECT(crumpled_subqdict));
     visit_type_BlockPermissionList(v, NULL, &list, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         goto out;
     }

     for (perm = list; perm; perm = perm->next) {
         *dest |= perm_map[perm->value];
     }

     qapi_free_BlockPermissionList(list);

out:
     visit_free(v);
     qobject_unref(subqdict);
     qobject_unref(crumpled_subqdict);
     return ret;
}


Probably, we can do similar thing for the whole blkdebug_open and drop runtime_opts,
but it's for another series..

> +
> +out:
> +    qobject_unref(subqdict);
> +    qobject_unref(crumpled_subqdict);
> +    return ret;
> +}
> +
> +static int blkdebug_parse_perms(BDRVBlkdebugState *s, QDict *options,
> +                                Error **errp)
> +{
> +    int ret;
> +
> +    ret = blkdebug_parse_perm_list(&s->take_child_perms, options,
> +                                   "take-child-perms.", errp);
> +    if (ret < 0) {
> +        return ret;
> +    }
> +
> +    ret = blkdebug_parse_perm_list(&s->unshare_child_perms, options,
> +                                   "unshare-child-perms.", errp);
> +    if (ret < 0) {
> +        return ret;
> +    }
> +
> +    return 0;
> +}
> +
>   static QemuOptsList runtime_opts = {
>       .name = "blkdebug",
>       .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
> @@ -419,6 +502,12 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
>       /* Set initial state */
>       s->state = 1;
>   
> +    /* Parse permissions modifiers before opening the image file */
> +    ret = blkdebug_parse_perms(s, options, errp);
> +    if (ret < 0) {
> +        goto out;
> +    }
> +
>       /* Open the image file */
>       bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
>                                  bs, &child_file, false, &local_err);
> @@ -916,6 +1005,21 @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
>       return 0;
>   }
>   
> +static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c,
> +                                const BdrvChildRole *role,
> +                                BlockReopenQueue *reopen_queue,
> +                                uint64_t perm, uint64_t shared,
> +                                uint64_t *nperm, uint64_t *nshared)
> +{
> +    BDRVBlkdebugState *s = bs->opaque;
> +
> +    bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
> +                              nperm, nshared);
> +
> +    *nperm |= s->take_child_perms;
> +    *nshared &= ~s->unshare_child_perms;
> +}
> +
>   static const char *const blkdebug_strong_runtime_opts[] = {
>       "config",
>       "inject-error.",
> @@ -940,7 +1044,7 @@ static BlockDriver bdrv_blkdebug = {
>       .bdrv_file_open         = blkdebug_open,
>       .bdrv_close             = blkdebug_close,
>       .bdrv_reopen_prepare    = blkdebug_reopen_prepare,
> -    .bdrv_child_perm        = bdrv_filter_default_perms,
> +    .bdrv_child_perm        = blkdebug_child_perm,
>   
>       .bdrv_getlength         = blkdebug_getlength,
>       .bdrv_refresh_filename  = blkdebug_refresh_filename,
> 
kkkk

-- 
Best regards,
Vladimir

  reply	other threads:[~2019-09-25 10:14 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-09-23 11:57 [PATCH v2 0/4] mirror: Do not dereference invalid pointers Max Reitz
2019-09-23 11:57 ` [PATCH v2 1/4] " Max Reitz
2019-09-23 11:57 ` [PATCH v2 2/4] blkdebug: Allow taking/unsharing permissions Max Reitz
2019-09-25 10:12   ` Vladimir Sementsov-Ogievskiy [this message]
2019-09-26 11:00     ` Max Reitz
2019-09-23 11:57 ` [PATCH v2 3/4] iotests: Add @error to wait_until_completed Max Reitz
2019-09-23 11:57 ` [PATCH v2 4/4] iotests: Add test for failing mirror complete Max Reitz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=a51238ad-bfac-32eb-1b1e-05f526181e07@virtuozzo.com \
    --to=vsementsov@virtuozzo.com \
    --cc=jsnow@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=mreitz@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).