* RFC: Xen cdrom haldaemon
2007-09-03 19:18 ` Daniel P. Berrange
2007-09-04 7:12 ` Keir Fraser
@ 2007-09-05 16:43 ` Pat Campbell
2007-09-05 17:39 ` Keir Fraser
2007-09-05 17:56 ` Daniel P. Berrange
1 sibling, 2 replies; 11+ messages in thread
From: Pat Campbell @ 2007-09-05 16:43 UTC (permalink / raw)
To: xen-devel
[-- Attachment #1: Type: text/plain, Size: 3566 bytes --]
Hi,
I have found that the DOM0 CDROM device returns a stale disk
size if a CD is changed while any application has the device open.
Test scenerio: ( Don't need XEN for this )
Two shell processes
Shell A runs simple test program with an arg to
open the cd for reading
report media size using lseek(0, SEEK_END)
then enter a sleep loop leaving FD open
In Shell B
eject
insert a different CD
eject -t,
run simple test progran, no arg
( size is still what was reported in shell A)
Kill Shell A test CD process
Run test CD process again, now you should have the
correct size
Simple test program, cdrom-test.c, has been attached.
I did enter a defect against the Linux kernel about this but
was unable to convince them it was their defect.
If we put Xen in the mix, say installing a FV Redhat system
from physical CD media you will have two CDROM device file
descriptors open. One in blkback and the other in QEMU.
When you get to CD #2 you won't be able to complete the
install as the total disk size has not been updated for
the larger CD #2, stays at the smaller CD #1 size.
You can get the QEMU descriptor closed by using xen-store
writes but none effect the blkback FD and there is no
way, that I have found, to effect ALL open Xen related FDs on
that device.
I have created a proof of concept patch for 3.1 that addresses the
above issue by causing all VMs, FV and PV, to close thier open
pyhsical CDROM file descriptors when the device door is opened. File
descriptors are re-opened when the door is closed AND a CD was
inserted.
The basic flow of the patch is:
Kernel:
blkback driver:
if block device is a physical cdrom then
Add media_present=1 into xenstore backend/vbd
for this device
Place a xenstore watch on media_present
watch_handler
if watch token is media_present
read value
if 0 then close block device fd
if 1 then re-open block device fd
Any access with fd closed results in EACCESS error
qemu
if block device is a cdrom
Place a xenstore watch on media_present
watch_handler
if watch token is media_present
read value
if 0 then close block device
if 1 then re-open block device and set media_changed
Any access with fd closed results in EACCESS error
xend
Starts XEN HalDaemon process
XEN HalDaemon
Registers event callback for HALD events
callback handler
gets device major/minor numbers
for each vbd in xenstore
if matching major and minor
if add_event ( cdrom door closed with media )
xenstore write 1 to vbd/media_present
else ( cddrom door open )
xenstore write 0 to vbd/media_present
I am just learning python, could use a python guy to enhance and
generalize.
With my patch applied I was able to install RHEL5 from the 5 CD set as
well as a WIN2003 server from multi CD media.
The patch is attached. Patch still needs some work but I would like
some feedback before going further down this path. Is this something
that fits into the current and near future architecture and might be
considered for addition?
Thanks in advance
Pat
[-- Attachment #2: cdrom-test.c --]
[-- Type: application/octet-stream, Size: 1055 bytes --]
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/cdrom.h>
#include <linux/hdreg.h>
#include <errno.h>
#define O_LARGEFILE 0100000
static int raw_open( const char *filename)
{
int fd;
int64_t size;
off_t len;
int64_t total_sectors;
fprintf(stderr, " %s() filename:%s \n", __PRETTY_FUNCTION__, filename);
fd = open(filename, O_RDWR | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_LARGEFILE);
if (fd < 0)
return -1;
}
len = lseek(fd, 0, SEEK_END);
if ( len == -1 )
{
perror("lseek");
fprintf(stderr, " len:%lld errno:%d \n",len, errno);
}
total_sectors = len / 512;
fprintf(stderr, " %s() len:%lld \n", __PRETTY_FUNCTION__, len );
fprintf(stderr, " %s() total_sectors:%lld \n", __PRETTY_FUNCTION__, total_sectors );
return 0;
}
main( int argc, char **argv )
{
raw_open( "/dev/cdrom");
if ( argc != 1 )
{
while( 1 )
sleep(1);
}
}
[-- Attachment #3: xen-3.1-cdrom.patch --]
[-- Type: text/plain, Size: 38705 bytes --]
# HG changeset patch
# User plc@plc4.provo.novell.com
# Date 1182539263 21600
# Node ID fa6ec13addb49f7054c364a90bbcbfae1d79fea8
# Parent 362adec0c4592f130ba17304126656b40f1b0324
CDROM removable media-present attribute plus handling code
diff -r 362adec0c459 -r fa6ec13addb4 linux-2.6-xen-sparse/drivers/xen/blkback/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/Makefile Fri Jun 22 13:02:23 2007 -0600
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/Makefile Fri Jun 22 13:07:43 2007 -0600
@@ -1,3 +1,3 @@ obj-$(CONFIG_XEN_BLKDEV_BACKEND) := blkb
obj-$(CONFIG_XEN_BLKDEV_BACKEND) := blkbk.o
-blkbk-y := blkback.o xenbus.o interface.o vbd.o
+blkbk-y := blkback.o xenbus.o interface.o vbd.o cdrom.o
diff -r 362adec0c459 -r fa6ec13addb4 linux-2.6-xen-sparse/drivers/xen/blkback/cdrom.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/cdrom.c Fri Jun 22 13:07:43 2007 -0600
@@ -0,0 +1,169 @@
+/******************************************************************************
+ * blkback/cdrom.c
+ *
+ * Routines for managing cdrom watch and media-present attribute of a
+ * cdrom type virtual block device (VBD).
+ *
+ * Copyright (c) 2003-2005, Keir Fraser & Steve Hand
+ * Copyright (c) 2007 Pat Campbell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "common.h"
+
+#undef DPRINTK
+#define DPRINTK(_f, _a...) \
+ printk("(%s() file=%s, line=%d) " _f "\n", \
+ __PRETTY_FUNCTION__, __FILE__ , __LINE__ , ##_a )
+
+
+#define MEDIA_PRESENT "media-present"
+
+static void cdrom_media_changed(struct xenbus_watch *, const char **, unsigned int);
+
+/**
+ * Writes media-present=1 attribute for the given vbd device if not
+ * already there
+ */
+static int cdrom_xenstore_write_media_present(struct backend_info *be)
+{
+ struct xenbus_device *dev = be->dev;
+ struct xenbus_transaction xbt;
+ int err;
+ int media_present;
+
+ DPRINTK(" ");
+
+ err = xenbus_scanf(XBT_NIL, dev->nodename, MEDIA_PRESENT, "%d",
+ &media_present);
+ if ( 0 < err) {
+ DPRINTK("already written err%d", err);
+ return(0);
+ }
+ media_present = 1;
+
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "starting transaction");
+ return(-1);
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, MEDIA_PRESENT, "%d", media_present );
+ if (err) {
+ xenbus_dev_fatal(dev, err, "writing %s/%s",
+ dev->nodename, MEDIA_PRESENT);
+ goto abort;
+ }
+ err = xenbus_transaction_end(xbt, 0);
+ if (err == -EAGAIN)
+ goto again;
+ if (err)
+ xenbus_dev_fatal(dev, err, "ending transaction");
+ return(0);
+ abort:
+ xenbus_transaction_end(xbt, 1);
+ return(-1);
+}
+
+/**
+ *
+ */
+int cdrom_is_type(struct backend_info *be)
+{
+ DPRINTK( "type:%x", be->blkif->vbd.type );
+ if ( be->blkif->vbd.type & VDISK_CDROM && be->blkif->vbd.type & GENHD_FL_REMOVABLE){
+ return(1);
+ }
+ return(0);
+}
+
+/**
+ *
+ */
+void cdrom_add_media_watch(struct backend_info *be)
+{
+ struct xenbus_device *dev = be->dev;
+ int err;
+
+ DPRINTK( "nodename:%s", dev->nodename);
+ if (cdrom_is_type(be)) {
+ DPRINTK("is a cdrom");
+ if ( cdrom_xenstore_write_media_present(be) == 0 ) {
+ DPRINTK( "xenstore wrote OK");
+ err = xenbus_watch_path2(dev, dev->nodename, MEDIA_PRESENT,
+ &be->backend_cdrom_watch, cdrom_media_changed);
+ if (err) {
+ DPRINTK( "media_present watch add failed" );
+ }
+ }
+ }
+}
+
+/**
+ * Callback received when the "media_present" xenstore node is changed
+ */
+static void cdrom_media_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ int err;
+ unsigned media_present;
+ struct backend_info *be
+ = container_of(watch, struct backend_info, backend_cdrom_watch);
+ struct xenbus_device *dev = be->dev;
+
+ DPRINTK(" ");
+
+ if ( !(cdrom_is_type(be))) {
+ DPRINTK("callback not for a cdrom" );
+ return;
+ }
+
+ err = xenbus_scanf(XBT_NIL, dev->nodename, MEDIA_PRESENT, "%d",
+ &media_present);
+ if (err == 0 || err == -ENOENT) {
+ DPRINTK("xenbus_read of cdrom media_present node error:%d",err);
+ return;
+ }
+
+ if (media_present == 0) {
+ vbd_free(&be->blkif->vbd);
+ }
+ else {
+ char *p = strrchr(dev->otherend, '/') + 1;
+ long handle = simple_strtoul(p, NULL, 0);
+
+ if (be->blkif->vbd.bdev == NULL) {
+ err = vbd_create(be->blkif, handle, be->major, be->minor,
+ (NULL == strchr(be->mode, 'w')));
+ if (err) {
+ be->major = be->minor = 0;
+ xenbus_dev_fatal(dev, err, "creating vbd structure");
+ return;
+ }
+ }
+ }
+}
diff -r 362adec0c459 -r fa6ec13addb4 linux-2.6-xen-sparse/drivers/xen/blkback/common.h
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/common.h Fri Jun 22 13:02:23 2007 -0600
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/common.h Fri Jun 22 13:07:43 2007 -0600
@@ -96,6 +96,17 @@ typedef struct blkif_st {
grant_ref_t shmem_ref;
} blkif_t;
+struct backend_info
+{
+ struct xenbus_device *dev;
+ blkif_t *blkif;
+ struct xenbus_watch backend_watch;
+ struct xenbus_watch backend_cdrom_watch;
+ unsigned major;
+ unsigned minor;
+ char *mode;
+};
+
blkif_t *blkif_alloc(domid_t domid);
void blkif_disconnect(blkif_t *blkif);
void blkif_free(blkif_t *blkif);
@@ -136,4 +147,8 @@ int blkback_barrier(struct xenbus_transa
int blkback_barrier(struct xenbus_transaction xbt,
struct backend_info *be, int state);
+/* cdrom media change */
+int cdrom_is_type(struct backend_info *be);
+void cdrom_add_media_watch(struct backend_info *be);
+
#endif /* __BLKIF__BACKEND__COMMON_H__ */
diff -r 362adec0c459 -r fa6ec13addb4 linux-2.6-xen-sparse/drivers/xen/blkback/vbd.c
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/vbd.c Fri Jun 22 13:02:23 2007 -0600
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/vbd.c Fri Jun 22 13:07:43 2007 -0600
@@ -106,6 +106,9 @@ int vbd_translate(struct phys_req *req,
if ((operation != READ) && vbd->readonly)
goto out;
+ if (vbd->bdev == NULL)
+ goto out;
+
if (unlikely((req->sector_number + req->nr_sects) > vbd_sz(vbd)))
goto out;
diff -r 362adec0c459 -r fa6ec13addb4 linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c Fri Jun 22 13:02:23 2007 -0600
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c Fri Jun 22 13:07:43 2007 -0600
@@ -26,16 +26,6 @@
#define DPRINTK(fmt, args...) \
pr_debug("blkback/xenbus (%s:%d) " fmt ".\n", \
__FUNCTION__, __LINE__, ##args)
-
-struct backend_info
-{
- struct xenbus_device *dev;
- blkif_t *blkif;
- struct xenbus_watch backend_watch;
- unsigned major;
- unsigned minor;
- char *mode;
-};
static void connect(struct backend_info *);
static int connect_ring(struct backend_info *);
@@ -179,6 +169,12 @@ static int blkback_remove(struct xenbus_
be->backend_watch.node = NULL;
}
+ if (be->backend_cdrom_watch.node) {
+ unregister_xenbus_watch(&be->backend_cdrom_watch);
+ kfree(be->backend_cdrom_watch.node);
+ be->backend_cdrom_watch.node = NULL;
+ }
+
if (be->blkif) {
blkif_disconnect(be->blkif);
vbd_free(&be->blkif->vbd);
@@ -330,6 +326,9 @@ static void backend_changed(struct xenbu
/* We're potentially connected now */
update_blkif_status(be->blkif);
+
+ /* Add watch for cdrom media status if necessay */
+ cdrom_add_media_watch(be);
}
}
diff -r 362adec0c459 -r fa6ec13addb4 tools/ioemu/block.c
--- a/tools/ioemu/block.c Fri Jun 22 13:02:23 2007 -0600
+++ b/tools/ioemu/block.c Fri Jun 22 13:07:43 2007 -0600
@@ -185,6 +185,13 @@ static BlockDriver *find_image_format(co
uint8_t *buf;
size_t bufsize = 1024;
+ if ( strcmp(filename, "/dev/cdrom") == 0) {
+ drv = bdrv_find_format("raw");
+ if (drv != NULL) {
+ return(drv);
+ }
+ }
+
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0) {
buf = NULL;
@@ -531,19 +538,9 @@ int bdrv_is_read_only(BlockDriverState *
return bs->read_only;
}
-int bdrv_is_inserted(BlockDriverState *bs)
-{
- return bs->inserted;
-}
-
int bdrv_is_locked(BlockDriverState *bs)
{
return bs->locked;
-}
-
-void bdrv_set_locked(BlockDriverState *bs, int locked)
-{
- bs->locked = locked;
}
void bdrv_set_change_cb(BlockDriverState *bs,
@@ -692,8 +689,10 @@ static int raw_open(BlockDriverState *bs
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
- if (fd < 0)
- return -1;
+ if (fd < 0 && strstart(filename, "/dev/cd", NULL))
+ fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE | O_NONBLOCK );
+ if (fd < 0)
+ return -1;
bs->read_only = 1;
}
#ifdef _BSD
@@ -764,7 +763,93 @@ static void raw_close(BlockDriverState *
BDRVRawState *s = bs->opaque;
bs->total_sectors = 0;
close(s->fd);
-}
+ s->fd = -1;
+}
+
+#include <linux/cdrom.h>
+#include <sys/ioctl.h>
+static int raw_is_inserted(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+ int ret;
+
+ switch(bs->removable) {
+ case BDRV_TYPE_CDROM:
+ ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
+ if (ret == CDS_DISC_OK) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ break;
+ default:
+ return 1;
+ }
+}
+
+static int raw_media_changed(BlockDriverState *bs)
+{
+ int ret = 0;
+
+ switch(bs->removable) {
+ case BDRV_TYPE_CDROM:
+ {
+ if( bs->media_changed == 1 )
+ {
+ ret = 1;
+ bs->media_changed = 0;
+ }
+ return ret;
+ }
+ default:
+ return -ENOTSUP;
+ }
+}
+
+
+static int raw_eject(BlockDriverState *bs, int eject_flag)
+{
+ char cmd[sizeof(bs->device_name) + 32];
+
+ switch(bs->removable) {
+ case BDRV_TYPE_CDROM:
+ if (eject_flag) {
+ sprintf(cmd, "eject %s", bs->filename);
+ if (system(cmd) == -1) {
+ perror("CDROMEJECT");
+ }
+ } else {
+ sprintf(cmd, "eject -t %s", bs->filename);
+ if (system(cmd) == -1) {
+ perror("CDROMCLOSETRAY");
+ }
+ }
+ break;
+ default:
+ return -ENOTSUP;
+ }
+ return 0;
+}
+
+static int raw_set_locked(BlockDriverState *bs, int locked)
+{
+ BDRVRawState *s = bs->opaque;
+
+ switch(bs->removable) {
+ case BDRV_TYPE_CDROM:
+ if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) {
+ /* Note: an error can happen if the distribution automatically
+ mounts the CD-ROM */
+ // perror("CDROM_LOCKDOOR");
+ }
+ break;
+ default:
+ return -ENOTSUP;
+ }
+ return 0;
+}
+
#ifdef _WIN32
#include <windows.h>
@@ -845,6 +930,12 @@ BlockDriver bdrv_raw = {
raw_close,
raw_create,
raw_flush,
+
+ /* removable device support */
+ .bdrv_is_inserted = raw_is_inserted,
+ .bdrv_media_changed = raw_media_changed,
+ .bdrv_eject = raw_eject,
+ .bdrv_set_locked = raw_set_locked,
};
void bdrv_init(void)
@@ -861,3 +952,96 @@ void bdrv_init(void)
bdrv_register(&bdrv_vpc);
bdrv_register(&bdrv_vvfat);
}
+
+/**************************************************************/
+/* removable device support */
+
+/**
+ * Return TRUE if the media is present
+ */
+int bdrv_is_inserted(BlockDriverState *bs)
+{
+ BlockDriver *drv = bs->drv;
+ int ret;
+ if (!drv)
+ return 0;
+ if (!drv->bdrv_is_inserted)
+ return 1;
+ ret = drv->bdrv_is_inserted(bs);
+ return ret;
+}
+
+/**
+ * Return TRUE if the media changed since the last call to this
+ * function.
+ */
+int bdrv_media_changed(BlockDriverState *bs)
+{
+ BlockDriver *drv = bs->drv;
+ int ret;
+
+ if (!drv || !drv->bdrv_media_changed)
+ ret = -ENOTSUP;
+ else
+ ret = drv->bdrv_media_changed(bs);
+ if (ret == -ENOTSUP)
+ ret = bs->media_changed;
+ bs->media_changed = 0;
+ return ret;
+}
+
+
+/**
+ * If eject_flag is TRUE, eject the media. Otherwise, close the tray
+ */
+void bdrv_eject(BlockDriverState *bs, int eject_flag)
+{
+
+ int ret = 0;
+ char cmd[sizeof(bs->device_name) + 32];
+ BlockDriver *drv = bs->drv;
+
+ switch(bs->removable) {
+ case BDRV_TYPE_CDROM:
+ if (eject_flag) {
+ sprintf(cmd, "eject %s", bs->filename);
+ if (system(cmd) == -1) {
+ perror("CDROMEJECT");
+ ret = -ENOTSUP;
+ }
+ } else {
+ sprintf(cmd, "eject -t %s", bs->filename);
+ if (system(cmd) == -1) {
+ perror("CDROMCLOSETRAY");
+ ret = -ENOTSUP;
+ }
+ }
+ break;
+ default:
+ if (!drv || !drv->bdrv_eject) {
+ ret = -ENOTSUP;
+ } else {
+ ret = drv->bdrv_eject(bs, eject_flag);
+ }
+ if (ret == -ENOTSUP) {
+ if (eject_flag)
+ bdrv_close(bs);
+ }
+ }
+ //return ret;
+}
+
+/**
+ * Lock or unlock the media (if it is locked, the user won't be able
+ * to eject it manually).
+ */
+void bdrv_set_locked(BlockDriverState *bs, int locked)
+{
+ BlockDriver *drv = bs->drv;
+
+ bs->locked = locked;
+ if (drv && drv->bdrv_set_locked) {
+ drv->bdrv_set_locked(bs, locked);
+ }
+}
+
diff -r 362adec0c459 -r fa6ec13addb4 tools/ioemu/block_int.h
--- a/tools/ioemu/block_int.h Fri Jun 22 13:02:23 2007 -0600
+++ b/tools/ioemu/block_int.h Fri Jun 22 13:07:43 2007 -0600
@@ -41,6 +41,13 @@ struct BlockDriver {
int nb_sectors, int *pnum);
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
int (*bdrv_make_empty)(BlockDriverState *bs);
+
+ /* removable device specific */
+ int (*bdrv_is_inserted)(BlockDriverState *bs);
+ int (*bdrv_media_changed)(BlockDriverState *bs);
+ int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
+ int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
+
struct BlockDriver *next;
};
@@ -65,6 +72,7 @@ struct BlockDriverState {
char backing_file[1024]; /* if non zero, the image is a diff of
this file image */
int is_temporary;
+ int media_changed;
BlockDriverState *backing_hd;
diff -r 362adec0c459 -r fa6ec13addb4 tools/ioemu/hw/ide.c
--- a/tools/ioemu/hw/ide.c Fri Jun 22 13:02:23 2007 -0600
+++ b/tools/ioemu/hw/ide.c Fri Jun 22 13:07:43 2007 -0600
@@ -278,6 +278,7 @@
#define ASC_ILLEGAL_OPCODE 0x20
#define ASC_LOGICAL_BLOCK_OOR 0x21
#define ASC_INV_FIELD_IN_CMD_PACKET 0x24
+#define ASC_MEDIA_CHANGED 0x28
#define ASC_MEDIUM_NOT_PRESENT 0x3a
#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39
@@ -393,6 +394,7 @@ typedef struct PCIIDEState {
} PCIIDEState;
#define DMA_MULTI_THREAD
+#undef DMA_MULTI_THREAD
#ifdef DMA_MULTI_THREAD
@@ -1341,7 +1343,6 @@ static void ide_atapi_cmd(IDEState *s)
} else {
ide_atapi_cmd_error(s, SENSE_NOT_READY,
ASC_MEDIUM_NOT_PRESENT);
- xenstore_check_new_media_present(1000);
}
break;
case GPCMD_MODE_SENSE_10:
@@ -1530,7 +1531,10 @@ static void ide_atapi_cmd(IDEState *s)
if (eject && !start) {
/* eject the disk */
- bdrv_close(s->bs);
+ bdrv_eject(s->bs, 1);
+ } else if (eject && start) {
+ /* close the tray */
+ bdrv_eject(s->bs, 0);
}
ide_atapi_cmd_ok(s);
}
diff -r 362adec0c459 -r fa6ec13addb4 tools/ioemu/xenstore.c
--- a/tools/ioemu/xenstore.c Fri Jun 22 13:02:23 2007 -0600
+++ b/tools/ioemu/xenstore.c Fri Jun 22 13:07:43 2007 -0600
@@ -82,7 +82,7 @@ void xenstore_parse_domain_config(int do
char **e = NULL;
char *buf = NULL, *path;
char *fpath = NULL, *bpath = NULL,
- *dev = NULL, *params = NULL, *type = NULL;
+ *dev = NULL, *params = NULL, *type = NULL, *media_present = NULL;
int i, is_scsi;
unsigned int len, num, hd_index;
@@ -168,8 +168,12 @@ void xenstore_parse_domain_config(int do
/* check if it is a cdrom */
if (type && !strcmp(type, "cdrom")) {
bdrv_set_type_hint(bs_table[hd_index], BDRV_TYPE_CDROM);
- if (pasprintf(&buf, "%s/params", bpath) != -1)
- xs_watch(xsh, buf, dev);
+ xs_watch(xsh, buf, dev);
+ if (pasprintf(&buf, "%s/media-present", bpath) != -1) {
+ free(media_present);
+ media_present = xs_read(xsh, XBT_NULL, buf, &len);
+ xs_watch(xsh, buf, "media_present");
+ }
}
/* open device now if media present */
if (params[0]) {
@@ -313,7 +317,7 @@ void xenstore_process_logdirty_event(voi
void xenstore_process_event(void *opaque)
{
- char **vec, *image = NULL;
+ char **vec, *image = NULL, *media_present = NULL;
unsigned int len, num, hd_index;
vec = xs_read_watch(xsh, &num);
@@ -322,6 +326,40 @@ void xenstore_process_event(void *opaque
if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
xenstore_process_logdirty_event();
+ goto out;
+ }
+
+ if (!strcmp(vec[XS_WATCH_TOKEN], "media_present")) {
+ media_present = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len);
+ if (media_present) {
+ BlockDriverState *bs;
+ char *buf = NULL, *cp = NULL, *path = NULL, *dev = NULL;
+
+ path = strdup(vec[XS_WATCH_PATH]);
+ cp = strstr(path, "media-present");
+ if (cp){
+ *(cp-1) = '\0';
+ pasprintf(&buf, "%s/dev", path);
+ dev = xs_read(xsh, XBT_NULL, buf, &len);
+ if (dev) {
+ bs = bdrv_find(dev);
+ if (!bs) {
+ term_printf("device not found\n");
+ goto out;
+ }
+ if (strcmp(media_present, "0") == 0 && bs) {
+ bdrv_close(bs);
+ }
+ else if (strcmp(media_present, "1") == 0 && bs != NULL && bs->drv == NULL) {
+ if (bdrv_open(bs, bs->filename, 0 /* snapshot */) < 0) {
+ fprintf(stderr, "qemu: could not open hard disk image '%s'\n",
+ bs->filename);
+ }
+ bs->media_changed = 1;
+ }
+ }
+ }
+ }
goto out;
}
diff -r 362adec0c459 -r fa6ec13addb4 tools/python/xen/xend/server/HalDaemon.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xend/server/HalDaemon.py Fri Jun 22 13:07:43 2007 -0600
@@ -0,0 +1,228 @@
+#!/usr/bin/env python
+# -*- mode: python; -*-
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2007 Pat Campbell <plc@novell.com>
+# Copyright (C) 2007 Novell Inc.
+#============================================================================
+
+"""hald (Hardware Abstraction Layer Daemon) watcher for Xen management
+ of removable block device media.
+
+"""
+
+import gobject
+import dbus
+import dbus.glib
+import os
+import types
+import sys
+import signal
+import traceback
+from xen.xend.xenstore.xstransact import xstransact, complete
+from xen.xend.xenstore.xsutil import xshandle
+from xen.xend import PrettyPrint
+from xen.xend import XendLogging
+from xen.xend.XendLogging import log
+
+class HalDaemon:
+ """The Hald block device watcher for XEN
+ """
+
+ """Default path to the log file. """
+ logfile_default = "/var/log/xen/hald.log"
+
+ """Default level of information to be logged."""
+ loglevel_default = 'INFO'
+
+ def __init__(self):
+
+ XendLogging.init(self.logfile_default, self.loglevel_default)
+ log.debug( "%s", "__init__")
+
+ self.udi_dict = {}
+ self.debug = 0
+ self.dbpath = "/local/domain/0/backend/vbd"
+ self.bus = dbus.SystemBus()
+ self.hal_manager_obj = self.bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager')
+ self.hal_manager = dbus.Interface( self.hal_manager_obj, 'org.freedesktop.Hal.Manager')
+ self.gatherBlockDevices()
+ self.registerDeviceCallbacks()
+
+ def run(self):
+ log.debug( "%s", "In new run" );
+ try:
+ self.mainloop = gobject.MainLoop()
+ self.mainloop.run()
+ except KeyboardInterrupt, ex:
+ log.debug('Keyboard exception handler: %s', ex )
+ self.mainloop.quit()
+ except Exception, ex:
+ log.debug('Generic exception handler: %s', ex )
+ self.mainloop.quit()
+
+ def __del__(self):
+ log.debug( "%s", "In del " );
+ self.unRegisterDeviceCallbacks()
+ self.mainloop.quit()
+
+ def shutdown(self):
+ log.debug( "%s", "In shutdown now " );
+ self.unRegisterDeviceCallbacks()
+ self.mainloop.quit()
+
+ def stop(self):
+ log.debug( "%s", "In stop now " );
+ self.unRegisterDeviceCallbacks()
+ self.mainloop.quit()
+
+ def gatherBlockDevices(self):
+
+ # Get all the current devices from hal and save in a dictionary
+ try:
+ device_names = self.hal_manager.GetAllDevices()
+ i = 0;
+ for name in device_names:
+ #log.debug("device name, device=%s",name)
+ dev_obj = self.bus.get_object ('org.freedesktop.Hal', name)
+ dev = dbus.Interface (dev_obj, 'org.freedesktop.Hal.Device')
+ dev_properties = dev_obj.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device")
+ if dev_properties.has_key('block.device'):
+ dev_str = dev_properties['block.device']
+ dev_major = dev_properties['block.major']
+ dev_minor = dev_properties['block.minor']
+ udi_info = {}
+ udi_info['device'] = dev_str
+ udi_info['major'] = dev_major
+ udi_info['minor'] = dev_minor
+ udi_info['udi'] = name
+ self.udi_dict[i] = udi_info
+ i = i + 1
+ except Exception, ex:
+ print >>sys.stderr, 'Exception gathering block devices:', ex
+ log.warn("Exception gathering block devices (%s)",ex)
+
+ #
+ def registerDeviceCallbacks(self):
+ # setup the callbacks for when the gdl changes
+ self.hal_manager.connect_to_signal('DeviceAdded', self.device_added_callback)
+ self.hal_manager.connect_to_signal('DeviceRemoved', self.device_removed_callback)
+
+ #
+ def unRegisterDeviceCallbacks(self):
+ # setup the callbacks for when the gdl changes
+ self.hal_manager.remove_signal_receiver(self.device_added_callback,'DeviceAdded')
+ self.hal_manager.remove_signal_receiver(self.device_removed_callback,'DeviceRemoved')
+
+ #
+ def device_removed_callback(self,udi):
+ log.debug('UDI %s was removed',udi)
+ self.show_dict(self.udi_dict)
+ for key in self.udi_dict:
+ udi_info = self.udi_dict[key]
+ if udi_info['udi'] == udi:
+ device = udi_info['device']
+ major = udi_info['major']
+ minor = udi_info['minor']
+ self.change_xenstore( "remove", device, major, minor)
+
+ # Adds device to dictionary if not already there
+ def device_added_callback(self,udi):
+ log.debug('UDI %s was added', udi)
+ self.show_dict(self.udi_dict)
+ dev_obj = self.bus.get_object ('org.freedesktop.Hal', udi)
+ dev = dbus.Interface (dev_obj, 'org.freedesktop.Hal.Device')
+ device = dev.GetProperty ('block.device')
+ major = dev.GetProperty ('block.major')
+ minor = dev.GetProperty ('block.minor')
+ udi_info = {}
+ udi_info['device'] = device
+ udi_info['major'] = major
+ udi_info['minor'] = minor
+ udi_info['udi'] = udi
+ already = 0
+ cnt = 0;
+ for key in self.udi_dict:
+ info = self.udi_dict[key]
+ if info['udi'] == udi:
+ already = 1
+ break
+ cnt = cnt + 1
+ if already == 0:
+ self.udi_dict[cnt] = udi_info;
+ log.debug('UDI %s was added, device:%s major:%s minor:%s index:%d\n', udi, device, major, minor, cnt)
+ self.change_xenstore( "add", device, major, minor)
+
+ # Debug helper, shows dictionary contents
+ def show_dict(self,dict=None):
+ if self.debug == 0 :
+ return
+ if dict == None :
+ dict = self.udi_dict
+ for key in dict:
+ log.debug('udi_info %s udi_info:%s',key,dict[key])
+
+ # Set or clear xenstore media-present depending on the action argument
+ # for every vbd that has this block device
+ def change_xenstore(self,action, device, major, minor):
+ domains = xstransact.List(self.dbpath)
+ log.debug('domains: %s', domains)
+ for domain in domains: # for each domain
+ devices = xstransact.List( self.dbpath + '/' + domain)
+ log.debug('devices: %s',devices)
+ for device in devices: # for each vbd device
+ str = device.split('/')
+ vbd_type = None;
+ vbd_physical_device = None
+ vbd_media = None
+ vbd_device_path = self.dbpath + '/' + domain + '/' + device
+ listing = xstransact.List(vbd_device_path)
+ for entry in listing: # for each entry
+ item = self.dbpath + '/' + entry
+ value = xstransact.Read( vbd_device_path + '/' + entry)
+ log.debug('%s=%s',item,value)
+ if item.find('media-present') != -1:
+ vbd_media = item;
+ vbd_media_path = item
+ if item.find('physical-device') != -1:
+ vbd_physical_device = value;
+ if item.find('type') != -1:
+ vbd_type = value;
+ if vbd_type is not None and vbd_physical_device is not None and vbd_media is not None :
+ inode = vbd_physical_device.split(':')
+ imajor = inode[0]
+ iminor = inode[1]
+ log.debug("action:%s major:%s- minor:%s- imajor:%s- iminor:%s- inode: %s",
+ action,major,minor, imajor, iminor, inode)
+ if int(imajor) == int(major) and int(iminor) == int(minor):
+ if action == "add":
+ xs_dict = {'media': "1"}
+ xstransact.Write(vbd_device_path, 'media-present', "1" )
+ log.debug("wrote xenstore media-present 1 path:%s",vbd_media_path)
+ else:
+ xstransact.Write(vbd_device_path, 'media-present', "0" )
+ log.debug("wrote xenstore media 0 path:%s",vbd_media_path)
+
+def mylog( fmt, *args):
+ f = open('/tmp/haldaemon.log', 'a')
+ print >>f, "HalDaemon ", fmt % args
+ f.close()
+
+if __name__ == "__main__":
+ watcher = HalDaemon()
+ watcher.run()
+ print 'Falling off end'
+
+
diff -r 362adec0c459 -r fa6ec13addb4 tools/python/xen/xend/server/Hald.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xend/server/Hald.py Fri Jun 22 13:07:43 2007 -0600
@@ -0,0 +1,113 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2007 Pat Campbell <plc@novell.com>
+# Copyright (C) 2007 Novell Inc.
+#============================================================================
+
+import errno
+import types
+import os
+import sys
+import time
+import signal
+from traceback import print_exc
+
+from xen.xend.XendLogging import log
+
+class Hald:
+ def __init__(self):
+ self.ready = False
+ self.running = True
+
+ def run(self):
+ """Starts the HalDaemon process
+ """
+ self.ready = True
+ try:
+ myfile = self.find("xen/xend/server/HalDaemon.py")
+ args = (["python", myfile ])
+ self.pid = self.daemonize("python", args )
+ #log.debug( "%s %s pid:%d", "Hald.py starting ", args, self.pid )
+ except:
+ self.pid = -1
+ log.debug("Unable to start HalDaemon process")
+
+ def shutdown(self):
+ """Shutdown the HalDaemon process
+ """
+ log.debug("%s pid:%d", "Hald.shutdown()", self.pid)
+ self.running = False
+ self.ready = False
+ if self.pid != -1:
+ try:
+ os.kill(self.pid, signal.SIGINT)
+ except:
+ print_exc()
+
+ def daemonize(self,prog, args):
+ """Runs a program as a daemon with the list of arguments. Returns the PID
+ of the daemonized program, or returns 0 on error.
+ Copied from xm/create.py instead of importing to reduce coupling
+ """
+ r, w = os.pipe()
+ pid = os.fork()
+
+ if pid == 0:
+ os.close(r)
+ w = os.fdopen(w, 'w')
+ os.setsid()
+ try:
+ pid2 = os.fork()
+ except:
+ pid2 = None
+ if pid2 == 0:
+ os.chdir("/")
+ for fd in range(0, 256):
+ try:
+ os.close(fd)
+ except:
+ pass
+ os.open("/dev/null", os.O_RDWR)
+ os.dup2(0, 1)
+ os.dup2(0, 2)
+ os.execvp(prog, args)
+ os._exit(1)
+ else:
+ w.write(str(pid2 or 0))
+ w.close()
+ os._exit(0)
+ os.close(w)
+ r = os.fdopen(r)
+ daemon_pid = int(r.read())
+ r.close()
+ os.waitpid(pid, 0)
+ #log.debug( "daemon_pid: %d", daemon_pid )
+ return daemon_pid
+
+ def find(self,path, matchFunc=os.path.isfile):
+ """Find a module in the sys.path
+ From web page: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52224
+ """
+ for dirname in sys.path:
+ candidate = os.path.join(dirname, path)
+ if matchFunc(candidate):
+ return candidate
+ raise Error("Can't find file %s" % path)
+
+if __name__ == "__main__":
+ watcher = Hald()
+ watcher.run()
+ time.sleep(10)
+ watcher.shutdown()
diff -r 362adec0c459 -r fa6ec13addb4 tools/python/xen/xend/server/SrvServer.py
--- a/tools/python/xen/xend/server/SrvServer.py Fri Jun 22 13:02:23 2007 -0600
+++ b/tools/python/xen/xend/server/SrvServer.py Fri Jun 22 13:07:43 2007 -0600
@@ -57,6 +57,7 @@ from xen.web.SrvDir import SrvDir
from SrvRoot import SrvRoot
from XMLRPCServer import XMLRPCServer
+from xen.xend.server.Hald import Hald
xoptions = XendOptions.instance()
@@ -248,6 +249,8 @@ def _loadConfig(servers, root, reload):
if xoptions.get_xend_unix_xmlrpc_server():
servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False))
+ servers.add(Hald())
+
def create():
root = SrvDir()
# HG changeset patch
# User plc@plc4.provo.novell.com
# Date 1182542474 21600
# Node ID 46685041fb424de81500375183149ecb126e1a88
# Parent fa6ec13addb49f7054c364a90bbcbfae1d79fea8
Added return true to raw_is_inserted() if ioctl fails
diff -r fa6ec13addb4 -r 46685041fb42 tools/ioemu/block.c
--- a/tools/ioemu/block.c Fri Jun 22 13:07:43 2007 -0600
+++ b/tools/ioemu/block.c Fri Jun 22 14:01:14 2007 -0600
@@ -777,6 +777,9 @@ static int raw_is_inserted(BlockDriverSt
case BDRV_TYPE_CDROM:
ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
if (ret == CDS_DISC_OK) {
+ return 1;
+ }
+ if (ret == -1) { // iso case
return 1;
}
else {
# HG changeset patch
# User plc@plc4.provo.novell.com
# Date 1182542925 21600
# Node ID 69fc41d0f24bbc6a428d0e5dd23225ef7aa9d6f5
# Parent 46685041fb424de81500375183149ecb126e1a88
Added if test for params
diff -r 46685041fb42 -r 69fc41d0f24b tools/ioemu/xenstore.c
--- a/tools/ioemu/xenstore.c Fri Jun 22 14:01:14 2007 -0600
+++ b/tools/ioemu/xenstore.c Fri Jun 22 14:08:45 2007 -0600
@@ -168,7 +168,8 @@ void xenstore_parse_domain_config(int do
/* check if it is a cdrom */
if (type && !strcmp(type, "cdrom")) {
bdrv_set_type_hint(bs_table[hd_index], BDRV_TYPE_CDROM);
- xs_watch(xsh, buf, dev);
+ if (pasprintf(&buf, "%s/params", bpath) != -1)
+ xs_watch(xsh, buf, dev);
if (pasprintf(&buf, "%s/media-present", bpath) != -1) {
free(media_present);
media_present = xs_read(xsh, XBT_NULL, buf, &len);
diff -ur a/tools/python/xen/xend/server/Hald.py b/tools/python/xen/xend/server/Hald.py
--- a/tools/python/xen/xend/server/Hald.py 2007-06-28 09:24:34.000000000 -0600
+++ b/tools/python/xen/xend/server/Hald.py 2007-06-28 09:25:33.000000000 -0600
@@ -74,6 +74,8 @@
pid2 = None
if pid2 == 0:
os.chdir("/")
+ env = os.environ.copy()
+ env['PYTHONPATH'] = self.getpythonpath()
for fd in range(0, 256):
try:
os.close(fd)
@@ -82,7 +84,7 @@
os.open("/dev/null", os.O_RDWR)
os.dup2(0, 1)
os.dup2(0, 2)
- os.execvp(prog, args)
+ os.execvpe(prog, args, env)
os._exit(1)
else:
w.write(str(pid2 or 0))
@@ -96,6 +98,16 @@
#log.debug( "daemon_pid: %d", daemon_pid )
return daemon_pid
+ def getpythonpath(self):
+ str = " "
+ for p in sys.path:
+ if str != " ":
+ str = str + ":" + p
+ else:
+ if str != "":
+ str = p
+ return str
+
def find(self,path, matchFunc=os.path.isfile):
"""Find a module in the sys.path
From web page: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52224
[-- Attachment #4: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 11+ messages in thread