aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-04-23 16:57:23 +0100
committerKeir Fraser <keir.fraser@citrix.com>2008-04-23 16:57:23 +0100
commitdefe5e9a3034c0c0bf4337cd1967571d8391041b (patch)
treeb1181a6965a0c15f436e627bedf765b8e4b18514
parente76492c4f4711bd51a23a631156cf458120b136c (diff)
downloadxen-defe5e9a3034c0c0bf4337cd1967571d8391041b.tar.gz
xen-defe5e9a3034c0c0bf4337cd1967571d8391041b.tar.bz2
xen-defe5e9a3034c0c0bf4337cd1967571d8391041b.zip
blktap: Automatically start tapdisk-ioemu on demand
When a domain wants to use a tap:ioemu disk but has no device model, start a tapdisk-ioemu instance as provider. Also, move the creation and removal of communication pipes to xend so that qemu-dm doesn't need the unwanted SIGHUP handler anymore. Signed-off-by: Kevin Wolf <kwolf@suse.de>
-rw-r--r--tools/blktap/drivers/blktapctrl.c75
-rw-r--r--tools/blktap/drivers/tapdisk.h2
-rw-r--r--tools/ioemu/Makefile2
-rw-r--r--tools/ioemu/hw/xen_blktap.c45
-rw-r--r--tools/ioemu/tapdisk-ioemu.c14
-rw-r--r--tools/ioemu/vl.c8
-rw-r--r--tools/python/xen/xend/XendDomainInfo.py3
-rw-r--r--tools/python/xen/xend/image.py42
8 files changed, 126 insertions, 65 deletions
diff --git a/tools/blktap/drivers/blktapctrl.c b/tools/blktap/drivers/blktapctrl.c
index 8825e919c4..f15c7b997d 100644
--- a/tools/blktap/drivers/blktapctrl.c
+++ b/tools/blktap/drivers/blktapctrl.c
@@ -474,9 +474,8 @@ static int read_msg(int fd, int msgtype, void *ptr)
}
-int launch_tapdisk(char *wrctldev, char *rdctldev)
+static int launch_tapdisk_provider(char **argv)
{
- char *argv[] = { "tapdisk", wrctldev, rdctldev, NULL };
pid_t child;
if ((child = fork()) < 0)
@@ -490,7 +489,9 @@ int launch_tapdisk(char *wrctldev, char *rdctldev)
i != STDERR_FILENO)
close(i);
- execvp("tapdisk", argv);
+ execvp(argv[0], argv);
+ DPRINTF("execvp failed: %d (%s)\n", errno, strerror(errno));
+ DPRINTF("PATH = %s\n", getenv("PATH"));
_exit(1);
} else {
pid_t got;
@@ -498,28 +499,78 @@ int launch_tapdisk(char *wrctldev, char *rdctldev)
got = waitpid(child, NULL, 0);
} while (got != child);
}
+ return child;
+}
+
+static int launch_tapdisk(char *wrctldev, char *rdctldev)
+{
+ char *argv[] = { "tapdisk", wrctldev, rdctldev, NULL };
+
+ if (launch_tapdisk_provider(argv) < 0)
+ return -1;
+
return 0;
}
-/* Connect to qemu-dm */
-static int connect_qemu(blkif_t *blkif)
+static int launch_tapdisk_ioemu(void)
+{
+ char *argv[] = { "tapdisk-ioemu", NULL };
+ return launch_tapdisk_provider(argv);
+}
+
+/*
+ * Connect to an ioemu based disk provider (qemu-dm or tapdisk-ioemu)
+ *
+ * If the domain has a device model, connect to qemu-dm through the
+ * domain specific pipe. Otherwise use a single tapdisk-ioemu instance
+ * which is represented by domid 0 and provides access for Dom0 and
+ * all DomUs without device model.
+ */
+static int connect_qemu(blkif_t *blkif, int domid)
{
char *rdctldev, *wrctldev;
+
+ static int tapdisk_ioemu_pid = 0;
+ static int dom0_readfd = 0;
+ static int dom0_writefd = 0;
- if (asprintf(&rdctldev, BLKTAP_CTRL_DIR "/qemu-read-%d",
- blkif->domid) < 0)
+ if (asprintf(&rdctldev, BLKTAP_CTRL_DIR "/qemu-read-%d", domid) < 0)
return -1;
- if (asprintf(&wrctldev, BLKTAP_CTRL_DIR "/qemu-write-%d",
- blkif->domid) < 0) {
+ if (asprintf(&wrctldev, BLKTAP_CTRL_DIR "/qemu-write-%d", domid) < 0) {
free(rdctldev);
return -1;
}
DPRINTF("Using qemu blktap pipe: %s\n", rdctldev);
- blkif->fds[READ] = open_ctrl_socket(wrctldev);
- blkif->fds[WRITE] = open_ctrl_socket(rdctldev);
+ if (domid == 0) {
+ /*
+ * tapdisk-ioemu exits as soon as the last image is
+ * disconnected. Check if it is still running.
+ */
+ if (tapdisk_ioemu_pid == 0 || kill(tapdisk_ioemu_pid, 0)) {
+ /* No device model and tapdisk-ioemu doesn't run yet */
+ DPRINTF("Launching tapdisk-ioemu\n");
+ tapdisk_ioemu_pid = launch_tapdisk_ioemu();
+
+ dom0_readfd = open_ctrl_socket(wrctldev);
+ dom0_writefd = open_ctrl_socket(rdctldev);
+ }
+
+ DPRINTF("Using tapdisk-ioemu connection\n");
+ blkif->fds[READ] = dom0_readfd;
+ blkif->fds[WRITE] = dom0_writefd;
+ } else if (access(rdctldev, R_OK | W_OK) == 0) {
+ /* Use existing pipe to the device model */
+ DPRINTF("Using qemu-dm connection\n");
+ blkif->fds[READ] = open_ctrl_socket(wrctldev);
+ blkif->fds[WRITE] = open_ctrl_socket(rdctldev);
+ } else {
+ /* No device model => try with tapdisk-ioemu */
+ DPRINTF("No device model\n");
+ connect_qemu(blkif, 0);
+ }
free(rdctldev);
free(wrctldev);
@@ -599,7 +650,7 @@ int blktapctrl_new_blkif(blkif_t *blkif)
if (!exist) {
if (type == DISK_TYPE_IOEMU) {
- if (connect_qemu(blkif))
+ if (connect_qemu(blkif, blkif->domid))
goto fail;
} else {
if (connect_tapdisk(blkif, minor))
diff --git a/tools/blktap/drivers/tapdisk.h b/tools/blktap/drivers/tapdisk.h
index 77b7fd8c83..c8a21827ff 100644
--- a/tools/blktap/drivers/tapdisk.h
+++ b/tools/blktap/drivers/tapdisk.h
@@ -235,7 +235,7 @@ static disk_info_t ioemu_disk = {
DISK_TYPE_IOEMU,
"ioemu disk",
"ioemu",
- 0,
+ 1,
#ifdef TAPDISK
NULL
#endif
diff --git a/tools/ioemu/Makefile b/tools/ioemu/Makefile
index 861311a8d2..3b31c2459a 100644
--- a/tools/ioemu/Makefile
+++ b/tools/ioemu/Makefile
@@ -87,7 +87,7 @@ endif
install: all $(if $(BUILD_DOCS),install-doc)
mkdir -p "$(DESTDIR)$(bindir)"
- $(INSTALL) -m 755 $(TOOLS) "$(DESTDIR)$(prefix)/sbin"
+ $(INSTALL) -m 755 $(TOOLS) "$(DESTDIR)$(SBINDIR)"
# mkdir -p "$(DESTDIR)$(datadir)"
# for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
# video.x openbios-sparc32 linux_boot.bin pxe-ne2k_pci.bin \
diff --git a/tools/ioemu/hw/xen_blktap.c b/tools/ioemu/hw/xen_blktap.c
index 5420da248b..996d492bc5 100644
--- a/tools/ioemu/hw/xen_blktap.c
+++ b/tools/ioemu/hw/xen_blktap.c
@@ -581,17 +581,13 @@ static void handle_blktap_ctrlmsg(void* private)
*/
static int open_ctrl_socket(char *devname)
{
- int ret;
int ipc_fd;
if (mkdir(BLKTAP_CTRL_DIR, 0755) == 0)
DPRINTF("Created %s directory\n", BLKTAP_CTRL_DIR);
- ret = mkfifo(devname,S_IRWXU|S_IRWXG|S_IRWXO);
- if ( (ret != 0) && (errno != EEXIST) ) {
- DPRINTF("ERROR: pipe failed (%d)\n", errno);
+ if (access(devname, R_OK | W_OK))
return -1;
- }
ipc_fd = open(devname,O_RDWR|O_NONBLOCK);
@@ -604,42 +600,6 @@ static int open_ctrl_socket(char *devname)
}
/**
- * Unmaps all disks and closes their pipes
- */
-void shutdown_blktap(void)
-{
- fd_list_entry_t *ptr;
- struct td_state *s;
- char *devname;
-
- DPRINTF("Shutdown blktap\n");
-
- /* Unmap all disks */
- ptr = fd_start;
- while (ptr != NULL) {
- s = ptr->s;
- unmap_disk(s);
- close(ptr->tap_fd);
- ptr = ptr->next;
- }
-
- /* Delete control pipes */
- if (asprintf(&devname, BLKTAP_CTRL_DIR "/qemu-read-%d", domid) >= 0) {
- DPRINTF("Delete %s\n", devname);
- if (unlink(devname))
- DPRINTF("Could not delete: %s\n", strerror(errno));
- free(devname);
- }
-
- if (asprintf(&devname, BLKTAP_CTRL_DIR "/qemu-write-%d", domid) >= 0) {
- DPRINTF("Delete %s\n", devname);
- if (unlink(devname))
- DPRINTF("Could not delete: %s\n", strerror(errno));
- free(devname);
- }
-}
-
-/**
* Initialize the blktap interface, i.e. open a pair of pipes in /var/run/tap
* and register a fd handler.
*
@@ -679,8 +639,5 @@ int init_blktap(void)
/* Attach a handler to the read pipe (called from qemu main loop) */
qemu_set_fd_handler2(read_fd, NULL, &handle_blktap_ctrlmsg, NULL, NULL);
- /* Register handler to clean up when the domain is destroyed */
- atexit(&shutdown_blktap);
-
return 0;
}
diff --git a/tools/ioemu/tapdisk-ioemu.c b/tools/ioemu/tapdisk-ioemu.c
index 272b277abb..52c5ac67ed 100644
--- a/tools/ioemu/tapdisk-ioemu.c
+++ b/tools/ioemu/tapdisk-ioemu.c
@@ -4,6 +4,7 @@
#include <string.h>
#include <stdint.h>
#include <signal.h>
+#include <unistd.h>
#include <sys/time.h>
#include <assert.h>
@@ -16,6 +17,8 @@ extern void bdrv_init(void);
extern void *qemu_mallocz(size_t size);
extern void qemu_free(void *ptr);
+extern void *fd_start;
+
int domid = 0;
FILE* logfile;
@@ -95,12 +98,17 @@ int main(void)
int max_fd;
fd_set rfds;
struct timeval tv;
+ void *old_fd_start = NULL;
logfile = stderr;
bdrv_init();
qemu_aio_init();
init_blktap();
+
+ /* Daemonize */
+ if (fork() != 0)
+ exit(0);
/*
* Main loop: Pass events to the corrsponding handlers and check for
@@ -137,6 +145,12 @@ int main(void)
} else
pioh = &ioh->next;
}
+
+ /* Exit when the last image has been closed */
+ if (old_fd_start != NULL && fd_start == NULL)
+ exit(0);
+
+ old_fd_start = fd_start;
}
return 0;
}
diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c
index c4832f5848..50e3f871f2 100644
--- a/tools/ioemu/vl.c
+++ b/tools/ioemu/vl.c
@@ -6275,12 +6275,6 @@ void qemu_system_powerdown_request(void)
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
-static void qemu_sighup_handler(int signal)
-{
- fprintf(stderr, "Received SIGHUP, terminating.\n");
- exit(0);
-}
-
void main_loop_wait(int timeout)
{
IOHandlerRecord *ioh;
@@ -7976,7 +7970,7 @@ int main(int argc, char **argv)
#ifndef CONFIG_STUBDOM
/* Unblock SIGTERM and SIGHUP, which may have been blocked by the caller */
- signal(SIGHUP, qemu_sighup_handler);
+ signal(SIGHUP, SIG_DFL);
sigemptyset(&set);
sigaddset(&set, SIGTERM);
sigaddset(&set, SIGHUP);
diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py
index 5fa15fd2fa..b833845ca2 100644
--- a/tools/python/xen/xend/XendDomainInfo.py
+++ b/tools/python/xen/xend/XendDomainInfo.py
@@ -1837,6 +1837,9 @@ class XendDomainInfo:
@raise: VmError for invalid devices
"""
+ if self.image:
+ self.image.prepareEnvironment()
+
ordered_refs = self.info.ordered_device_refs()
for dev_uuid in ordered_refs:
devclass, config = self.info['devices'][dev_uuid]
diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py
index 95a2f68a5a..2fd4fe9693 100644
--- a/tools/python/xen/xend/image.py
+++ b/tools/python/xen/xend/image.py
@@ -185,6 +185,42 @@ class ImageHandler:
"""Build the domain. Define in subclass."""
raise NotImplementedError()
+ def prepareEnvironment(self):
+ """Prepare the environment for the execution of the domain. This
+ method is called before any devices are set up."""
+
+ domid = self.vm.getDomid()
+
+ # Delete left-over pipes
+ try:
+ os.unlink('/var/run/tap/qemu-read-%d' % domid)
+ os.unlink('/var/run/tap/qemu-write-%d' % domid)
+ except:
+ pass
+
+ # No device model, don't create pipes
+ if self.device_model is None:
+ return
+
+ # If we use a device model, the pipes for communication between
+ # blktapctrl and ioemu must be present before the devices are
+ # created (blktapctrl must access them for new block devices)
+
+ # mkdir throws an exception if the path already exists
+ try:
+ os.mkdir('/var/run/tap', 0755)
+ except:
+ pass
+
+ try:
+ os.mkfifo('/var/run/tap/qemu-read-%d' % domid, 0600)
+ os.mkfifo('/var/run/tap/qemu-write-%d' % domid, 0600)
+ except OSError, e:
+ log.warn('Could not create blktap pipes for domain %d' % domid)
+ log.exception(e)
+ pass
+
+
# Return a list of cmd line args to the device models based on the
# xm config file
def parseDeviceModelArgs(self, vmConfig):
@@ -411,6 +447,12 @@ class ImageHandler:
self.pid = None
state = xstransact.Remove("/local/domain/0/device-model/%i"
% self.vm.getDomid())
+
+ try:
+ os.unlink('/var/run/tap/qemu-read-%d' % self.vm.getDomid())
+ os.unlink('/var/run/tap/qemu-write-%d' % self.vm.getDomid())
+ except:
+ pass
class LinuxImageHandler(ImageHandler):