qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH for-2.10] block: Skip implicit nodes in query-bl


From: Nir Soffer
Subject: Re: [Qemu-devel] [PATCH for-2.10] block: Skip implicit nodes in query-block/blockstats
Date: Wed, 19 Jul 2017 13:19:34 +0000

On Wed, Jul 19, 2017 at 4:05 PM Markus Armbruster <address@hidden> wrote:

> Kevin Wolf <address@hidden> writes:
>
> > Commits 0db832f and 6cdbceb introduced the automatic insertion of filter
> > nodes above the top layer of mirror and commit block jobs. The
> > assumption made there was that since libvirt doesn't do node-level
> > management of the block layer yet, it shouldn't be affected by added
> > nodes.
> >
> > This is true as far as commands issued by libvirt are concerned. It only
> > uses BlockBackend names to address nodes, so any operations it performs
> > still operate on the root of the tree as intended.
> >
> > However, the assumption breaks down when you consider query commands,
> > which return data for the wrong node now. These commands also return
> > information on some child nodes (bs->file and/or bs->backing), which
> > libvirt does make use of, and which refer to the wrong nodes, too.
> >
> > One of the consequences is that oVirt gets wrong information about the
> > image size and stops the VM in response as long as a mirror or commit
> > job is running:
> >
> > https://bugzilla.redhat.com/show_bug.cgi?id=1470634
> >
> > This patch fixes the problem by hiding the implict nodes created
> > automatically by the mirror and commit block jobs in the output of
> > query-block and BlockBackend-based query-blockstats as long as the user
> > doesn't indicate that they are aware of those nodes by providing a node
> > name for them in the QMP command to start the block job.
> >
> > The node-based commands query-named-block-nodes and query-blockstats
> > with query-nodes=true still show all nodes, including implicit ones.
>
> The only other query-FOO in block*.json is query-block-jobs.  Good.
>
> > This ensures that users that are capable of node-level management can
> > still access the full information; users that only know BlockBackends
> > won't use these commands.
>
> I think I can follow your reasoning, but I could use a concrete example.
> A small reproducer with output before and after the patch, and an
> explanation what exactly makes the output before the patch problematic.
>

You can find a reproducer and example output here:
https://bugzilla.redhat.com/show_bug.cgi?id=1470634#c28


