From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48120) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1avPbr-0002Ki-MA for qemu-devel@nongnu.org; Wed, 27 Apr 2016 09:34:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1avPbq-0004ya-Am for qemu-devel@nongnu.org; Wed, 27 Apr 2016 09:34:31 -0400 References: From: Max Reitz Message-ID: <5720BFDB.60600@redhat.com> Date: Wed, 27 Apr 2016 15:34:19 +0200 MIME-Version: 1.0 In-Reply-To: Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="TPTAgD1HA4G2Bm22LvR7GSqdvtekCHgk3" Subject: Re: [Qemu-devel] [PATCH v9 07/11] block: Add QMP support for streaming to an intermediate layer List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Alberto Garcia , qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, Kevin Wolf , Eric Blake , Stefan Hajnoczi This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --TPTAgD1HA4G2Bm22LvR7GSqdvtekCHgk3 Content-Type: multipart/mixed; boundary="OIdU136CMTbEKVF4d2A4Uj6Hkxw4OJe8E" From: Max Reitz To: Alberto Garcia , qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, Kevin Wolf , Eric Blake , Stefan Hajnoczi Message-ID: <5720BFDB.60600@redhat.com> Subject: Re: [PATCH v9 07/11] block: Add QMP support for streaming to an intermediate layer References: In-Reply-To: --OIdU136CMTbEKVF4d2A4Uj6Hkxw4OJe8E Content-Type: text/plain; charset=iso-8859-15 Content-Transfer-Encoding: quoted-printable On 04.04.2016 15:43, Alberto Garcia wrote: > This patch makes the 'device' parameter of the 'block-stream' command > accept a node name as well as a device name. >=20 > In addition to that, operation blockers will be checked in all > intermediate nodes between the top and the base node. >=20 > Since qmp_block_stream() now uses the error from bdrv_lookup_bs() and > no longer returns DeviceNotFound, iotest 030 is updated to expect > GenericError instead. >=20 > Signed-off-by: Alberto Garcia > --- > blockdev.c | 31 +++++++++++++++++++++++-------- > qapi/block-core.json | 10 +++++++--- > tests/qemu-iotests/030 | 2 +- > 3 files changed, 31 insertions(+), 12 deletions(-) >=20 > diff --git a/blockdev.c b/blockdev.c > index 2e7712e..bfdc0e3 100644 > --- a/blockdev.c > +++ b/blockdev.c > @@ -2989,6 +2989,7 @@ void qmp_block_stream(const char *device, > BlockBackend *blk; > BlockDriverState *bs; > BlockDriverState *base_bs =3D NULL; > + BlockDriverState *active; > AioContext *aio_context; > Error *local_err =3D NULL; > const char *base_name =3D NULL; > @@ -2997,21 +2998,19 @@ void qmp_block_stream(const char *device, > on_error =3D BLOCKDEV_ON_ERROR_REPORT; > } > =20 > - blk =3D blk_by_name(device); > - if (!blk) { > - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, > - "Device '%s' not found", device); > + bs =3D bdrv_lookup_bs(device, device, errp); > + if (!bs) { > return; > } > =20 > - aio_context =3D blk_get_aio_context(blk); > + aio_context =3D bdrv_get_aio_context(bs); > aio_context_acquire(aio_context); > =20 > - if (!blk_is_available(blk)) { > + blk =3D blk_by_name(device); > + if (blk && !blk_is_available(blk)) { > error_setg(errp, "Device '%s' has no medium", device); > goto out; > } > - bs =3D blk_bs(blk); > =20 > if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_STREAM, errp)) { > goto out; > @@ -3027,6 +3026,22 @@ void qmp_block_stream(const char *device, > base_name =3D base; > } > =20 > + /* Look for the top-level node that contains 'bs' in its chain */ > + active =3D NULL; > + do { > + active =3D bdrv_next(active); > + } while (active && !bdrv_chain_contains(active, bs)); Alternatively, you could iterate up directly from @bs. Just look for the BdrvChild in bs->parents with .role =3D=3D &child_backing. More interesting question: What happens if you have e.g. a qcow2 file as a quorum child, and then want to stream inside of the qcow2 backing chain= ? So maybe you should first walk up along &child_backing and then along &child_file/&child_format. I think a generic bdrv_get_root_bs() wouldn't hurt. > + > + if (active =3D=3D NULL) { > + error_setg(errp, "Cannot find top level node for '%s'", device= ); > + goto out; > + } > + > + /* Check for op blockers in the top-level node too */ > + if (bdrv_op_is_blocked(active, BLOCK_OP_TYPE_STREAM, errp)) { > + goto out; > + } > + > /* if we are streaming the entire chain, the result will have no b= acking > * file, and specifying one is therefore an error */ > if (base_bs =3D=3D NULL && has_backing_file) { > @@ -3038,7 +3053,7 @@ void qmp_block_stream(const char *device, > /* backing_file string overrides base bs filename */ > base_name =3D has_backing_file ? backing_file : base_name; > =20 > - stream_start(bs, NULL, base_bs, base_name, has_speed ? speed : 0, > + stream_start(bs, active, base_bs, base_name, has_speed ? speed : 0= , stream_start() behaves differently for active =3D=3D NULL and active =3D=3D= bs. I think both kinds of behavior work, but it looks weird for active =3D=3D= bs. Should we pass NULL in that case instead? Max > on_error, block_job_cb, bs, &local_err); > if (local_err) { > error_propagate(errp, local_err); > diff --git a/qapi/block-core.json b/qapi/block-core.json > index 59107ed..e20193a 100644 > --- a/qapi/block-core.json > +++ b/qapi/block-core.json > @@ -1405,6 +1405,10 @@ > # with query-block-jobs. The operation can be stopped before it has c= ompleted > # using the block-job-cancel command. > # > +# The node that receives the data is called the top image, can be loca= ted > +# in any part of the whole chain and can be specified using its device= > +# or node name. > +# > # If a base file is specified then sectors are not copied from that ba= se file and > # its backing chain. When streaming completes the image file will hav= e the base > # file as its backing file. This can be used to stream a subset of th= e backing > @@ -1413,12 +1417,12 @@ > # On successful completion the image file is updated to drop the backi= ng file > # and the BLOCK_JOB_COMPLETED event is emitted. > # > -# @device: the device name > +# @device: the device or node name of the top image > # > # @base: #optional the common backing file name > # > -# @backing-file: #optional The backing file string to write into the a= ctive > -# layer. This filename is not validated. > +# @backing-file: #optional The backing file string to write into the t= op > +# image. This filename is not validated. > # > # If a pathname string is such that it cannot= be > # resolved by QEMU, that means that subsequen= t QMP or > diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 > index 3ac2443..107049b 100755 > --- a/tests/qemu-iotests/030 > +++ b/tests/qemu-iotests/030 > @@ -126,7 +126,7 @@ class TestSingleDrive(iotests.QMPTestCase): > =20 > def test_device_not_found(self): > result =3D self.vm.qmp('block-stream', device=3D'nonexistent')= > - self.assert_qmp(result, 'error/class', 'DeviceNotFound') > + self.assert_qmp(result, 'error/class', 'GenericError') > =20 > =20 > class TestSmallerBackingFile(iotests.QMPTestCase): >=20 --OIdU136CMTbEKVF4d2A4Uj6Hkxw4OJe8E-- --TPTAgD1HA4G2Bm22LvR7GSqdvtekCHgk3 Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAEBCAAGBQJXIL/bAAoJEDuxQgLoOKytpX8H/3DioQpd8OkWk6EDpFUy36gq xYoR7ELq/O/GvC3MJdTKB5/MirhPd299XN78gKhlCmOdbIBykeZeXIp1Wg3wSjkE s6xId3thZDmPULIGIB5kbDlST/n3OTiTPM7iorNIXLeWa97wQP8khP3q/G2YPdZ2 ar8PcMCOtfxbxSk8cDbgSsqWK1xT3kvQWfJzdeiE16N2Qg1M7cqeh+qKmnPWAuCa DmR7hMd5+dEEZ31wC/ud+AdtbX1FaUnoU98Olyx47J81Jv08pANSRkvPDlqnmHGS IstwiGUv9wbTNEYIojUerMsTs07kLnQg8DRSKu+kfqFlQWnfOWqb0QPA9/FhT3s= =3JT0 -----END PGP SIGNATURE----- --TPTAgD1HA4G2Bm22LvR7GSqdvtekCHgk3--