When an fd, and optionally opaque, are passed with -drive, they
are added to an automatically generated fd set. The file name
is also generated in the form of "/dev/fdset/nnn", where nnn is
the fd set ID. qemu_open() already knows how to handle a
filename of this format. qemu_open() searches the corresponding
fd set for an fd and when it finds a match, QEMU goes on to use a
dup of that fd just like it would have used an fd that it opened
itself.
Signed-off-by: Corey Bryant <coreyb(a)linux.vnet.ibm.com>
---
blockdev.c | 40 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 5f18dfa..cf348c6 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -281,6 +281,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
const char *file = NULL;
const char *serial;
const char *mediastr = "";
+ const char *opaque = NULL;
BlockInterfaceType type;
enum { MEDIA_DISK, MEDIA_CDROM } media;
int bus_id, unit_id;
@@ -297,6 +298,10 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
int snapshot = 0;
bool copy_on_read;
int ret;
+ int fd;
+ char filename[32];
+ AddfdInfo *fdinfo = NULL;
+ Error *errp = NULL;
translation = BIOS_ATA_TRANSLATION_AUTO;
media = MEDIA_DISK;
@@ -315,6 +320,8 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
copy_on_read = qemu_opt_get_bool(opts, "copy-on-read", false);
file = qemu_opt_get(opts, "file");
+ fd = qemu_opt_get_number(opts, "fd", -1);
+ opaque = qemu_opt_get(opts, "opaque");
serial = qemu_opt_get(opts, "serial");
if ((buf = qemu_opt_get(opts, "if")) != NULL) {
@@ -575,9 +582,35 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
default:
abort();
}
- if (!file || !*file) {
- return dinfo;
+
+ if (file && fd != -1) {
+ error_report("file cannot be used with fd");
+ goto err;
+ }
+
+ if (opaque && fd == -1) {
+ error_report("opaque cannot be specified without fd");
+ goto err;
+ }
+
+ if ((!file || !*file)) {
+ if (fd != -1) {
+ /* add the fd, and optionally opaque, to an fd set */
+ fdinfo = monitor_fdset_add_fd(fd, false, -1, opaque ? true : false,
+ opaque, &errp);
+ if (fdinfo == NULL) {
+ goto err;
+ }
+
+ /* set file name to /dev/fdset/nnn */
+ snprintf(filename, sizeof(filename), "/dev/fdset/%" PRId64,
+ fdinfo->fdset_id);
+ file = filename;
+ } else {
+ return dinfo;
+ }
}
+
if (snapshot) {
/* always use cache=unsafe with snapshot */
bdrv_flags &= ~BDRV_O_CACHE_MASK;
@@ -625,6 +658,9 @@ err:
g_free(dinfo->id);
QTAILQ_REMOVE(&drives, dinfo, next);
g_free(dinfo);
+ if (fdinfo) {
+ qmp_remove_fd(fdinfo->fdset_id, true, fdinfo->fd, &errp);
+ }
return NULL;
}
--
1.7.11.4