>
> > Cc: address@hidden
> > Signed-off-by: Kevin Wolf <address@hidden>
> > ---
> >  block/commit.c             |  3 +++
> >  block/mirror.c             |  3 +++
> >  block/qapi.c               | 13 ++++++++++++-
> >  include/block/block_int.h  |  1 +
> >  qapi/block-core.json       |  6 ++++--
> >  tests/qemu-iotests/041     | 23 +++++++++++++++++++++++
> >  tests/qemu-iotests/041.out |  4 ++--
> >  7 files changed, 48 insertions(+), 5 deletions(-)
> >
> > diff --git a/block/commit.c b/block/commit.c
> > index 5cc910f..c7857c3 100644
> > --- a/block/commit.c
> > +++ b/block/commit.c
> > @@ -346,6 +346,9 @@ void commit_start(const char *job_id,
> BlockDriverState *bs,
> >      if (commit_top_bs == NULL) {
> >          goto fail;
> >      }
> > +    if (!filter_node_name) {
> > +        commit_top_bs->implicit = true;
> > +    }
> >      commit_top_bs->total_sectors = top->total_sectors;
> >      bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(top));
> >
> > diff --git a/block/mirror.c b/block/mirror.c
> > index 8583b76..c9a6a3c 100644
> > --- a/block/mirror.c
> > +++ b/block/mirror.c
> > @@ -1168,6 +1168,9 @@ static void mirror_start_job(const char *job_id,
> BlockDriverState *bs,
> >      if (mirror_top_bs == NULL) {
> >          return;
> >      }
> > +    if (!filter_node_name) {
> > +        mirror_top_bs->implicit = true;
> > +    }
> >      mirror_top_bs->total_sectors = bs->total_sectors;
> >      bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(bs));
> >
> > diff --git a/block/qapi.c b/block/qapi.c
> > index 95b2e2d..0ed23b8 100644
> > --- a/block/qapi.c
> > +++ b/block/qapi.c
> > @@ -324,6 +324,11 @@ static void bdrv_query_info(BlockBackend *blk,
> BlockInfo **p_info,
> >      BlockDriverState *bs = blk_bs(blk);
> >      char *qdev;
> >
> > +    /* Skip automatically inserted nodes that the user isn't aware of */
> > +    while (bs && bs->drv && bs->implicit) {
> > +        bs = backing_bs(bs);
> > +    }
> > +
> >      info->device = g_strdup(blk_name(blk));
> >      info->type = g_strdup("unknown");
> >      info->locked = blk_dev_is_medium_locked(blk);
> > @@ -518,12 +523,18 @@ BlockStatsList *qmp_query_blockstats(bool
> has_query_nodes,
> >          }
> >      } else {
> >          for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
> > +            BlockDriverState *bs = blk_bs(blk);
> >              BlockStatsList *info = g_malloc0(sizeof(*info));
> >              AioContext *ctx = blk_get_aio_context(blk);
> >              BlockStats *s;
> >
> > +            /* Skip automatically inserted nodes that the user isn't
> aware of */
> > +            while (bs && bs->drv && bs->implicit) {
> > +                bs = backing_bs(bs);
> > +            }
> > +
> >              aio_context_acquire(ctx);
> > -            s = bdrv_query_bds_stats(blk_bs(blk), true);
> > +            s = bdrv_query_bds_stats(bs, true);
> >              s->has_device = true;
> >              s->device = g_strdup(blk_name(blk));
> >              bdrv_query_blk_stats(s->stats, blk);
>
> The result types of query-block and query-blockstats are recursive.  How
> can I convince myself that we're skipping everywhere we need to?
>
> > diff --git a/include/block/block_int.h b/include/block/block_int.h
> > index 5c6b761..d4f4ea7 100644
> > --- a/include/block/block_int.h
> > +++ b/include/block/block_int.h
> > @@ -549,6 +549,7 @@ struct BlockDriverState {
> >      bool sg;        /* if true, the device is a /dev/sg* */
> >      bool probed;    /* if true, format was probed rather than specified
> */
> >      bool force_share; /* if true, always allow all shared permissions */
> > +    bool implicit;  /* if true, this filter node was automatically
> inserted */
>
> Makes sense.  How can I convince myself that your patch marks them all?
>
> >
> >      BlockDriver *drv; /* NULL means no media */
> >      void *opaque;
> > diff --git a/qapi/block-core.json b/qapi/block-core.json
> > index ff8e2ba..006e048 100644
> > --- a/qapi/block-core.json
> > +++ b/qapi/block-core.json
> > @@ -520,7 +520,8 @@
> >  #
> >  # Get a list of BlockInfo for all virtual block devices.
> >  #
> > -# Returns: a list of @BlockInfo describing each virtual block device
> > +# Returns: a list of @BlockInfo describing each virtual block device.
> Filter
> > +# nodes that were created implicitly are skipped over.
> >  #
> >  # Since: 0.14.0
> >  #
> > @@ -780,7 +781,8 @@
> >  #               information, but not "backing".
> >  #               If false or omitted, the behavior is as before - query
> all the
> >  #               device backends, recursively including their "parent"
> and
> > -#               "backing". (Since 2.3)
> > +#               "backing". Filter nodes that were created implicitly are
> > +#               skipped over in this mode. (Since 2.3)
> >  #
> >  # Returns: A list of @BlockStats for each virtual block devices.
> >  #
> > diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
> > index 2f54986..b798cca 100755
> > --- a/tests/qemu-iotests/041
> > +++ b/tests/qemu-iotests/041
> > @@ -169,6 +169,29 @@ class TestSingleDrive(iotests.QMPTestCase):
> >          self.assertTrue(iotests.compare_images(test_img, target_img),
> >                          'target image does not match source after
> mirroring')
> >
> > +    # Tests that the insertion of the mirror_top filter node doesn't
> make a
> > +    # difference to query-block
> > +    def test_implicit_node(self):
> > +        self.assert_no_active_block_jobs()
> > +
> > +        result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
> > +                             target=self.qmp_target)
> > +        self.assert_qmp(result, 'return', {})
> > +
> > +        result = self.vm.qmp('query-block')
> > +        self.assert_qmp(result, 'return[0]/inserted/file', test_img)
> > +        self.assert_qmp(result, 'return[0]/inserted/drv',
> iotests.imgfmt)
> > +        self.assert_qmp(result, 'return[0]/inserted/backing_file',
> backing_img)
> > +        self.assert_qmp(result,
> 'return[0]/inserted/backing_file_depth', 1)
> > +
> > +        self.cancel_and_wait(force=True)
> > +        result = self.vm.qmp('query-block')
> > +        self.assert_qmp(result, 'return[0]/inserted/file', test_img)
> > +        self.assert_qmp(result, 'return[0]/inserted/drv',
> iotests.imgfmt)
> > +        self.assert_qmp(result, 'return[0]/inserted/backing_file',
> backing_img)
> > +        self.assert_qmp(result,
> 'return[0]/inserted/backing_file_depth', 1)
> > +        self.vm.shutdown()
> > +
> >      def test_medium_not_found(self):
> >          if iotests.qemu_default_machine != 'pc':
> >              return
> > diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out
> > index e30fd3b..c28b392 100644
> > --- a/tests/qemu-iotests/041.out
> > +++ b/tests/qemu-iotests/041.out
> > @@ -1,5 +1,5 @@
> >
> -...............................................................................
> >
> +.....................................................................................
> >  ----------------------------------------------------------------------
> > -Ran 79 tests
> > +Ran 85 tests
> >
> >  OK
>
> The patch makes sense to me.  The hard part is judging whether it's
> complete.  I could use a bit of help with that.
>


reply via email to

[Prev in Thread] Current Thread [Next in Thread]