> 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<coreyb@xxxxxxxxxxxxxxxxxx>
> ---
> block.c | 16 ++++++++++
> block.h | 1 +
> block/cow.c | 5 +++
> block/qcow.c | 5 +++
> block/qcow2.c | 5 +++
> block/qed.c | 4 ++
> block/raw-posix.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++------
> block/vmdk.c | 5 +++
> block_int.h | 1 +
> blockdev.c | 10 ++++++
> monitor.c | 5 +++
> monitor.h | 1 +
> qemu-options.hx | 8 +++--
> qemu-tool.c | 5 +++
> 14 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 *filename, int flags,
> char tmp_filename[PATH_MAX];
> char backing_filename[PATH_MAX];
>
> + if (bdrv_is_fd_protocol(bs)) {
> + return -ENOTSUP;
> + }
> +
> /* if snapshot, we create a temporary backing file and open it
> instead of opening 'filename' directly */
>
> @@ -585,6 +589,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
>
> /* Find the right image format driver */
> if (!drv) {
> + /* format must be specified for fd: protocol */
> + if (bdrv_is_fd_protocol(bs)) {
> + return -ENOTSUP;
> + }
> ret = find_image_format(filename,&drv);
> }
>
> @@ -1460,6 +1468,11 @@ int bdrv_enable_write_cache(BlockDriverState *bs)
> return bs->enable_write_cache;
> }
>
> +int bdrv_is_fd_protocol(BlockDriverState *bs)
> +{
> + return bs->fd_protocol;
> +}
> +
> /* XXX: no longer used */
> void bdrv_set_change_cb(BlockDriverState *bs,
> void (*change_cb)(void *opaque, int reason),
> @@ -1964,6 +1977,9 @@ int bdrv_snapshot_create(BlockDriverState *bs,
> BlockDriver *drv = bs->drv;
> if (!drv)
> return -ENOMEDIUM;
> + if (bdrv_is_fd_protocol(bs)) {
> + return -ENOTSUP;
> + }
> if (drv->bdrv_snapshot_create)
> return drv->bdrv_snapshot_create(bs, sn_info);
> 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);
> int bdrv_is_read_only(BlockDriverState *bs);
> int bdrv_is_sg(BlockDriverState *bs);
> int bdrv_enable_write_cache(BlockDriverState *bs);
> +int bdrv_is_fd_protocol(BlockDriverState *bs);
> int bdrv_is_inserted(BlockDriverState *bs);
> int bdrv_media_changed(BlockDriverState *bs);
> int 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)
> pstrcpy(bs->backing_file, sizeof(bs->backing_file),
> cow_header.backing_file);
>
> + if (bs->backing_file[0] != '\0'&& bdrv_is_fd_protocol(bs)) {
> + /* backing file currently not supported by fd: protocol */
> + goto fail;
> + }
> +
> bitmap_size = ((bs->total_sectors + 7)>> 3) + sizeof(cow_header);
> s->cow_sectors_offset = (bitmap_size + 511)& ~511;
> 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)
> if (bdrv_pread(bs->file, header.backing_file_offset, bs->backing_file, len) != len)
> goto fail;
> bs->backing_file[len] = '\0';
> +
> + if (bs->backing_file[0] != '\0'&& bdrv_is_fd_protocol(bs)) {
> + /* backing file currently not supported by fd: protocol */
> + goto fail;
> + }
> }
> 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 flags)
> goto fail;
> }
> bs->backing_file[len] = '\0';
> +
> + if (bs->backing_file[0] != '\0'&& bdrv_is_fd_protocol(bs)) {
> + ret = -ENOTSUP;
> + goto fail;
> + }
> }
> if (qcow2_read_snapshots(bs)< 0) {
> ret = -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 flags)
> return ret;
> }
>
> + if (bs->backing_file[0] != '\0'&& bdrv_is_fd_protocol(bs)) {
> + return -ENOTSUP;
> + }
> +
> if (s->header.features& QED_F_BACKING_FORMAT_NO_PROBE) {
> pstrcpy(bs->backing_format, sizeof(bs->backing_format), "raw");
> }
> 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 @@
> #include "block_int.h"
> #include "module.h"
> #include "block/raw-posix-aio.h"
> +#include "monitor.h"
>
> #ifdef CONFIG_COCOA
> #include<paths.h>
> @@ -183,7 +184,8 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
> int bdrv_flags, int open_flags)
> {
> BDRVRawState *s = bs->opaque;
> - int fd, ret;
> + int fd = -1;
> + int ret;
>
> ret = raw_normalize_devicepath(&filename);
> if (ret != 0) {
> @@ -205,15 +207,17 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
> if (!(bdrv_flags& BDRV_O_CACHE_WB))
> s->open_flags |= O_DSYNC;
>
> - s->fd = -1;
> - fd = qemu_open(filename, s->open_flags, 0644);
> - if (fd< 0) {
> - ret = -errno;
> - if (ret == -EROFS)
> - ret = -EACCES;
> - return ret;
> + if (s->fd == -1) {
> + fd = qemu_open(filename, s->open_flags, 0644);
> + if (fd< 0) {
> + ret = -errno;
> + if (ret == -EROFS) {
> + ret = -EACCES;
> + }
> + return ret;
> + }
> + s->fd = fd;
> }
> - s->fd = fd;
> s->aligned_buf = NULL;
>
> if ((bdrv_flags& BDRV_O_NOCACHE)) {
> @@ -270,6 +274,7 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
> {
> BDRVRawState *s = bs->opaque;
>
> + s->fd = -1;
> s->type = FTYPE_FILE;
> return raw_open_common(bs, filename, flags, 0);
> }
> @@ -890,6 +895,60 @@ static BlockDriver bdrv_file = {
> .create_options = raw_create_options,
> };
>
> +static int raw_open_fd(BlockDriverState *bs, const char *filename, int flags)
> +{
> + BDRVRawState *s = bs->opaque;
> + const char *fd_str;
> + int fd;
> +
> + /* extract the file descriptor - fail if it's not fd: */
> + if (!strstart(filename, "fd:",&fd_str)) {
> + return -EINVAL;
> + }
> +
> + if (!qemu_isdigit(fd_str[0])) {
> + /* get fd from monitor */
> + fd = qemu_get_fd(fd_str);
> + if (fd == -1) {
> + return -EBADF;
> + }
> + } else {
> + char *endptr = NULL;
> +
> + fd = strtol(fd_str,&endptr, 10);
> + if (*endptr || (fd == 0&& fd_str == endptr)) {
> + return -EBADF;
> + }
> + }
> +
> + s->fd = fd;
> + s->type = FTYPE_FILE;
> +
> + return raw_open_common(bs, filename, flags, 0);
> +}
> +
> +static BlockDriver bdrv_file_fd = {
> + .format_name = "file",
> + .protocol_name = "fd",
> + .instance_size = sizeof(BDRVRawState),
> + .bdrv_probe = NULL, /* no probe for protocols */
> + .bdrv_file_open = raw_open_fd,
> + .bdrv_read = raw_read,
> + .bdrv_write = raw_write,
> + .bdrv_close = raw_close,
> + .bdrv_flush = raw_flush,
> + .bdrv_discard = raw_discard,
> +
> + .bdrv_aio_readv = raw_aio_readv,
> + .bdrv_aio_writev = raw_aio_writev,
> + .bdrv_aio_flush = raw_aio_flush,
> +
> + .bdrv_truncate = raw_truncate,
> + .bdrv_getlength = raw_getlength,
> +
> + .create_options = raw_create_options,
> +};
> +
> /***********************************************/
> /* host device */
>
> @@ -998,6 +1057,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
> }
> #endif
>
> + s->fd = -1;
> s->type = FTYPE_FILE;
> #if defined(__linux__)
> {
> @@ -1168,6 +1228,7 @@ static int floppy_open(BlockDriverState *bs, const char *filename, int flags)
> BDRVRawState *s = bs->opaque;
> int ret;
>
> + s->fd = -1;
> s->type = FTYPE_FD;
>
> /* 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 char *filename, int flags)
> {
> BDRVRawState *s = bs->opaque;
>
> + s->fd = -1;
> s->type = FTYPE_CD;
>
> /* open will not fail even if no CD is inserted, so add O_NONBLOCK */
> @@ -1503,6 +1565,7 @@ static void bdrv_file_init(void)
> * Register all the drivers. Note that order is important, the driver
> * registered last will get probed first.
> */
> + bdrv_register(&bdrv_file_fd);
> bdrv_register(&bdrv_file);
> bdrv_register(&bdrv_host_device);
> #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)
> return -1;
>
> pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
> +
> + if (bs->backing_file[0] != '\0'&& bdrv_is_fd_protocol(bs)) {
> + /* backing file currently not supported by fd: protocol */
> + return -1;
> + }
> }
>
> 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 {
> int encrypted; /* if true, the media is encrypted */
> int valid_key; /* if true, a valid encryption key has been set */
> int sg; /* if true, the device is a /dev/sg* */
> + int fd_protocol; /* if true, the fd: protocol was specified */