ia64/xen-unstable

changeset 17517:2bc699de2297

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>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Apr 23 16:57:23 2008 +0100 (2008-04-23)
parents 2573a22d408d
children 77dec8732cde
files tools/blktap/drivers/blktapctrl.c tools/blktap/drivers/tapdisk.h tools/ioemu/Makefile tools/ioemu/hw/xen_blktap.c tools/ioemu/tapdisk-ioemu.c tools/ioemu/vl.c tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/image.py
line diff
     1.1 --- a/tools/blktap/drivers/blktapctrl.c	Wed Apr 23 17:01:43 2008 +0100
     1.2 +++ b/tools/blktap/drivers/blktapctrl.c	Wed Apr 23 16:57:23 2008 +0100
     1.3 @@ -474,9 +474,8 @@ static int read_msg(int fd, int msgtype,
     1.4  
     1.5  }
     1.6  
     1.7 -int launch_tapdisk(char *wrctldev, char *rdctldev)
     1.8 +static int launch_tapdisk_provider(char **argv)
     1.9  {
    1.10 -	char *argv[] = { "tapdisk", wrctldev, rdctldev, NULL };
    1.11  	pid_t child;
    1.12  	
    1.13  	if ((child = fork()) < 0)
    1.14 @@ -490,7 +489,9 @@ int launch_tapdisk(char *wrctldev, char 
    1.15  			    i != STDERR_FILENO)
    1.16  				close(i);
    1.17  
    1.18 -		execvp("tapdisk", argv);
    1.19 +		execvp(argv[0], argv);
    1.20 +		DPRINTF("execvp failed: %d (%s)\n", errno, strerror(errno));
    1.21 +		DPRINTF("PATH = %s\n", getenv("PATH"));
    1.22  		_exit(1);
    1.23  	} else {
    1.24  		pid_t got;
    1.25 @@ -498,28 +499,78 @@ int launch_tapdisk(char *wrctldev, char 
    1.26  			got = waitpid(child, NULL, 0);
    1.27  		} while (got != child);
    1.28  	}
    1.29 +	return child;
    1.30 +}
    1.31 +
    1.32 +static int launch_tapdisk(char *wrctldev, char *rdctldev)
    1.33 +{
    1.34 +	char *argv[] = { "tapdisk", wrctldev, rdctldev, NULL };
    1.35 +
    1.36 +	if (launch_tapdisk_provider(argv) < 0)
    1.37 +		return -1;
    1.38 +
    1.39  	return 0;
    1.40  }
    1.41  
    1.42 -/* Connect to qemu-dm */
    1.43 -static int connect_qemu(blkif_t *blkif)
    1.44 +static int launch_tapdisk_ioemu(void)
    1.45 +{
    1.46 +	char *argv[] = { "tapdisk-ioemu", NULL };
    1.47 +	return launch_tapdisk_provider(argv);
    1.48 +}
    1.49 +
    1.50 +/* 
    1.51 + * Connect to an ioemu based disk provider (qemu-dm or tapdisk-ioemu)
    1.52 + *
    1.53 + * If the domain has a device model, connect to qemu-dm through the
    1.54 + * domain specific pipe. Otherwise use a single tapdisk-ioemu instance
    1.55 + * which is represented by domid 0 and provides access for Dom0 and
    1.56 + * all DomUs without device model.
    1.57 + */
    1.58 +static int connect_qemu(blkif_t *blkif, int domid)
    1.59  {
    1.60  	char *rdctldev, *wrctldev;
    1.61 +
    1.62 +	static int tapdisk_ioemu_pid = 0;
    1.63 +	static int dom0_readfd = 0;
    1.64 +	static int dom0_writefd = 0;
    1.65  	
    1.66 -	if (asprintf(&rdctldev, BLKTAP_CTRL_DIR "/qemu-read-%d", 
    1.67 -			blkif->domid) < 0)
    1.68 +	if (asprintf(&rdctldev, BLKTAP_CTRL_DIR "/qemu-read-%d", domid) < 0)
    1.69  		return -1;
    1.70  
    1.71 -	if (asprintf(&wrctldev, BLKTAP_CTRL_DIR "/qemu-write-%d", 
    1.72 -			blkif->domid) < 0) {
    1.73 +	if (asprintf(&wrctldev, BLKTAP_CTRL_DIR "/qemu-write-%d", domid) < 0) {
    1.74  		free(rdctldev);
    1.75  		return -1;
    1.76  	}
    1.77  
    1.78  	DPRINTF("Using qemu blktap pipe: %s\n", rdctldev);
    1.79  	
    1.80 -	blkif->fds[READ] = open_ctrl_socket(wrctldev);
    1.81 -	blkif->fds[WRITE] = open_ctrl_socket(rdctldev);
    1.82 +	if (domid == 0) {
    1.83 +		/*
    1.84 +		 * tapdisk-ioemu exits as soon as the last image is 
    1.85 +		 * disconnected. Check if it is still running.
    1.86 +		 */
    1.87 +		if (tapdisk_ioemu_pid == 0 || kill(tapdisk_ioemu_pid, 0)) {
    1.88 +			/* No device model and tapdisk-ioemu doesn't run yet */
    1.89 +			DPRINTF("Launching tapdisk-ioemu\n");
    1.90 +			tapdisk_ioemu_pid = launch_tapdisk_ioemu();
    1.91 +			
    1.92 +			dom0_readfd = open_ctrl_socket(wrctldev);
    1.93 +			dom0_writefd = open_ctrl_socket(rdctldev);
    1.94 +		}
    1.95 +
    1.96 +		DPRINTF("Using tapdisk-ioemu connection\n");
    1.97 +		blkif->fds[READ] = dom0_readfd;
    1.98 +		blkif->fds[WRITE] = dom0_writefd;
    1.99 +	} else if (access(rdctldev, R_OK | W_OK) == 0) {
   1.100 +		/* Use existing pipe to the device model */
   1.101 +		DPRINTF("Using qemu-dm connection\n");
   1.102 +		blkif->fds[READ] = open_ctrl_socket(wrctldev);
   1.103 +		blkif->fds[WRITE] = open_ctrl_socket(rdctldev);
   1.104 +	} else {
   1.105 +		/* No device model => try with tapdisk-ioemu */
   1.106 +		DPRINTF("No device model\n");
   1.107 +		connect_qemu(blkif, 0);
   1.108 +	}
   1.109  	
   1.110  	free(rdctldev);
   1.111  	free(wrctldev);
   1.112 @@ -599,7 +650,7 @@ int blktapctrl_new_blkif(blkif_t *blkif)
   1.113  
   1.114  		if (!exist) {
   1.115  			if (type == DISK_TYPE_IOEMU) {
   1.116 -				if (connect_qemu(blkif))
   1.117 +				if (connect_qemu(blkif, blkif->domid))
   1.118  					goto fail;
   1.119  			} else {
   1.120  				if (connect_tapdisk(blkif, minor))
     2.1 --- a/tools/blktap/drivers/tapdisk.h	Wed Apr 23 17:01:43 2008 +0100
     2.2 +++ b/tools/blktap/drivers/tapdisk.h	Wed Apr 23 16:57:23 2008 +0100
     2.3 @@ -235,7 +235,7 @@ static disk_info_t ioemu_disk = {
     2.4  	DISK_TYPE_IOEMU,
     2.5  	"ioemu disk",
     2.6  	"ioemu",
     2.7 -	0,
     2.8 +	1,
     2.9  #ifdef TAPDISK
    2.10  	NULL
    2.11  #endif
     3.1 --- a/tools/ioemu/Makefile	Wed Apr 23 17:01:43 2008 +0100
     3.2 +++ b/tools/ioemu/Makefile	Wed Apr 23 16:57:23 2008 +0100
     3.3 @@ -87,7 +87,7 @@ endif
     3.4  
     3.5  install: all $(if $(BUILD_DOCS),install-doc)
     3.6  	mkdir -p "$(DESTDIR)$(bindir)"
     3.7 -	$(INSTALL) -m 755 $(TOOLS) "$(DESTDIR)$(prefix)/sbin"
     3.8 +	$(INSTALL) -m 755 $(TOOLS) "$(DESTDIR)$(SBINDIR)"
     3.9  #	mkdir -p "$(DESTDIR)$(datadir)"
    3.10  #	for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
    3.11  #		video.x openbios-sparc32 linux_boot.bin pxe-ne2k_pci.bin \
     4.1 --- a/tools/ioemu/hw/xen_blktap.c	Wed Apr 23 17:01:43 2008 +0100
     4.2 +++ b/tools/ioemu/hw/xen_blktap.c	Wed Apr 23 16:57:23 2008 +0100
     4.3 @@ -581,17 +581,13 @@ static void handle_blktap_ctrlmsg(void* 
     4.4   */
     4.5  static int open_ctrl_socket(char *devname)
     4.6  {
     4.7 -	int ret;
     4.8  	int ipc_fd;
     4.9  
    4.10  	if (mkdir(BLKTAP_CTRL_DIR, 0755) == 0)
    4.11  		DPRINTF("Created %s directory\n", BLKTAP_CTRL_DIR);
    4.12  
    4.13 -	ret = mkfifo(devname,S_IRWXU|S_IRWXG|S_IRWXO);
    4.14 -	if ( (ret != 0) && (errno != EEXIST) ) {
    4.15 -		DPRINTF("ERROR: pipe failed (%d)\n", errno);
    4.16 +	if (access(devname, R_OK | W_OK))
    4.17  		return -1;
    4.18 -	}
    4.19  
    4.20  	ipc_fd = open(devname,O_RDWR|O_NONBLOCK);
    4.21  
    4.22 @@ -604,42 +600,6 @@ static int open_ctrl_socket(char *devnam
    4.23  }
    4.24  
    4.25  /**
    4.26 - * Unmaps all disks and closes their pipes
    4.27 - */
    4.28 -void shutdown_blktap(void)
    4.29 -{
    4.30 -	fd_list_entry_t *ptr;
    4.31 -	struct td_state *s;
    4.32 -	char *devname;
    4.33 -
    4.34 -	DPRINTF("Shutdown blktap\n");
    4.35 -
    4.36 -	/* Unmap all disks */
    4.37 -	ptr = fd_start;
    4.38 -	while (ptr != NULL) {
    4.39 -		s = ptr->s;
    4.40 -		unmap_disk(s);
    4.41 -		close(ptr->tap_fd);
    4.42 -		ptr = ptr->next;
    4.43 -	}
    4.44 -
    4.45 -	/* Delete control pipes */
    4.46 -	if (asprintf(&devname, BLKTAP_CTRL_DIR "/qemu-read-%d", domid) >= 0) {
    4.47 -		DPRINTF("Delete %s\n", devname);
    4.48 -		if (unlink(devname))
    4.49 -			DPRINTF("Could not delete: %s\n", strerror(errno));
    4.50 -		free(devname);
    4.51 -	}
    4.52 -	
    4.53 -	if (asprintf(&devname, BLKTAP_CTRL_DIR "/qemu-write-%d", domid) >= 0) {	
    4.54 -		DPRINTF("Delete %s\n", devname);
    4.55 -		if (unlink(devname))
    4.56 -			DPRINTF("Could not delete: %s\n", strerror(errno));
    4.57 -		free(devname);
    4.58 -	}
    4.59 -}
    4.60 -
    4.61 -/**
    4.62   * Initialize the blktap interface, i.e. open a pair of pipes in /var/run/tap
    4.63   * and register a fd handler.
    4.64   *
    4.65 @@ -679,8 +639,5 @@ int init_blktap(void)
    4.66  	/* Attach a handler to the read pipe (called from qemu main loop) */
    4.67  	qemu_set_fd_handler2(read_fd, NULL, &handle_blktap_ctrlmsg, NULL, NULL);
    4.68  
    4.69 -	/* Register handler to clean up when the domain is destroyed */
    4.70 -	atexit(&shutdown_blktap);
    4.71 -
    4.72  	return 0;
    4.73  }
     5.1 --- a/tools/ioemu/tapdisk-ioemu.c	Wed Apr 23 17:01:43 2008 +0100
     5.2 +++ b/tools/ioemu/tapdisk-ioemu.c	Wed Apr 23 16:57:23 2008 +0100
     5.3 @@ -4,6 +4,7 @@
     5.4  #include <string.h>
     5.5  #include <stdint.h>
     5.6  #include <signal.h>
     5.7 +#include <unistd.h>
     5.8  #include <sys/time.h>
     5.9  
    5.10  #include <assert.h>
    5.11 @@ -16,6 +17,8 @@ extern void bdrv_init(void);
    5.12  extern void *qemu_mallocz(size_t size);
    5.13  extern void qemu_free(void *ptr);
    5.14  
    5.15 +extern void *fd_start;
    5.16 +
    5.17  int domid = 0;
    5.18  FILE* logfile;
    5.19  
    5.20 @@ -95,12 +98,17 @@ int main(void)
    5.21      int max_fd;
    5.22      fd_set rfds;
    5.23      struct timeval tv;
    5.24 +    void *old_fd_start = NULL;
    5.25  
    5.26      logfile = stderr;
    5.27      
    5.28      bdrv_init();
    5.29      qemu_aio_init();
    5.30      init_blktap();
    5.31 +
    5.32 +    /* Daemonize */
    5.33 +    if (fork() != 0)
    5.34 +    	exit(0);
    5.35     
    5.36      /* 
    5.37       * Main loop: Pass events to the corrsponding handlers and check for
    5.38 @@ -137,6 +145,12 @@ int main(void)
    5.39              } else 
    5.40                  pioh = &ioh->next;
    5.41          }
    5.42 +
    5.43 +        /* Exit when the last image has been closed */
    5.44 +        if (old_fd_start != NULL && fd_start == NULL)
    5.45 +            exit(0);
    5.46 +
    5.47 +        old_fd_start = fd_start;
    5.48      }
    5.49      return 0;
    5.50  }
     6.1 --- a/tools/ioemu/vl.c	Wed Apr 23 17:01:43 2008 +0100
     6.2 +++ b/tools/ioemu/vl.c	Wed Apr 23 16:57:23 2008 +0100
     6.3 @@ -6275,12 +6275,6 @@ void qemu_system_powerdown_request(void)
     6.4          cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
     6.5  }
     6.6  
     6.7 -static void qemu_sighup_handler(int signal)
     6.8 -{
     6.9 -    fprintf(stderr, "Received SIGHUP, terminating.\n");
    6.10 -    exit(0);
    6.11 -}
    6.12 -
    6.13  void main_loop_wait(int timeout)
    6.14  {
    6.15      IOHandlerRecord *ioh;
    6.16 @@ -7976,7 +7970,7 @@ int main(int argc, char **argv)
    6.17  
    6.18  #ifndef CONFIG_STUBDOM
    6.19      /* Unblock SIGTERM and SIGHUP, which may have been blocked by the caller */
    6.20 -    signal(SIGHUP, qemu_sighup_handler);
    6.21 +    signal(SIGHUP, SIG_DFL);
    6.22      sigemptyset(&set);
    6.23      sigaddset(&set, SIGTERM);
    6.24      sigaddset(&set, SIGHUP);
     7.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Wed Apr 23 17:01:43 2008 +0100
     7.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Wed Apr 23 16:57:23 2008 +0100
     7.3 @@ -1837,6 +1837,9 @@ class XendDomainInfo:
     7.4  
     7.5          @raise: VmError for invalid devices
     7.6          """
     7.7 +        if self.image:
     7.8 +            self.image.prepareEnvironment()
     7.9 +
    7.10          ordered_refs = self.info.ordered_device_refs()
    7.11          for dev_uuid in ordered_refs:
    7.12              devclass, config = self.info['devices'][dev_uuid]
     8.1 --- a/tools/python/xen/xend/image.py	Wed Apr 23 17:01:43 2008 +0100
     8.2 +++ b/tools/python/xen/xend/image.py	Wed Apr 23 16:57:23 2008 +0100
     8.3 @@ -185,6 +185,42 @@ class ImageHandler:
     8.4          """Build the domain. Define in subclass."""
     8.5          raise NotImplementedError()
     8.6  
     8.7 +    def prepareEnvironment(self):
     8.8 +        """Prepare the environment for the execution of the domain. This
     8.9 +        method is called before any devices are set up."""
    8.10 +        
    8.11 +        domid = self.vm.getDomid()
    8.12 +	
    8.13 +        # Delete left-over pipes
    8.14 +        try:
    8.15 +            os.unlink('/var/run/tap/qemu-read-%d' % domid)
    8.16 +            os.unlink('/var/run/tap/qemu-write-%d' % domid)
    8.17 +        except:
    8.18 +            pass
    8.19 +
    8.20 +        # No device model, don't create pipes
    8.21 +        if self.device_model is None:
    8.22 +            return
    8.23 +
    8.24 +        # If we use a device model, the pipes for communication between
    8.25 +        # blktapctrl and ioemu must be present before the devices are 
    8.26 +        # created (blktapctrl must access them for new block devices)
    8.27 +
    8.28 +        # mkdir throws an exception if the path already exists
    8.29 +        try:
    8.30 +            os.mkdir('/var/run/tap', 0755)
    8.31 +        except:
    8.32 +            pass
    8.33 +
    8.34 +        try:
    8.35 +            os.mkfifo('/var/run/tap/qemu-read-%d' % domid, 0600)
    8.36 +            os.mkfifo('/var/run/tap/qemu-write-%d' % domid, 0600)
    8.37 +        except OSError, e:
    8.38 +            log.warn('Could not create blktap pipes for domain %d' % domid)
    8.39 +            log.exception(e)
    8.40 +            pass
    8.41 +
    8.42 +
    8.43      # Return a list of cmd line args to the device models based on the
    8.44      # xm config file
    8.45      def parseDeviceModelArgs(self, vmConfig):
    8.46 @@ -411,6 +447,12 @@ class ImageHandler:
    8.47              self.pid = None
    8.48              state = xstransact.Remove("/local/domain/0/device-model/%i"
    8.49                                        % self.vm.getDomid())
    8.50 +            
    8.51 +            try:
    8.52 +                os.unlink('/var/run/tap/qemu-read-%d' % self.vm.getDomid())
    8.53 +                os.unlink('/var/run/tap/qemu-write-%d' % self.vm.getDomid())
    8.54 +            except:
    8.55 +                pass
    8.56  
    8.57  
    8.58  class LinuxImageHandler(ImageHandler):