From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:47133) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QWvWd-0006IT-F5 for qemu-devel@nongnu.org; Wed, 15 Jun 2011 15:13:18 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QWvWV-0008BB-FZ for qemu-devel@nongnu.org; Wed, 15 Jun 2011 15:13:15 -0400 Received: from mail-qy0-f180.google.com ([209.85.216.180]:54302) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QWvWV-0008B1-1P for qemu-devel@nongnu.org; Wed, 15 Jun 2011 15:13:07 -0400 Received: by qyk10 with SMTP id 10so431867qyk.4 for ; Wed, 15 Jun 2011 12:13:06 -0700 (PDT) MIME-Version: 1.0 In-Reply-To: <4DF762A4.2040503@us.ibm.com> References: <4DF762A4.2040503@us.ibm.com> From: Blue Swirl Date: Wed, 15 Jun 2011 22:12:46 +0300 Message-ID: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [PATCH v2] Add support for fd: protocol List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Corey Bryant Cc: libvir-list@redhat.com, Anthony Liguori , qemu-devel@nongnu.org, Tyler C Hicks On Tue, Jun 14, 2011 at 4:31 PM, Corey Bryant wrote: > sVirt provides SELinux MAC isolation for Qemu guest processes and their > corresponding resources (image files). sVirt provides this support > by labeling guests and resources with security labels that are stored > in file system extended attributes. Some file systems, such as NFS, do > not support the extended attribute security namespace, which is needed > for image file isolation when using the sVirt SELinux security driver > in libvirt. > > The proposed solution entails a combination of Qemu, libvirt, and > SELinux patches that work together to isolate multiple guests' images > when they're stored in the same NFS mount. This results in an > environment where sVirt isolation and NFS image file isolation can both > be provided. > > This patch contains the Qemu code to support this solution. I would > like to solicit input from the libvirt community prior to starting > the libvirt patch. > > Currently, Qemu opens an image file in addition to performing the > necessary read and write operations. The proposed solution will move > the open out of Qemu and into libvirt. Once libvirt opens an image > file for the guest, it will pass the file descriptor to Qemu via a > new fd: protocol. > > If the image file resides in an NFS mount, the following SELinux policy > changes will provide image isolation: > > =C2=A0- A new SELinux boolean is created (e.g. virt_read_write_nfs) to > =C2=A0 =C2=A0allow Qemu (svirt_t) to only have SELinux read and write > =C2=A0 =C2=A0permissions on nfs_t files > > =C2=A0- Qemu (svirt_t) also gets SELinux use permissions on libvirt > =C2=A0 =C2=A0(virtd_t) file descriptors > > Following is a sample invocation of Qemu using the fd: protocol on > the command line: > > =C2=A0 =C2=A0qemu -drive file=3Dfd:4,format=3Dqcow2 > > The fd: protocol is also supported by the drive_add monitor command. > This requires that the specified file descriptor is passed to the > monitor alongside a prior getfd monitor command. > > There are some additional features provided by certain image types > where Qemu reopens the image file. All of these scenarios will be > unsupported for the fd: protocol, at least for this patch: > > =C2=A0- The -snapshot command line option > =C2=A0- The savevm monitor command > =C2=A0- The snapshot_blkdev monitor command > =C2=A0- Starting Qemu with a backing file There's also native CDROM device. Did you consider adding an explicit reopen method to block layer? > The thought is that this support can be added in the future, but is > not required for the initial fd: support. > > This patch was tested with the following formats: raw, cow, qcow, > qcow2, qed, and vmdk, using the fd: protocol from the command line > and the monitor. Tests were also run to verify existing file name > support and qemu-img were not regressed. Non-valid file descriptors, > fd: without format, snapshot and backing files were also tested. > > Signed-off-by: Corey Bryant > --- > =C2=A0block.c =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =C2=A0 16 ++++++++++ > =C2=A0block.h =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A01 + > =C2=A0block/cow.c =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A05 +++ > =C2=A0block/qcow.c =C2=A0 =C2=A0 =C2=A0| =C2=A0 =C2=A05 +++ > =C2=A0block/qcow2.c =C2=A0 =C2=A0 | =C2=A0 =C2=A05 +++ > =C2=A0block/qed.c =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A04 ++ > =C2=A0block/raw-posix.c | =C2=A0 81 +++++++++++++++++++++++++++++++++++++= ++++++++++------ > =C2=A0block/vmdk.c =C2=A0 =C2=A0 =C2=A0| =C2=A0 =C2=A05 +++ > =C2=A0block_int.h =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A01 + > =C2=A0blockdev.c =C2=A0 =C2=A0 =C2=A0 =C2=A0| =C2=A0 10 ++++++ > =C2=A0monitor.c =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A05 +++ > =C2=A0monitor.h =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A01 + > =C2=A0qemu-options.hx =C2=A0 | =C2=A0 =C2=A08 +++-- > =C2=A0qemu-tool.c =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A05 +++ > =C2=A014 files changed, 140 insertions(+), 12 deletions(-) > > diff --git a/block.c b/block.c > index 24a25d5..500db84 100644 > --- a/block.c > +++ b/block.c > @@ -536,6 +536,10 @@ int bdrv_open(BlockDriverState *bs, const char *file= name, int flags, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 char tmp_filename[PATH_MAX]; > =C2=A0 =C2=A0 =C2=A0 =C2=A0 char backing_filename[PATH_MAX]; > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (bdrv_is_fd_protocol(bs)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -ENOTSUP; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + > =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* if snapshot, we create a temporary backing= file and open it > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0instead of opening 'filename' di= rectly */ > > @@ -585,6 +589,10 @@ int bdrv_open(BlockDriverState *bs, const char *file= name, int flags, > > =C2=A0 =C2=A0 /* Find the right image format driver */ > =C2=A0 =C2=A0 if (!drv) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* format must be specified for fd: protocol= */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (bdrv_is_fd_protocol(bs)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -ENOTSUP; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D find_image_format(filename, &drv); > =C2=A0 =C2=A0 } > > @@ -1460,6 +1468,11 @@ int bdrv_enable_write_cache(BlockDriverState *bs) > =C2=A0 =C2=A0 return bs->enable_write_cache; > =C2=A0} > > +int bdrv_is_fd_protocol(BlockDriverState *bs) > +{ > + =C2=A0 =C2=A0return bs->fd_protocol; > +} > + > =C2=A0/* XXX: no longer used */ > =C2=A0void bdrv_set_change_cb(BlockDriverState *bs, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 void (*change_cb)(void *opaque, int reason), > @@ -1964,6 +1977,9 @@ int bdrv_snapshot_create(BlockDriverState *bs, > =C2=A0 =C2=A0 BlockDriver *drv =3D bs->drv; > =C2=A0 =C2=A0 if (!drv) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 return -ENOMEDIUM; > + =C2=A0 =C2=A0if (bdrv_is_fd_protocol(bs)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return -ENOTSUP; > + =C2=A0 =C2=A0} > =C2=A0 =C2=A0 if (drv->bdrv_snapshot_create) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 return drv->bdrv_snapshot_create(bs, sn_info)= ; > =C2=A0 =C2=A0 if (bs->file) > diff --git a/block.h b/block.h > index da7d39c..dd46d52 100644 > --- a/block.h > +++ b/block.h > @@ -182,6 +182,7 @@ int bdrv_is_removable(BlockDriverState *bs); > =C2=A0int bdrv_is_read_only(BlockDriverState *bs); > =C2=A0int bdrv_is_sg(BlockDriverState *bs); > =C2=A0int bdrv_enable_write_cache(BlockDriverState *bs); > +int bdrv_is_fd_protocol(BlockDriverState *bs); > =C2=A0int bdrv_is_inserted(BlockDriverState *bs); > =C2=A0int bdrv_media_changed(BlockDriverState *bs); > =C2=A0int bdrv_is_locked(BlockDriverState *bs); > diff --git a/block/cow.c b/block/cow.c > index 4cf543c..e17f8e7 100644 > --- a/block/cow.c > +++ b/block/cow.c > @@ -82,6 +82,11 @@ static int cow_open(BlockDriverState *bs, int flags) > =C2=A0 =C2=A0 pstrcpy(bs->backing_file, sizeof(bs->backing_file), > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 cow_header.backing_file); > > + =C2=A0 =C2=A0if (bs->backing_file[0] !=3D '\0' && bdrv_is_fd_protocol(b= s)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* backing file currently not supported by f= d: protocol */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0goto fail; > + =C2=A0 =C2=A0} > + > =C2=A0 =C2=A0 bitmap_size =3D ((bs->total_sectors + 7) >> 3) + sizeof(cow= _header); > =C2=A0 =C2=A0 s->cow_sectors_offset =3D (bitmap_size + 511) & ~511; > =C2=A0 =C2=A0 return 0; > diff --git a/block/qcow.c b/block/qcow.c > index a26c886..1e46bdb 100644 > --- a/block/qcow.c > +++ b/block/qcow.c > @@ -157,6 +157,11 @@ static int qcow_open(BlockDriverState *bs, int flags= ) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (bdrv_pread(bs->file, header.backing_file_= offset, bs->backing_file, len) !=3D len) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto fail; > =C2=A0 =C2=A0 =C2=A0 =C2=A0 bs->backing_file[len] =3D '\0'; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (bs->backing_file[0] !=3D '\0' && bdrv_is= _fd_protocol(bs)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* backing file currently not = supported by fd: protocol */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto fail; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > =C2=A0 =C2=A0 } > =C2=A0 =C2=A0 return 0; > > diff --git a/block/qcow2.c b/block/qcow2.c > index 8451ded..8b9c160 100644 > --- a/block/qcow2.c > +++ b/block/qcow2.c > @@ -270,6 +270,11 @@ static int qcow2_open(BlockDriverState *bs, int flag= s) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto fail; > =C2=A0 =C2=A0 =C2=A0 =C2=A0 } > =C2=A0 =C2=A0 =C2=A0 =C2=A0 bs->backing_file[len] =3D '\0'; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (bs->backing_file[0] !=3D '\0' && bdrv_is= _fd_protocol(bs)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D -ENOTSUP; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto fail; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > =C2=A0 =C2=A0 } > =C2=A0 =C2=A0 if (qcow2_read_snapshots(bs) < 0) { > =C2=A0 =C2=A0 =C2=A0 =C2=A0 ret =3D -EINVAL; > diff --git a/block/qed.c b/block/qed.c > index 3970379..5028897 100644 > --- a/block/qed.c > +++ b/block/qed.c > @@ -446,6 +446,10 @@ static int bdrv_qed_open(BlockDriverState *bs, int f= lags) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return ret; > =C2=A0 =C2=A0 =C2=A0 =C2=A0 } > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (bs->backing_file[0] !=3D '\0' && bdrv_is= _fd_protocol(bs)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -ENOTSUP; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + > =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (s->header.features & QED_F_BACKING_FORMAT= _NO_PROBE) { > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pstrcpy(bs->backing_format, siz= eof(bs->backing_format), "raw"); > =C2=A0 =C2=A0 =C2=A0 =C2=A0 } > diff --git a/block/raw-posix.c b/block/raw-posix.c > index 4cd7d7a..c72de3d 100644 > --- a/block/raw-posix.c > +++ b/block/raw-posix.c > @@ -28,6 +28,7 @@ > =C2=A0#include "block_int.h" > =C2=A0#include "module.h" > =C2=A0#include "block/raw-posix-aio.h" > +#include "monitor.h" > > =C2=A0#ifdef CONFIG_COCOA > =C2=A0#include > @@ -183,7 +184,8 @@ static int raw_open_common(BlockDriverState *bs, cons= t char *filename, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0int bdrv_flags, int open_flags) > =C2=A0{ > =C2=A0 =C2=A0 BDRVRawState *s =3D bs->opaque; > - =C2=A0 =C2=A0int fd, ret; > + =C2=A0 =C2=A0int fd =3D -1; > + =C2=A0 =C2=A0int ret; > > =C2=A0 =C2=A0 ret =3D raw_normalize_devicepath(&filename); > =C2=A0 =C2=A0 if (ret !=3D 0) { > @@ -205,15 +207,17 @@ static int raw_open_common(BlockDriverState *bs, co= nst char *filename, > =C2=A0 =C2=A0 if (!(bdrv_flags & BDRV_O_CACHE_WB)) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 s->open_flags |=3D O_DSYNC; > > - =C2=A0 =C2=A0s->fd =3D -1; > - =C2=A0 =C2=A0fd =3D qemu_open(filename, s->open_flags, 0644); > - =C2=A0 =C2=A0if (fd < 0) { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D -errno; > - =C2=A0 =C2=A0 =C2=A0 =C2=A0if (ret =3D=3D -EROFS) > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D -EACCES; > - =C2=A0 =C2=A0 =C2=A0 =C2=A0return ret; > + =C2=A0 =C2=A0if (s->fd =3D=3D -1) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0fd =3D qemu_open(filename, s->open_flags, 06= 44); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (fd < 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D -errno; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (ret =3D=3D -EROFS) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D -EACCES; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return ret; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0s->fd =3D fd; > =C2=A0 =C2=A0 } > - =C2=A0 =C2=A0s->fd =3D fd; > =C2=A0 =C2=A0 s->aligned_buf =3D NULL; > > =C2=A0 =C2=A0 if ((bdrv_flags & BDRV_O_NOCACHE)) { > @@ -270,6 +274,7 @@ static int raw_open(BlockDriverState *bs, const char = *filename, int flags) > =C2=A0{ > =C2=A0 =C2=A0 BDRVRawState *s =3D bs->opaque; > > + =C2=A0 =C2=A0s->fd =3D -1; > =C2=A0 =C2=A0 s->type =3D FTYPE_FILE; > =C2=A0 =C2=A0 return raw_open_common(bs, filename, flags, 0); > =C2=A0} > @@ -890,6 +895,60 @@ static BlockDriver bdrv_file =3D { > =C2=A0 =C2=A0 .create_options =3D raw_create_options, > =C2=A0}; > > +static int raw_open_fd(BlockDriverState *bs, const char *filename, int f= lags) > +{ > + =C2=A0 =C2=A0BDRVRawState *s =3D bs->opaque; > + =C2=A0 =C2=A0const char *fd_str; > + =C2=A0 =C2=A0int fd; > + > + =C2=A0 =C2=A0/* extract the file descriptor - fail if it's not fd: */ > + =C2=A0 =C2=A0if (!strstart(filename, "fd:", &fd_str)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return -EINVAL; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0if (!qemu_isdigit(fd_str[0])) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* get fd from monitor */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0fd =3D qemu_get_fd(fd_str); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (fd =3D=3D -1) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -EBADF; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0char *endptr =3D NULL; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0fd =3D strtol(fd_str, &endptr, 10); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (*endptr || (fd =3D=3D 0 && fd_str =3D=3D= endptr)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -EBADF; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0s->fd =3D fd; > + =C2=A0 =C2=A0s->type =3D FTYPE_FILE; > + > + =C2=A0 =C2=A0return raw_open_common(bs, filename, flags, 0); > +} > + > +static BlockDriver bdrv_file_fd =3D { > + =C2=A0 =C2=A0.format_name =3D "file", > + =C2=A0 =C2=A0.protocol_name =3D "fd", > + =C2=A0 =C2=A0.instance_size =3D sizeof(BDRVRawState), > + =C2=A0 =C2=A0.bdrv_probe =3D NULL, /* no probe for protocols */ > + =C2=A0 =C2=A0.bdrv_file_open =3D raw_open_fd, > + =C2=A0 =C2=A0.bdrv_read =3D raw_read, > + =C2=A0 =C2=A0.bdrv_write =3D raw_write, > + =C2=A0 =C2=A0.bdrv_close =3D raw_close, > + =C2=A0 =C2=A0.bdrv_flush =3D raw_flush, > + =C2=A0 =C2=A0.bdrv_discard =3D raw_discard, > + > + =C2=A0 =C2=A0.bdrv_aio_readv =3D raw_aio_readv, > + =C2=A0 =C2=A0.bdrv_aio_writev =3D raw_aio_writev, > + =C2=A0 =C2=A0.bdrv_aio_flush =3D raw_aio_flush, > + > + =C2=A0 =C2=A0.bdrv_truncate =3D raw_truncate, > + =C2=A0 =C2=A0.bdrv_getlength =3D raw_getlength, > + > + =C2=A0 =C2=A0.create_options =3D raw_create_options, > +}; > + > =C2=A0/***********************************************/ > =C2=A0/* host device */ > > @@ -998,6 +1057,7 @@ static int hdev_open(BlockDriverState *bs, const cha= r *filename, int flags) > =C2=A0 =C2=A0 } > =C2=A0#endif > > + =C2=A0 =C2=A0s->fd =3D -1; > =C2=A0 =C2=A0 s->type =3D FTYPE_FILE; > =C2=A0#if defined(__linux__) > =C2=A0 =C2=A0 { > @@ -1168,6 +1228,7 @@ static int floppy_open(BlockDriverState *bs, const = char *filename, int flags) > =C2=A0 =C2=A0 BDRVRawState *s =3D bs->opaque; > =C2=A0 =C2=A0 int ret; > > + =C2=A0 =C2=A0s->fd =3D -1; > =C2=A0 =C2=A0 s->type =3D FTYPE_FD; > > =C2=A0 =C2=A0 /* open will not fail even if no floppy is inserted, so add= O_NONBLOCK */ > @@ -1280,6 +1341,7 @@ static int cdrom_open(BlockDriverState *bs, const c= har *filename, int flags) > =C2=A0{ > =C2=A0 =C2=A0 BDRVRawState *s =3D bs->opaque; > > + =C2=A0 =C2=A0s->fd =3D -1; > =C2=A0 =C2=A0 s->type =3D FTYPE_CD; > > =C2=A0 =C2=A0 /* open will not fail even if no CD is inserted, so add O_N= ONBLOCK */ > @@ -1503,6 +1565,7 @@ static void bdrv_file_init(void) > =C2=A0 =C2=A0 =C2=A0* Register all the drivers. =C2=A0Note that order is = important, the driver > =C2=A0 =C2=A0 =C2=A0* registered last will get probed first. > =C2=A0 =C2=A0 =C2=A0*/ > + =C2=A0 =C2=A0bdrv_register(&bdrv_file_fd); > =C2=A0 =C2=A0 bdrv_register(&bdrv_file); > =C2=A0 =C2=A0 bdrv_register(&bdrv_host_device); > =C2=A0#ifdef __linux__ > diff --git a/block/vmdk.c b/block/vmdk.c > index 922b23d..2ea808e 100644 > --- a/block/vmdk.c > +++ b/block/vmdk.c > @@ -353,6 +353,11 @@ static int vmdk_parent_open(BlockDriverState *bs) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return -1; > > =C2=A0 =C2=A0 =C2=A0 =C2=A0 pstrcpy(bs->backing_file, end_name - p_name += 1, p_name); > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (bs->backing_file[0] !=3D '\0' && bdrv_is= _fd_protocol(bs)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* backing file currently not = supported by fd: protocol */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -1; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > =C2=A0 =C2=A0 } > > =C2=A0 =C2=A0 return 0; > diff --git a/block_int.h b/block_int.h > index fa91337..a305ee2 100644 > --- a/block_int.h > +++ b/block_int.h > @@ -152,6 +152,7 @@ struct BlockDriverState { > =C2=A0 =C2=A0 int encrypted; /* if true, the media is encrypted */ > =C2=A0 =C2=A0 int valid_key; /* if true, a valid encryption key has been = set */ > =C2=A0 =C2=A0 int sg; =C2=A0 =C2=A0 =C2=A0 =C2=A0/* if true, the device i= s a /dev/sg* */ > + =C2=A0 =C2=A0int fd_protocol; /* if true, the fd: protocol was specifie= d */ bool? > =C2=A0 =C2=A0 /* event callback when inserting/removing */ > =C2=A0 =C2=A0 void (*change_cb)(void *opaque, int reason); > =C2=A0 =C2=A0 void *change_opaque; > diff --git a/blockdev.c b/blockdev.c > index e81e0ab..a536c20 100644 > --- a/blockdev.c > +++ b/blockdev.c > @@ -546,6 +546,10 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to= _scsi) > > =C2=A0 =C2=A0 bdrv_flags |=3D ro ? 0 : BDRV_O_RDWR; > > + =C2=A0 =C2=A0if (strncmp(file, "fd:", 3) =3D=3D 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0dinfo->bdrv->fd_protocol =3D 1; > + =C2=A0 =C2=A0} > + > =C2=A0 =C2=A0 ret =3D bdrv_open(dinfo->bdrv, file, bdrv_flags, drv); > =C2=A0 =C2=A0 if (ret < 0) { > =C2=A0 =C2=A0 =C2=A0 =C2=A0 error_report("could not open disk image %s: %= s", > @@ -606,6 +610,12 @@ int do_snapshot_blkdev(Monitor *mon, const QDict *qd= ict, QObject **ret_data) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto out; > =C2=A0 =C2=A0 } > > + =C2=A0 =C2=A0if (bdrv_is_fd_protocol(bs)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0qerror_report(QERR_UNSUPPORTED); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D -1; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0goto out; > + =C2=A0 =C2=A0} > + > =C2=A0 =C2=A0 pstrcpy(old_filename, sizeof(old_filename), bs->filename); > > =C2=A0 =C2=A0 old_drv =3D bs->drv; > diff --git a/monitor.c b/monitor.c > index 59a3e76..ea60be2 100644 > --- a/monitor.c > +++ b/monitor.c > @@ -2832,6 +2832,11 @@ int monitor_get_fd(Monitor *mon, const char *fdnam= e) > =C2=A0 =C2=A0 return -1; > =C2=A0} > > +int qemu_get_fd(const char *fdname) > +{ > + =C2=A0 =C2=A0return cur_mon ? monitor_get_fd(cur_mon, fdname) : -1; > +} > + > =C2=A0static const mon_cmd_t mon_cmds[] =3D { > =C2=A0#include "hmp-commands.h" > =C2=A0 =C2=A0 { NULL, NULL, }, > diff --git a/monitor.h b/monitor.h > index 4f2d328..de5b987 100644 > --- a/monitor.h > +++ b/monitor.h > @@ -51,6 +51,7 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriv= erState *bs, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void *opaque); > > =C2=A0int monitor_get_fd(Monitor *mon, const char *fdname); > +int qemu_get_fd(const char *fdname); > > =C2=A0void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) > =C2=A0 =C2=A0 GCC_FMT_ATTR(2, 0); > diff --git a/qemu-options.hx b/qemu-options.hx > index 1d5ad8b..f9b66f4 100644 > --- a/qemu-options.hx > +++ b/qemu-options.hx > @@ -116,7 +116,7 @@ using @file{/dev/cdrom} as filename (@pxref{host_driv= es}). > =C2=A0ETEXI > > =C2=A0DEF("drive", HAS_ARG, QEMU_OPTION_drive, > - =C2=A0 =C2=A0"-drive [file=3Dfile][,if=3Dtype][,bus=3Dn][,unit=3Dm][,me= dia=3Dd][,index=3Di]\n" > + =C2=A0 =C2=A0"-drive [file=3D[fd:]file][,if=3Dtype][,bus=3Dn][,unit=3Dm= ][,media=3Dd][,index=3Di]\n" > =C2=A0 =C2=A0 " =C2=A0 =C2=A0 =C2=A0 [,cyls=3Dc,heads=3Dh,secs=3Ds[,trans= =3Dt]][,snapshot=3Don|off]\n" > =C2=A0 =C2=A0 " =C2=A0 =C2=A0 =C2=A0 [,cache=3Dwritethrough|writeback|non= e|unsafe][,format=3Df]\n" > =C2=A0 =C2=A0 " =C2=A0 =C2=A0 =C2=A0 [,serial=3Ds][,addr=3DA][,id=3Dname]= [,aio=3Dthreads|native]\n" > @@ -129,10 +129,12 @@ STEXI > =C2=A0Define a new drive. Valid options are: > > =C2=A0@table @option > -@item file=3D@var{file} > +@item file=3D[fd:]@var{file} > =C2=A0This option defines which disk image (@pxref{disk_images}) to use w= ith > =C2=A0this drive. If the filename contains comma, you must double it > -(for instance, "file=3Dmy,,file" to use file "my,file"). > +(for instance, "file=3Dmy,,file" to use file "my,file"). @option{fd:}@va= r{file} > +specifies the file descriptor of an already open disk image. > +@option{format=3D}@var{format} is required by @option{fd:}@var{file}. > =C2=A0@item if=3D@var{interface} > =C2=A0This option defines on which type on interface the drive is connect= ed. > =C2=A0Available types are: ide, scsi, sd, mtd, floppy, pflash, virtio. > diff --git a/qemu-tool.c b/qemu-tool.c > index 41e5c41..8fe6b8c 100644 > --- a/qemu-tool.c > +++ b/qemu-tool.c > @@ -96,3 +96,8 @@ int64_t qemu_get_clock_ns(QEMUClock *clock) > =C2=A0{ > =C2=A0 =C2=A0 return 0; > =C2=A0} > + > +int qemu_get_fd(const char *fdname) > +{ > + =C2=A0 =C2=A0return -1; > +} > -- > 1.7.1 > > >