Skip to contentSkip to conversation

Shared CD-Rom Support

PATCH New Ben Guthro 1 participant 1 message Aug 28, 2007

lore
Share & tools
lore

Ben Guthro

author
#0 lore raw

PATCH 1/1 Shared CD-Rom Support

This patch adds a QEMU monitor command may switch the domain owning the physical cdrom, such that an eject command on the guest command line will physically eject the drive door.

Monitor command example:
set_cdrom_owner 1 hdd
(for the time being the "hdd" parameter is a constant, as we only support a singular CD-Rom)

NOTE: This was also submitted to the Xen list, with a couple additional xen-specific changes, that are not necessarily applicable here (xenstore entries, etc)

block.c +83 -4
diff -r 106bc46793ca block.c
@@ -56,6 +56,8 @@ static BlockDriverState *bdrv_first;
 static BlockDriverState *bdrv_first;
 static BlockDriver *first_drv;
 
+static BlockDriver *get_bdrv_raw(void);
+
 int path_is_absolute(const char *path)
 {
     const char *p;
@@ -323,6 +325,7 @@ int bdrv_open2(BlockDriverState *bs, con
 {
     int ret, open_flags;
     char tmp_filename[PATH_MAX];
+    int is_media_inserted;
     char backing_filename[PATH_MAX];
     
     bs->read_only = 0;
@@ -359,6 +362,10 @@ int bdrv_open2(BlockDriverState *bs, con
     }
 
     pstrcpy(bs->filename, sizeof(bs->filename), filename);
+    if (bs->type == BDRV_TYPE_CDROM && !drv && bs->is_shared) {
+        drv = get_bdrv_raw();
+    }else{
+
     if (flags & BDRV_O_FILE) {
         drv = find_protocol(filename);
         if (!drv)
@@ -370,16 +377,27 @@ int bdrv_open2(BlockDriverState *bs, con
                 return -1;
         }
     }
+
+    }
     bs->drv = drv;
     bs->opaque = qemu_mallocz(drv->instance_size);
     if (bs->opaque == NULL && drv->instance_size > 0)
         return -1;
+    is_media_inserted = 1;
     /* Note: for compatibility, we open disk image files as RDWR, and
        RDONLY as fallback */
     if (!(flags & BDRV_O_FILE))
         open_flags = BDRV_O_RDWR;
     else
         open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
+
+    if (bs->type == BDRV_TYPE_CDROM && bs->is_shared) {
+        if (!bs->is_owner) {
+            bs->total_sectors = 0;
+            return ENOMEDIUM;
+        }
+    }
+
     ret = drv->bdrv_open(bs, filename, open_flags);
     if (ret == -EACCES && !(flags & BDRV_O_FILE)) {
         ret = drv->bdrv_open(bs, filename, BDRV_O_RDONLY);
@@ -391,6 +409,20 @@ int bdrv_open2(BlockDriverState *bs, con
         bs->drv = NULL;
         return ret;
     }
+
+    if (bs->type == BDRV_TYPE_CDROM && ret < 1) {
+        if (!bs->is_owner) {
+            bs->total_sectors = 0;
+            if (errno == ENOMEDIUM )
+                return ENOMEDIUM;
+            else
+                return -1;
+        }
+    }
+
+    if (bs->type == BDRV_TYPE_CDROM && ret == ENOMEDIUM)
+        is_media_inserted = 0;
+
     if (drv->bdrv_getlength) {
         bs->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
     }
@@ -413,8 +445,12 @@ int bdrv_open2(BlockDriverState *bs, con
             goto fail;
     }
 
+    if (is_media_inserted)
+        bs->media_changed = 1;
+    else
+        bs->media_changed = 0;
+
     /* call the change callback */
-    bs->media_changed = 1;
     if (bs->change_cb)
         bs->change_cb(bs->change_opaque);
 
@@ -427,19 +463,20 @@ void bdrv_close(BlockDriverState *bs)
         if (bs->backing_hd)
             bdrv_delete(bs->backing_hd);
         bs->drv->bdrv_close(bs);
-        qemu_free(bs->opaque);
+        bs->drv = NULL;
 #ifdef _WIN32
         if (bs->is_temporary) {
             unlink(bs->filename);
         }
 #endif
-        bs->opaque = NULL;
-        bs->drv = NULL;
 
         /* call the change callback */
         bs->media_changed = 1;
         if (bs->change_cb)
             bs->change_cb(bs->change_opaque);
+ 
+        qemu_free(bs->opaque);
+        bs->opaque = NULL;
     }
 }
 
@@ -749,6 +786,28 @@ void bdrv_set_translation_hint(BlockDriv
     bs->translation = translation;
 }
 
+void bdrv_set_shared_owner_hint(BlockDriverState *bs, int is_owner)
+{
+    bs->is_shared = 1;
+    bs->is_owner = is_owner;
+}
+
+void bdrv_change_shared_owner(BlockDriverState *bs, int new_owner_state)
+{
+    if (!bs->is_shared)
+        return;
+
+    if (bs->is_owner == new_owner_state)
+        return;
+
+    bs->is_owner = new_owner_state;
+
+    if (!new_owner_state) {
+        bdrv_close(bs);
+        return;
+    }
+}
+
 void bdrv_get_geometry_hint(BlockDriverState *bs, 
                             int *pcyls, int *pheads, int *psecs)
 {
@@ -765,6 +824,16 @@ int bdrv_get_translation_hint(BlockDrive
 int bdrv_get_translation_hint(BlockDriverState *bs)
 {
     return bs->translation;
+}
+
+int bdrv_is_shared(BlockDriverState *bs)
+{
+    return bs->is_shared;
+}
+
+int bdrv_is_owner(BlockDriverState *bs)
+{
+    return bs->is_owner;
 }
 
 int bdrv_is_removable(BlockDriverState *bs)
@@ -849,6 +918,11 @@ const char *bdrv_get_device_name(BlockDr
 const char *bdrv_get_device_name(BlockDriverState *bs)
 {
     return bs->device_name;
+}
+
+const char *bdrv_get_filename(BlockDriverState *bs)
+{
+    return bs->filename;
 }
 
 void bdrv_flush(BlockDriverState *bs)
@@ -1226,6 +1300,11 @@ static int bdrv_write_em(BlockDriverStat
     return async_ret;
 }
 
+static BlockDriver *get_bdrv_raw(void)
+{
+    return &bdrv_raw ;
+}
+
 void bdrv_init(void)
 {
     bdrv_register(&bdrv_raw);
block_int.h +2 -0
diff -r 106bc46793ca block_int.h
@@ -87,6 +87,8 @@ struct BlockDriverState {
     int removable; /* if true, the media can be removed */
     int locked;    /* if true, the media cannot temporarily be ejected */
     int encrypted; /* if true, the media is encrypted */
+    int is_shared; /* if true, the media is shared across multiple QEMU instances */
+    int is_owner;  /* if true, the media is sharable and currently owned by this QEMU instance */
     /* event callback when inserting/removing */
     void (*change_cb)(void *opaque);
     void *change_opaque;
hw/ide.c +212 -2

275 lines not on this page · raw message

monitor.c +36 -0
diff -r 106bc46793ca monitor.c
@@ -192,6 +192,40 @@ static void help_cmd(const char *name)
             }
         }
     }
+}
+
+static void do_set_cdrom_owner(const char* new_owner_state_cstr, const char *device)
+{
+    BlockDriverState *bs;
+    int new_owner_state;
+
+    if (!new_owner_state_cstr || !device) {
+        term_printf("[set_cdrom_owner] ERROR : insufficient args (NULL) !?!\n");
+        return;
+    }
+
+    if (sscanf(new_owner_state_cstr, "%d", &new_owner_state) != 1) {
+        term_printf("[set_cdrom_owner] ERROR : bad arg '%s'\n", new_owner_state_cstr);
+        return;
+    }
+
+    if (new_owner_state)    // normalize given input
+        new_owner_state = 1;
+
+    bs = bdrv_find(device);
+    if (!bs) {
+        term_printf("[set_cdrom_owner] ERROR : cdrom device '%s' not found %d\n", device, new_owner_state);
+        return;
+    }
+
+    if (bdrv_is_owner(bs) == new_owner_state) {
+        term_printf("[set_cdrom_owner] IGNORED : no change to ownership %d\n", new_owner_state);
+        return;
+    }
+
+    bdrv_change_shared_owner(bs, new_owner_state);
+
+    term_printf("[set_cdrom_owner] done : (%d)\n", new_owner_state);
 }
 
 static void do_help(const char *name)
@@ -1250,6 +1284,8 @@ static term_cmd_t term_cmds[] = {
       "tag|id", "save a VM snapshot. If no tag or id are provided, a new snapshot is created" }, 
     { "loadvm", "s", do_loadvm,
       "tag|id", "restore a VM snapshot from its tag or id" }, 
+    { "set_cdrom_owner", "sB", do_set_cdrom_owner,
+      "<1|0> device", "1 to become the owner and acquire the physical drive or 0 to release it and no longer be the owner" },
     { "delvm", "s", do_delvm,
       "tag|id", "delete a VM snapshot from its tag or id" }, 
     { "stop", "", do_stop, 
vl.c +5 -0
diff -r 106bc46793ca vl.c
@@ -7110,6 +7110,7 @@ enum {
     QEMU_OPTION_hdc,
     QEMU_OPTION_hdd,
     QEMU_OPTION_cdrom,
+    QEMU_OPTION_cdrom_shared_with_eject,
     QEMU_OPTION_mtdblock,
     QEMU_OPTION_sd,
     QEMU_OPTION_pflash,
@@ -7197,6 +7198,7 @@ const QEMUOption qemu_options[] = {
     { "hdc", HAS_ARG, QEMU_OPTION_hdc },
     { "hdd", HAS_ARG, QEMU_OPTION_hdd },
     { "cdrom", HAS_ARG, QEMU_OPTION_cdrom },
+    { "cdrom-shared-with-eject", 0, QEMU_OPTION_cdrom_shared_with_eject },
     { "mtdblock", HAS_ARG, QEMU_OPTION_mtdblock },
     { "sd", HAS_ARG, QEMU_OPTION_sd },
     { "pflash", HAS_ARG, QEMU_OPTION_pflash },
@@ -7778,6 +7780,9 @@ int main(int argc, char **argv)
                     hd_filename[cdrom_index] = optarg;
                 }
                 break;
+            case QEMU_OPTION_cdrom_shared_with_eject:
+               // XXX Temporarily ignore this option
+               break;
             case QEMU_OPTION_boot:
                 boot_device = optarg[0];
                 if (boot_device != 'a' && 
vl.h +5 -0
diff -r 106bc46793ca vl.h
@@ -661,10 +661,14 @@ void bdrv_set_geometry_hint(BlockDriverS
                             int cyls, int heads, int secs);
 void bdrv_set_type_hint(BlockDriverState *bs, int type);
 void bdrv_set_translation_hint(BlockDriverState *bs, int translation);
+void bdrv_set_shared_owner_hint(BlockDriverState *bs, int is_owner);
+void bdrv_change_shared_owner(BlockDriverState *bs, int new_owner_state);
 void bdrv_get_geometry_hint(BlockDriverState *bs, 
                             int *pcyls, int *pheads, int *psecs);
 int bdrv_get_type_hint(BlockDriverState *bs);
 int bdrv_get_translation_hint(BlockDriverState *bs);
+int bdrv_is_shared(BlockDriverState *bs);
+int bdrv_is_owner(BlockDriverState *bs);
 int bdrv_is_removable(BlockDriverState *bs);
 int bdrv_is_read_only(BlockDriverState *bs);
 int bdrv_is_inserted(BlockDriverState *bs);
@@ -683,6 +687,7 @@ void bdrv_iterate_format(void (*it)(void
 void bdrv_iterate_format(void (*it)(void *opaque, const char *name), 
                          void *opaque);
 const char *bdrv_get_device_name(BlockDriverState *bs);
+const char *bdrv_get_filename(BlockDriverState *bs);
 int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, 
                           const uint8_t *buf, int nb_sectors);
 int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);