[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] blktap: Automatically start tapdisk-ioemu on demand


  • To: xen-devel@xxxxxxxxxxxxxxxxxxx
  • From: Kevin Wolf <kwolf@xxxxxxx>
  • Date: Tue, 22 Apr 2008 15:24:48 +0200
  • Delivery-date: Tue, 22 Apr 2008 06:30:32 -0700
  • List-id: Xen developer discussion <xen-devel.lists.xensource.com>

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@xxxxxxx>

diff -r 08e010c3f251 tools/blktap/drivers/blktapctrl.c
--- a/tools/blktap/drivers/blktapctrl.c Tue Apr 15 16:39:00 2008 +0100
+++ b/tools/blktap/drivers/blktapctrl.c Tue Apr 22 15:20:09 2008 +0200
@@ -474,9 +474,8 @@ static int read_msg(int fd, int msgtype,
 
 }
 
-int launch_tapdisk(char *wrctldev, char *rdctldev)
-{
-       char *argv[] = { "tapdisk", wrctldev, rdctldev, NULL };
+static int launch_tapdisk_provider(char **argv)
+{
        pid_t child;
        
        if ((child = fork()) < 0)
@@ -490,7 +489,9 @@ int launch_tapdisk(char *wrctldev, char 
                            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 
                        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;
-       
-       if (asprintf(&rdctldev, BLKTAP_CTRL_DIR "/qemu-read-%d", 
-                       blkif->domid) < 0)
-               return -1;
-
-       if (asprintf(&wrctldev, BLKTAP_CTRL_DIR "/qemu-write-%d", 
-                       blkif->domid) < 0) {
+
+       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", domid) < 0)
+               return -1;
+
+       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 -r 08e010c3f251 tools/blktap/drivers/tapdisk.h
--- a/tools/blktap/drivers/tapdisk.h    Tue Apr 15 16:39:00 2008 +0100
+++ b/tools/blktap/drivers/tapdisk.h    Tue Apr 22 15:20:09 2008 +0200
@@ -235,7 +235,7 @@ static disk_info_t ioemu_disk = {
        DISK_TYPE_IOEMU,
        "ioemu disk",
        "ioemu",
-       0,
+       1,
 #ifdef TAPDISK
        NULL
 #endif
diff -r 08e010c3f251 tools/ioemu/Makefile
--- a/tools/ioemu/Makefile      Tue Apr 15 16:39:00 2008 +0100
+++ b/tools/ioemu/Makefile      Tue Apr 22 15:20:09 2008 +0200
@@ -87,7 +87,7 @@ endif
 
 install: all $(if $(BUILD_DOCS),install-doc)
        mkdir -p "$(DESTDIR)$(bindir)"
-       $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(prefix)/sbin"
+       $(INSTALL) -m 755 -s $(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 -r 08e010c3f251 tools/ioemu/hw/xen_blktap.c
--- a/tools/ioemu/hw/xen_blktap.c       Tue Apr 15 16:39:00 2008 +0100
+++ b/tools/ioemu/hw/xen_blktap.c       Tue Apr 22 15:20:09 2008 +0200
@@ -581,17 +581,13 @@ static void handle_blktap_ctrlmsg(void* 
  */
 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);
 
@@ -601,42 +597,6 @@ static int open_ctrl_socket(char *devnam
        }
 
        return ipc_fd;
-}
-
-/**
- * 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);
-       }
 }
 
 /**
@@ -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 -r 08e010c3f251 tools/ioemu/tapdisk-ioemu.c
--- a/tools/ioemu/tapdisk-ioemu.c       Tue Apr 15 16:39:00 2008 +0100
+++ b/tools/ioemu/tapdisk-ioemu.c       Tue Apr 22 15:20:09 2008 +0200
@@ -4,6 +4,7 @@
 #include <string.h>
 #include <stdint.h>
 #include <signal.h>
+#include <unistd.h>
 #include <sys/time.h>
 
 #include <assert.h>
@@ -15,6 +16,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 -r 08e010c3f251 tools/ioemu/vl.c
--- a/tools/ioemu/vl.c  Tue Apr 15 16:39:00 2008 +0100
+++ b/tools/ioemu/vl.c  Tue Apr 22 15:20:09 2008 +0200
@@ -6276,12 +6276,6 @@ void qemu_system_powerdown_request(void)
     powerdown_requested = 1;
     if (cpu_single_env)
         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)
@@ -7979,7 +7973,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 -r 08e010c3f251 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py   Tue Apr 15 16:39:00 2008 +0100
+++ b/tools/python/xen/xend/XendDomainInfo.py   Tue Apr 22 15:20:09 2008 +0200
@@ -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 -r 08e010c3f251 tools/python/xen/xend/image.py
--- a/tools/python/xen/xend/image.py    Tue Apr 15 16:39:00 2008 +0100
+++ b/tools/python/xen/xend/image.py    Tue Apr 22 15:20:09 2008 +0200
@@ -184,6 +184,30 @@ class ImageHandler:
     def buildDomain(self):
         """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)
+        os.mkfifo('/var/run/tap/qemu-read-%d' % domid, 0600)
+        os.mkfifo('/var/run/tap/qemu-write-%d' % domid, 0600)
+        
 
     # Return a list of cmd line args to the device models based on the
     # xm config file
@@ -411,6 +435,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):
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.