# HG changeset patch # User Daniel Stodden # Date 1275947596 25200 # Node ID ccef87cf5f4125061e46c7eb0d1483e6f369fb77 # Parent 3ea1751e3fe79c53acec392ee060b34491925235 blktap2: The tap-ctl userspace control utility and library. Tapdisk control in userspace, a replacement for the original blktap2 control stack, which had to pass a kernel space interface based on sysfs nodes. All tapdisk processes listen for commands on a unix stream socket. The control library supports scanning the socket namespace for running tapdisks, VBD minors allocated, associated images and state inquiry. Control operations include allocating/releasing devices, spawning tapdisks, opening/closing images, attaching disk images to devices. disk pause/resume operations and runtime switching of disk images. Signed-off-by: Jake Wires Signed-off-by: Daniel Stodden diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/Makefile --- a/tools/blktap2/Makefile Mon Jun 07 14:53:15 2010 -0700 +++ b/tools/blktap2/Makefile Mon Jun 07 14:53:16 2010 -0700 @@ -9,6 +9,7 @@ SUBDIRS-y += lvm SUBDIRS-y += vhd SUBDIRS-y += drivers +SUBDIRS-y += control clean: rm -rf *.a *.so *.o *.rpm $(LIB) *~ $(DEPS) TAGS diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/Makefile Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,57 @@ +XEN_ROOT := ../../../ +include $(XEN_ROOT)/tools/Rules.mk + +IBIN = tap-ctl +INST_DIR = /usr/sbin + +CFLAGS += -Werror +CFLAGS += -Wno-unused +CFLAGS += -I../include -I../drivers +CFLAGS += -I$(XEN_INCLUDE) -I$(XEN_LIBXC) +CFLAGS += -D_GNU_SOURCE +CFLAGS += -DTAPCTL + +# Get gcc to generate the dependencies for us. +CFLAGS += -Wp,-MD,.$(@F).d +DEPS = .*.d + +CTL_OBJS := tap-ctl-ipc.o +CTL_OBJS += tap-ctl-list.o +CTL_OBJS += tap-ctl-allocate.o +CTL_OBJS += tap-ctl-free.o +CTL_OBJS += tap-ctl-create.o +CTL_OBJS += tap-ctl-destroy.o +CTL_OBJS += tap-ctl-spawn.o +CTL_OBJS += tap-ctl-attach.o +CTL_OBJS += tap-ctl-detach.o +CTL_OBJS += tap-ctl-open.o +CTL_OBJS += tap-ctl-close.o +CTL_OBJS += tap-ctl-pause.o +CTL_OBJS += tap-ctl-unpause.o +CTL_OBJS += tap-ctl-major.o +CTL_OBJS += tap-ctl-check.o + +OBJS = $(CTL_OBJS) +LIBS = libblktapctl.a + +all: build + +build: $(IBIN) + +tap-ctl: tap-ctl.o libblktapctl.a + $(CC) $(CFLAGS) -o $@ $^ + +libblktapctl.a: $(CTL_OBJS) + ar r $@ $^ + +install: all + $(INSTALL_DIR) -p $(DESTDIR)$(INST_DIR) + $(INSTALL_PROG) $(IBIN) $(DESTDIR)$(INST_DIR) + +clean: + rm -f $(OBJS) $(DEPS) $(IBIN) $(LIBS) + rm -f *~ + +.PHONY: all build clean install + +-include $(DEPS) diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-allocate.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-allocate.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tap-ctl.h" +#include "blktap2.h" + +static int +tap_ctl_prepare_directory(const char *dir) +{ + int err; + char *ptr, *name, *start; + + err = access(dir, W_OK | R_OK); + if (!err) + return 0; + + name = strdup(dir); + if (!name) + return ENOMEM; + + start = name; + + for (;;) { + ptr = strchr(start + 1, '/'); + if (ptr) + *ptr = '\0'; + + err = mkdir(name, 0755); + if (err && errno != EEXIST) { + PERROR("mkdir %s", name); + err = errno; + break; + } + + if (!ptr) + break; + else { + *ptr = '/'; + start = ptr + 1; + } + } + + free(name); + return err; +} + +static int +tap_ctl_make_device(const char *devname, const int major, + const int minor, const int perm) +{ + int err; + char *copy, *dir; + + copy = strdup(devname); + if (!copy) + return ENOMEM; + + dir = dirname(copy); + + err = tap_ctl_prepare_directory(dir); + free(copy); + + if (err) + return err; + + if (!access(devname, F_OK)) + if (unlink(devname)) { + PERROR("unlink %s", devname); + return errno; + } + + err = mknod(devname, perm, makedev(major, minor)); + if (err) { + PERROR("mknod %s", devname); + return errno; + } + + return 0; +} + +static int +tap_ctl_check_environment(void) +{ + FILE *f; + int err, minor; + char name[256]; + + err = tap_ctl_prepare_directory(BLKTAP2_CONTROL_DIR); + if (err) + return err; + + if (!access(BLKTAP2_CONTROL_DEVICE, R_OK | W_OK)) + return 0; + + memset(name, 0, sizeof(name)); + + f = fopen("/proc/misc", "r"); + if (!f) { + EPRINTF("failed to open /proc/misc: %d\n", errno); + return errno; + } + + while (fscanf(f, "%d %256s", &minor, name) == 2) + if (!strcmp(name, BLKTAP2_CONTROL_NAME)) { + err = tap_ctl_make_device(BLKTAP2_CONTROL_DEVICE, + MISC_MAJOR, + minor, S_IFCHR | 0600); + goto out; + } + + err = ENOSYS; + EPRINTF("didn't find %s in /proc/misc\n", BLKTAP2_CONTROL_NAME); + +out: + fclose(f); + return err; +} + +static int +tap_ctl_allocate_device(int *minor, char **devname) +{ + char *name; + int fd, err; + struct blktap2_handle handle; + + *minor = -1; + if (!devname) + return EINVAL; + + fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY); + if (fd == -1) { + EPRINTF("failed to open control device: %d\n", errno); + return errno; + } + + err = ioctl(fd, BLKTAP2_IOCTL_ALLOC_TAP, &handle); + close(fd); + if (err == -1) { + EPRINTF("failed to allocate new device: %d\n", errno); + return errno; + } + + err = asprintf(&name, "%s%d", BLKTAP2_RING_DEVICE, handle.minor); + if (err == -1) { + err = ENOMEM; + goto fail; + } + + err = tap_ctl_make_device(name, handle.ring, + handle.minor, S_IFCHR | 0600); + free(name); + if (err) { + EPRINTF("creating ring device for %d failed: %d\n", + handle.minor, err); + goto fail; + } + + if (*devname) + name = *devname; + else { + err = asprintf(&name, "%s%d", + BLKTAP2_IO_DEVICE, handle.minor); + if (err == -1) { + err = ENOMEM; + goto fail; + } + *devname = name; + } + + err = tap_ctl_make_device(name, handle.device, + handle.minor, S_IFBLK | 0600); + if (err) { + EPRINTF("creating IO device for %d failed: %d\n", + handle.minor, err); + goto fail; + } + + DBG("new interface: ring: %u, device: %u, minor: %u\n", + handle.ring, handle.device, handle.minor); + + *minor = handle.minor; + return 0; + +fail: + tap_ctl_free(handle.minor); + return err; +} + +int +tap_ctl_allocate(int *minor, char **devname) +{ + int err; + + *minor = -1; + + err = tap_ctl_check_environment(); + if (err) + return err; + + err = tap_ctl_allocate_device(minor, devname); + if (err) + return err; + + return 0; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-attach.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-attach.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +#include "tap-ctl.h" + +int +tap_ctl_attach(const int id, const int minor) +{ + int err; + tapdisk_message_t message; + + memset(&message, 0, sizeof(message)); + message.type = TAPDISK_MESSAGE_ATTACH; + message.cookie = minor; + + err = tap_ctl_connect_send_and_receive(id, &message, 5); + if (err) + return err; + + if (message.type == TAPDISK_MESSAGE_ATTACH_RSP) { + err = message.u.response.error; + if (err) + EPRINTF("attach failed: %d\n", err); + } else { + EPRINTF("got unexpected result '%s' from %d\n", + tapdisk_message_name(message.type), id); + err = EINVAL; + } + + return err; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-check.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-check.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include + +#include "tap-ctl.h" +#include "blktap2.h" + +int +tap_ctl_check_blktap(const char **msg) +{ + FILE *f; + int err = 0, minor; + char name[32]; + + memset(name, 0, sizeof(name)); + + f = fopen("/proc/misc", "r"); + if (!f) { + *msg = "failed to open /proc/misc"; + return -errno; + } + + while (fscanf(f, "%d %32s", &minor, name) == 2) { + if (!strcmp(name, BLKTAP2_CONTROL_NAME)) + goto out; + } + + err = -ENOSYS; + *msg = "blktap kernel module not installed"; + +out: + fclose(f); + return err; +} + +int +tap_ctl_check(const char **msg) +{ + int err; + uid_t uid; + + err = tap_ctl_check_blktap(msg); + if (err) + goto out; + + err = 0; + *msg = "ok"; + +out: + return err; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-close.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-close.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include + +#include "tap-ctl.h" + +static int +__tap_ctl_close(const int id, const int minor, const int force) +{ + int err; + tapdisk_message_t message; + + memset(&message, 0, sizeof(message)); + message.type = TAPDISK_MESSAGE_CLOSE; + if (force) + message.type = TAPDISK_MESSAGE_FORCE_SHUTDOWN; + message.cookie = minor; + + err = tap_ctl_connect_send_and_receive(id, &message, 5); + if (err) + return err; + + if (message.type == TAPDISK_MESSAGE_CLOSE_RSP) { + err = message.u.response.error; + if (err) + EPRINTF("close failed: %d\n", err); + } else { + EPRINTF("got unexpected result '%s' from %d\n", + tapdisk_message_name(message.type), id); + err = EINVAL; + } + + return err; +} + +int +tap_ctl_close(const int id, const int minor, const int force) +{ + int i, err; + + for (i = 0; i < 20; i++) { + err = __tap_ctl_close(id, minor, force); + if (!err) + return 0; + + err = (err < 0 ? -err : err); + if (err != EAGAIN) { + EPRINTF("close failed: %d\n", err); + return err; + } + + usleep(1000); + } + + EPRINTF("close timed out\n"); + return EIO; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-create.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-create.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +#include "tap-ctl.h" +#include "blktap2.h" + +int +tap_ctl_create(const char *params, char **devname) +{ + int err, id, minor; + + err = tap_ctl_allocate(&minor, devname); + if (err) + return err; + + id = tap_ctl_spawn(); + if (id < 0) + goto destroy; + + err = tap_ctl_attach(id, minor); + if (err) + goto destroy; + + err = tap_ctl_open(id, minor, params); + if (err) + goto detach; + + return 0; + +detach: + tap_ctl_detach(id, minor); +destroy: + tap_ctl_free(minor); + return err; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-destroy.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-destroy.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include + +#include "tap-ctl.h" +#include "blktap2.h" + +int +tap_ctl_destroy(const int id, const int minor) +{ + int err; + + err = tap_ctl_close(id, minor, 0); + if (err) + return err; + + err = tap_ctl_detach(id, minor); + if (err) + return err; + + err = tap_ctl_free(minor); + if (err) + return err; + + return 0; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-detach.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-detach.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +#include "tap-ctl.h" + +int +tap_ctl_detach(const int id, const int minor) +{ + int err; + tapdisk_message_t message; + + memset(&message, 0, sizeof(message)); + message.type = TAPDISK_MESSAGE_DETACH; + message.cookie = minor; + + err = tap_ctl_connect_send_and_receive(id, &message, 5); + if (err) + return err; + + if (message.type == TAPDISK_MESSAGE_DETACH_RSP) { + err = message.u.response.error; + if (err < 0) + printf("detach failed: %d\n", err); + } else { + printf("got unexpected result '%s' from %d\n", + tapdisk_message_name(message.type), id); + err = EINVAL; + } + + return err; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-free.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-free.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "tap-ctl.h" +#include "blktap2.h" + +int +tap_ctl_free(const int minor) +{ + int fd, err; + + fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY); + if (fd == -1) { + EPRINTF("failed to open control device: %d\n", errno); + return errno; + } + + err = ioctl(fd, BLKTAP2_IOCTL_FREE_TAP, minor); + close(fd); + + return err; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-ipc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-ipc.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tap-ctl.h" +#include "blktap2.h" + +int tap_ctl_debug = 0; + +int +tap_ctl_read_message(int fd, tapdisk_message_t *message, int timeout) +{ + fd_set readfds; + int ret, len, offset; + struct timeval tv, *t; + + t = NULL; + offset = 0; + len = sizeof(tapdisk_message_t); + + if (timeout) { + tv.tv_sec = timeout; + tv.tv_usec = 0; + t = &tv; + } + + memset(message, 0, sizeof(tapdisk_message_t)); + + while (offset < len) { + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + ret = select(fd + 1, &readfds, NULL, NULL, t); + if (ret == -1) + break; + else if (FD_ISSET(fd, &readfds)) { + ret = read(fd, message + offset, len - offset); + if (ret <= 0) + break; + offset += ret; + } else + break; + } + + if (offset != len) { + EPRINTF("failure reading message\n"); + return -EIO; + } + + DBG("received '%s' message (uuid = %u)\n", + tapdisk_message_name(message->type), message->cookie); + + return 0; +} + +int +tap_ctl_write_message(int fd, tapdisk_message_t *message, int timeout) +{ + fd_set writefds; + int ret, len, offset; + struct timeval tv, *t; + + t = NULL; + offset = 0; + len = sizeof(tapdisk_message_t); + + if (timeout) { + tv.tv_sec = timeout; + tv.tv_usec = 0; + t = &tv; + } + + DBG("sending '%s' message (uuid = %u)\n", + tapdisk_message_name(message->type), message->cookie); + + while (offset < len) { + FD_ZERO(&writefds); + FD_SET(fd, &writefds); + + /* we don't bother reinitializing tv. at worst, it will wait a + * bit more time than expected. */ + + ret = select(fd + 1, NULL, &writefds, NULL, t); + if (ret == -1) + break; + else if (FD_ISSET(fd, &writefds)) { + ret = write(fd, message + offset, len - offset); + if (ret <= 0) + break; + offset += ret; + } else + break; + } + + if (offset != len) { + EPRINTF("failure writing message\n"); + return -EIO; + } + + return 0; +} + +int +tap_ctl_send_and_receive(int sfd, tapdisk_message_t *message, int timeout) +{ + int err; + + err = tap_ctl_write_message(sfd, message, timeout); + if (err) { + EPRINTF("failed to send '%s' message\n", + tapdisk_message_name(message->type)); + return err; + } + + err = tap_ctl_read_message(sfd, message, timeout); + if (err) { + EPRINTF("failed to receive '%s' message\n", + tapdisk_message_name(message->type)); + return err; + } + + return 0; +} + +char * +tap_ctl_socket_name(int id) +{ + char *name; + + if (asprintf(&name, "%s/%s%d", + BLKTAP2_CONTROL_DIR, BLKTAP2_CONTROL_SOCKET, id) == -1) + return NULL; + + return name; +} + +int +tap_ctl_connect(const char *name, int *sfd) +{ + int fd, err; + struct sockaddr_un saddr; + + *sfd = -1; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + EPRINTF("couldn't create socket for %s: %d\n", name, errno); + return -errno; + } + + memset(&saddr, 0, sizeof(saddr)); + saddr.sun_family = AF_UNIX; + strcpy(saddr.sun_path, name); + + err = connect(fd, (const struct sockaddr *)&saddr, sizeof(saddr)); + if (err) { + EPRINTF("couldn't connect to %s: %d\n", name, errno); + close(fd); + return -errno; + } + + *sfd = fd; + return 0; +} + +int +tap_ctl_connect_id(int id, int *sfd) +{ + int err; + char *name; + + *sfd = -1; + + if (id < 0) { + EPRINTF("invalid id %d\n", id); + return -EINVAL; + } + + name = tap_ctl_socket_name(id); + if (!name) { + EPRINTF("couldn't name socket for %d\n", id); + return -ENOMEM; + } + + err = tap_ctl_connect(name, sfd); + free(name); + + return err; +} + +int +tap_ctl_connect_send_and_receive(int id, tapdisk_message_t *message, int timeout) +{ + int err, sfd; + + err = tap_ctl_connect_id(id, &sfd); + if (err) + return err; + + err = tap_ctl_send_and_receive(sfd, message, timeout); + + close(sfd); + return err; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-list.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-list.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "tap-ctl.h" +#include "blktap2.h" +#include "list.h" + +static void +free_list(tap_list_t *entry) +{ + if (entry->type) { + free(entry->type); + entry->type = NULL; + } + + if (entry->path) { + free(entry->path); + entry->path = NULL; + } + + free(entry); +} + +int +_parse_params(const char *params, char **type, char **path) +{ + char *ptr; + size_t len; + + ptr = strchr(params, ':'); + if (!ptr) + return -EINVAL; + + len = ptr - params; + + *type = strndup(params, len); + *path = strdup(params + len + 1); + + if (!*type || !*path) { + free(*type); + *type = NULL; + + free(*path); + *path = NULL; + + return -errno; + } + + return 0; +} + +static int +init_list(tap_list_t *entry, + int tap_id, pid_t tap_pid, int vbd_minor, int vbd_state, + const char *params) +{ + int err = 0; + + entry->id = tap_id; + entry->pid = tap_pid; + entry->minor = vbd_minor; + entry->state = vbd_state; + + if (params) + err = _parse_params(params, &entry->type, &entry->path); + + return err; +} + +void +tap_ctl_free_list(tap_list_t **list) +{ + tap_list_t **_entry; + + for (_entry = list; *_entry != NULL; ++_entry) + free_list(*_entry); + + free(list); +} + +static tap_list_t** +tap_ctl_alloc_list(int n) +{ + tap_list_t **list, *entry; + size_t size; + int i; + + size = sizeof(tap_list_t*) * (n+1); + list = malloc(size); + if (!list) + goto fail; + + memset(list, 0, size); + + for (i = 0; i < n; ++i) { + tap_list_t *entry; + + entry = malloc(sizeof(tap_list_t)); + if (!entry) + goto fail; + + memset(entry, 0, sizeof(tap_list_t)); + + list[i] = entry; + } + + return list; + +fail: + if (list) + tap_ctl_free_list(list); + + return NULL; +} + +static int +tap_ctl_list_length(const tap_list_t **list) +{ + const tap_list_t **_entry; + int n; + + n = 0; + for (_entry = list; *_entry != NULL; ++_entry) + n++; + + return n; +} + +static int +_tap_minor_cmp(const void *a, const void *b) +{ + return *(int*)a - *(int*)b; +} + +int +_tap_ctl_find_minors(int **_minorv) +{ + glob_t glbuf = { 0 }; + const char *pattern, *format; + int *minorv = NULL, n_minors = 0; + int err, i; + + pattern = BLKTAP2_SYSFS_DIR"/blktap*"; + format = BLKTAP2_SYSFS_DIR"/blktap%d"; + + n_minors = 0; + minorv = NULL; + + err = glob(pattern, 0, NULL, &glbuf); + switch (err) { + case GLOB_NOMATCH: + goto done; + + case GLOB_ABORTED: + case GLOB_NOSPACE: + err = -errno; + EPRINTF("%s: glob failed, err %d", pattern, err); + goto fail; + } + + minorv = malloc(sizeof(int) * glbuf.gl_pathc); + if (!minorv) { + err = -errno; + goto fail; + } + + for (i = 0; i < glbuf.gl_pathc; ++i) { + int n; + + n = sscanf(glbuf.gl_pathv[i], format, &minorv[n_minors]); + if (n != 1) + continue; + + n_minors++; + } + + qsort(minorv, n_minors, sizeof(int), _tap_minor_cmp); + +done: + *_minorv = minorv; + err = 0; + +out: + if (glbuf.gl_pathv) + globfree(&glbuf); + + return err ? : n_minors; + +fail: + if (minorv) + free(minorv); + + goto out; +} + +struct tapdisk { + int id; + pid_t pid; + struct list_head list; +}; + +static int +_tap_tapdisk_cmp(const void *a, const void *b) +{ + return ((struct tapdisk*)a)->id - ((struct tapdisk*)b)->id; +} + +int +_tap_ctl_find_tapdisks(struct tapdisk **_tapv) +{ + glob_t glbuf = { 0 }; + const char *pattern, *format; + struct tapdisk *tapv = NULL; + int err, i, n_taps = 0; + + pattern = BLKTAP2_CONTROL_DIR"/"BLKTAP2_CONTROL_SOCKET"*"; + format = BLKTAP2_CONTROL_DIR"/"BLKTAP2_CONTROL_SOCKET"%d"; + + n_taps = 0; + tapv = NULL; + + err = glob(pattern, 0, NULL, &glbuf); + switch (err) { + case GLOB_NOMATCH: + goto done; + + case GLOB_ABORTED: + case GLOB_NOSPACE: + err = -errno; + EPRINTF("%s: glob failed, err %d", pattern, err); + goto fail; + } + + tapv = malloc(sizeof(struct tapdisk) * glbuf.gl_pathc); + if (!tapv) { + err = -errno; + goto fail; + } + + for (i = 0; i < glbuf.gl_pathc; ++i) { + struct tapdisk *tap; + int n; + + tap = &tapv[n_taps]; + + err = sscanf(glbuf.gl_pathv[i], format, &tap->id); + if (err != 1) + continue; + + tap->pid = tap_ctl_get_pid(tap->id); + if (tap->pid < 0) + continue; + + n_taps++; + } + + qsort(tapv, n_taps, sizeof(struct tapdisk), _tap_tapdisk_cmp); + + for (i = 0; i < n_taps; ++i) + INIT_LIST_HEAD(&tapv[i].list); + +done: + *_tapv = tapv; + err = 0; + +out: + if (glbuf.gl_pathv) + globfree(&glbuf); + + return err ? : n_taps; + +fail: + if (tapv) + free(tapv); + + goto out; +} + +struct tapdisk_list { + int minor; + int state; + char *params; + struct list_head entry; +}; + +int +_tap_ctl_list_tapdisk(int id, struct list_head *_list) +{ + tapdisk_message_t message; + struct list_head list; + struct tapdisk_list *tl, *next; + int err, sfd; + + err = tap_ctl_connect_id(id, &sfd); + if (err) + return err; + + memset(&message, 0, sizeof(message)); + message.type = TAPDISK_MESSAGE_LIST; + message.cookie = -1; + + err = tap_ctl_write_message(sfd, &message, 2); + if (err) + return err; + + INIT_LIST_HEAD(&list); + do { + err = tap_ctl_read_message(sfd, &message, 2); + if (err) { + err = -EPROTO; + break; + } + + if (message.u.list.count == 0) + break; + + tl = malloc(sizeof(struct tapdisk_list)); + if (!tl) { + err = -ENOMEM; + break; + } + + tl->minor = message.u.list.minor; + tl->state = message.u.list.state; + if (message.u.list.path[0] != 0) { + tl->params = strndup(message.u.list.path, + sizeof(message.u.list.path)); + if (!tl->params) { + err = -errno; + break; + } + } else + tl->params = NULL; + + list_add(&tl->entry, &list); + } while (1); + + if (err) + list_for_each_entry_safe(tl, next, &list, entry) { + list_del(&tl->entry); + free(tl->params); + free(tl); + } + + close(sfd); + list_splice(&list, _list); + return err; +} + +void +_tap_ctl_free_tapdisks(struct tapdisk *tapv, int n_taps) +{ + struct tapdisk *tap; + + for (tap = tapv; tap < &tapv[n_taps]; ++tap) { + struct tapdisk_list *tl; + + list_for_each_entry(tl, &tap->list, entry) { + free(tl->params); + free(tl); + } + } + + free(tapv); +} + +int +_tap_list_join3(int n_minors, int *minorv, int n_taps, struct tapdisk *tapv, + tap_list_t ***_list) +{ + tap_list_t **list, **_entry, *entry; + int i, _m, err; + + list = tap_ctl_alloc_list(n_minors + n_taps); + if (!list) { + err = -ENOMEM; + goto fail; + } + + _entry = list; + + for (i = 0; i < n_taps; ++i) { + struct tapdisk *tap = &tapv[i]; + struct tapdisk_list *tl; + + /* orphaned tapdisk */ + if (list_empty(&tap->list)) { + err = init_list(*_entry++, tap->id, tap->pid, -1, -1, NULL); + if (err) + goto fail; + continue; + } + + list_for_each_entry(tl, &tap->list, entry) { + + err = init_list(*_entry++, + tap->id, tap->pid, + tl->minor, tl->state, tl->params); + if (err) + goto fail; + + if (tl->minor >= 0) { + /* clear minor */ + for (_m = 0; _m < n_minors; ++_m) { + if (minorv[_m] == tl->minor) { + minorv[_m] = -1; + break; + } + } + } + } + } + + /* orphaned minors */ + for (_m = 0; _m < n_minors; ++_m) { + int minor = minorv[_m]; + if (minor >= 0) { + err = init_list(*_entry++, -1, -1, minor, -1, NULL); + if (err) + goto fail; + } + } + + /* free extraneous list entries */ + for (; *_entry != NULL; ++entry) { + free_list(*_entry); + *_entry = NULL; + } + + *_list = list; + + return 0; + +fail: + if (list) + tap_ctl_free_list(list); + + return err; +} + +int +tap_ctl_list(tap_list_t ***list) +{ + int n_taps, n_minors, err, *minorv; + struct tapdisk *tapv, *tap; + + n_taps = -1; + n_minors = -1; + + err = n_minors = _tap_ctl_find_minors(&minorv); + if (err < 0) + goto out; + + err = n_taps = _tap_ctl_find_tapdisks(&tapv); + if (err < 0) + goto out; + + for (tap = tapv; tap < &tapv[n_taps]; ++tap) { + err = _tap_ctl_list_tapdisk(tap->id, &tap->list); + if (err) + goto out; + } + + err = _tap_list_join3(n_minors, minorv, n_taps, tapv, list); + +out: + if (n_taps > 0) + _tap_ctl_free_tapdisks(tapv, n_taps); + + if (n_minors > 0) + free(minorv); + + return err; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-major.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-major.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "tap-ctl.h" + +int +tap_ctl_blk_major(void) +{ + FILE *devices; + int rv, major; + + devices = fopen("/proc/devices", "r"); + if (!devices) { + rv = -errno; + goto out; + } + + do { + char buf[32], *s; + int n, offset; + + s = fgets(buf, sizeof(buf), devices); + if (!s) + break; + + major = -ENODEV; + offset = 0; + + n = sscanf(buf, "%d tapdev%n", &major, &offset); + if (n == 1 && offset) + break; + } while (1); + + rv = major; + +out: + if (devices) + fclose(devices); + + return rv; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-open.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-open.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include + +#include "tap-ctl.h" +#include "blktaplib.h" + +int +tap_ctl_open(const int id, const int minor, const char *params) +{ + int err; + tapdisk_message_t message; + + memset(&message, 0, sizeof(message)); + message.type = TAPDISK_MESSAGE_OPEN; + message.cookie = minor; + message.u.params.storage = TAPDISK_STORAGE_TYPE_DEFAULT; + message.u.params.devnum = minor; + + err = snprintf(message.u.params.path, + sizeof(message.u.params.path) - 1, "%s", params); + if (err >= sizeof(message.u.params.path)) { + EPRINTF("name too long\n"); + return ENAMETOOLONG; + } + + err = tap_ctl_connect_send_and_receive(id, &message, 5); + if (err) + return err; + + switch (message.type) { + case TAPDISK_MESSAGE_OPEN_RSP: + break; + case TAPDISK_MESSAGE_ERROR: + err = -message.u.response.error; + EPRINTF("open failed, err %d\n", err); + break; + default: + EPRINTF("got unexpected result '%s' from %d\n", + tapdisk_message_name(message.type), id); + err = EINVAL; + } + + return err; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-pause.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-pause.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +#include "tap-ctl.h" + +int +tap_ctl_pause(const int id, const int minor) +{ + int err; + tapdisk_message_t message; + + memset(&message, 0, sizeof(message)); + message.type = TAPDISK_MESSAGE_PAUSE; + message.cookie = minor; + + err = tap_ctl_connect_send_and_receive(id, &message, 5); + if (err) + return err; + + if (message.type == TAPDISK_MESSAGE_PAUSE_RSP) + err = message.u.response.error; + else { + err = EINVAL; + EPRINTF("got unexpected result '%s' from %d\n", + tapdisk_message_name(message.type), id); + } + + return err; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-spawn.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-spawn.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "tap-ctl.h" +#include "blktap2.h" + +static pid_t +__tap_ctl_spawn(int *readfd) +{ + int err, child, channel[2]; + char *tapdisk; + + if (pipe(channel)) { + EPRINTF("pipe failed: %d\n", errno); + return -errno; + } + + if ((child = fork()) == -1) { + EPRINTF("fork failed: %d\n", errno); + return -errno; + } + + if (child) { + close(channel[1]); + *readfd = channel[0]; + return child; + } + + if (dup2(channel[1], STDOUT_FILENO) == -1) { + EPRINTF("dup2 failed: %d\n", errno); + exit(errno); + } + + if (dup2(channel[1], STDERR_FILENO) == -1) { + EPRINTF("dup2 failed: %d\n", errno); + exit(errno); + } + + close(channel[0]); + close(channel[1]); + + tapdisk = getenv("TAPDISK2"); + if (!tapdisk) + tapdisk = "tapdisk2"; + + execlp(tapdisk, tapdisk, NULL); + + EPRINTF("exec failed\n"); + exit(1); +} + +pid_t +tap_ctl_get_pid(const int id) +{ + int err; + tapdisk_message_t message; + + memset(&message, 0, sizeof(message)); + message.type = TAPDISK_MESSAGE_PID; + + err = tap_ctl_connect_send_and_receive(id, &message, 2); + if (err) + return err; + + return message.u.tapdisk_pid; +} + +static int +tap_ctl_wait(pid_t child) +{ + pid_t pid; + int status; + + pid = waitpid(child, &status, 0); + if (pid < 0) { + EPRINTF("wait(%d) failed, err %d\n", child, errno); + return -errno; + } + + if (WIFEXITED(status)) { + int code = WEXITSTATUS(status); + if (code) + EPRINTF("tapdisk2[%d] failed, status %d\n", child, code); + return -code; + } + + if (WIFSIGNALED(status)) { + int signo = WTERMSIG(status); + EPRINTF("tapdisk2[%d] killed by signal %d\n", child, signo); + return -EINTR; + } + + EPRINTF("tapdisk2[%d]: unexpected status %#x\n", child, status); + return -EAGAIN; +} + +static int +tap_ctl_get_child_id(int readfd) +{ + int id; + FILE *f; + + f = fdopen(readfd, "r"); + if (!f) { + EPRINTF("fdopen failed: %d\n", errno); + return -1; + } + + errno = 0; + if (fscanf(f, BLKTAP2_CONTROL_DIR"/" + BLKTAP2_CONTROL_SOCKET"%d", &id) != 1) { + errno = (errno ? : EINVAL); + EPRINTF("parsing id failed: %d\n", errno); + id = -1; + } + + fclose(f); + return id; +} + +int +tap_ctl_spawn(void) +{ + pid_t child; + int err, id, readfd; + + readfd = -1; + + child = __tap_ctl_spawn(&readfd); + if (child < 0) + return child; + + err = tap_ctl_wait(child); + if (err) + return err; + + id = tap_ctl_get_child_id(readfd); + if (id < 0) + EPRINTF("get_id failed, child %d err %d\n", child, errno); + + return id; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl-unpause.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl-unpause.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include + +#include "tap-ctl.h" + +int +tap_ctl_unpause(const int id, const int minor, const char *params) +{ + int err; + tapdisk_message_t message; + + memset(&message, 0, sizeof(message)); + message.type = TAPDISK_MESSAGE_RESUME; + message.cookie = minor; + + if (params) + strncpy(message.u.params.path, params, + sizeof(message.u.params.path) - 1); + + err = tap_ctl_connect_send_and_receive(id, &message, 15); + if (err) + return err; + + if (message.type == TAPDISK_MESSAGE_RESUME_RSP) + err = message.u.response.error; + else { + err = EINVAL; + EPRINTF("got unexpected result '%s' from %d\n", + tapdisk_message_name(message.type), id); + } + + return err; +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,815 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "tap-ctl.h" + +typedef int (*tap_ctl_func_t) (int, char **); + +struct command { + char *name; + tap_ctl_func_t func; +}; + +static void +tap_cli_list_usage(FILE *stream) +{ + fprintf(stream, + "usage: list [-h] [-p pid] [-m minor] [-t type] [-f file]\n"); +} + +static void +tap_ctl_list_row(tap_list_t *entry) +{ + char minor_str[10] = "-"; + char state_str[10] = "-"; + char pid_str[10] = "-"; + + if (entry->pid != -1) + sprintf(pid_str, "%d", entry->pid); + + if (entry->minor != -1) + sprintf(minor_str, "%d", entry->minor); + + if (entry->state != -1) + sprintf(state_str, "%x", entry->state); + + printf("%8s %2s %4s %10s %s\n", + pid_str, minor_str, state_str, + entry->type ? : "-", entry->path ? : "-"); +} + +static void +tap_ctl_list_dict(tap_list_t *entry) +{ + int d = 0; + + if (entry->pid != -1) { + if (d) putc(' ', stdout); + d = printf("pid=%d", entry->pid); + } + + if (entry->minor != -1) { + if (d) putc(' ', stdout); + d = printf("minor=%d", entry->minor); + } + + if (entry->state != -1) { + if (d) putc(' ', stdout); + d = printf("state=%d", entry->state); + } + + if (entry->type && entry->path) { + if (d) putc(' ', stdout); + d = printf("args=%s:%s", entry->type, entry->path); + } + + putc('\n', stdout); +} + +int +tap_cli_list(int argc, char **argv) +{ + tap_list_t **list, **_entry; + int c, minor, tty, err; + const char *type, *file; + pid_t pid; + + err = tap_ctl_list(&list); + if (err) + return -err; + + pid = -1; + minor = -1; + type = NULL; + file = NULL; + + while ((c = getopt(argc, argv, "m:p:t:f:h")) != -1) { + switch (c) { + case 'm': + minor = atoi(optarg); + break; + case 'p': + pid = atoi(optarg); + break; + case 't': + type = optarg; + break; + case 'f': + file = optarg; + break; + case '?': + goto usage; + case 'h': + tap_cli_list_usage(stdout); + return 0; + } + } + + tty = isatty(STDOUT_FILENO); + + for (_entry = list; *_entry != NULL; ++_entry) { + tap_list_t *entry = *_entry; + + if (minor >= 0 && entry->minor != minor) + continue; + + if (pid >= 0 && entry->pid != pid) + continue; + + if (type && entry->type && strcmp(entry->type, type)) + continue; + + if (file && entry->path && strcmp(entry->path, file)) + continue; + + if (tty) + tap_ctl_list_row(entry); + else + tap_ctl_list_dict(entry); + } + + tap_ctl_free_list(list); + + return 0; + +usage: + tap_cli_list_usage(stderr); + return EINVAL; +} + +static void +tap_cli_allocate_usage(FILE *stream) +{ + fprintf(stream, "usage: allocate [-d device name]>\n"); +} + +static int +tap_cli_allocate(int argc, char **argv) +{ + char *devname; + int c, minor, err; + + devname = NULL; + + optind = 0; + while ((c = getopt(argc, argv, "d:h")) != -1) { + switch (c) { + case 'd': + devname = optarg; + break; + case '?': + goto usage; + case 'h': + tap_cli_allocate_usage(stdout); + return 0; + } + } + + err = tap_ctl_allocate(&minor, &devname); + if (!err) + printf("%s\n", devname); + + return err; + +usage: + tap_cli_allocate_usage(stderr); + return EINVAL; +} + +static void +tap_cli_free_usage(FILE *stream) +{ + fprintf(stream, "usage: free <-m minor>\n"); +} + +static int +tap_cli_free(int argc, char **argv) +{ + int c, minor; + + minor = -1; + + optind = 0; + while ((c = getopt(argc, argv, "m:h")) != -1) { + switch (c) { + case 'm': + minor = atoi(optarg); + break; + case '?': + goto usage; + case 'h': + tap_cli_free_usage(stdout); + return 0; + } + } + + if (minor == -1) + goto usage; + + return tap_ctl_free(minor); + +usage: + tap_cli_free_usage(stderr); + return EINVAL; +} + +static void +tap_cli_create_usage(FILE *stream) +{ + fprintf(stream, "usage: create <-a args> [-d device name]\n"); +} + +static int +tap_cli_create(int argc, char **argv) +{ + int c, err; + char *args, *devname; + + args = NULL; + devname = NULL; + + optind = 0; + while ((c = getopt(argc, argv, "a:d:h")) != -1) { + switch (c) { + case 'a': + args = optarg; + break; + case 'd': + devname = optarg; + break; + case '?': + goto usage; + case 'h': + tap_cli_create_usage(stdout); + return 0; + } + } + + if (!args) + goto usage; + + err = tap_ctl_create(args, &devname); + if (!err) + printf("%s\n", devname); + + return err; + +usage: + tap_cli_create_usage(stderr); + return EINVAL; +} + +static void +tap_cli_destroy_usage(FILE *stream) +{ + fprintf(stream, "usage: destroy <-p pid> <-m minor>\n"); +} + +static int +tap_cli_destroy(int argc, char **argv) +{ + int c, pid, minor; + + pid = -1; + minor = -1; + + optind = 0; + while ((c = getopt(argc, argv, "p:m:h")) != -1) { + switch (c) { + case 'p': + pid = atoi(optarg); + break; + case 'm': + minor = atoi(optarg); + break; + case '?': + goto usage; + case 'h': + tap_cli_destroy_usage(stdout); + return 0; + } + } + + if (pid == -1 || minor == -1) + goto usage; + + return tap_ctl_destroy(pid, minor); + +usage: + tap_cli_destroy_usage(stderr); + return EINVAL; +} + +static void +tap_cli_spawn_usage(FILE *stream) +{ + fprintf(stream, "usage: spawn\n"); +} + +static int +tap_cli_spawn(int argc, char **argv) +{ + int c; + pid_t task; + + optind = 0; + while ((c = getopt(argc, argv, "h")) != -1) { + switch (c) { + case '?': + goto usage; + case 'h': + tap_cli_spawn_usage(stdout); + return 0; + } + } + + task = tap_ctl_spawn(); + if (task < 0) { + printf("spawn failed: %d\n", errno); + return task; + } + + printf("tapdisk spawned with pid %d\n", task); + return 0; + +usage: + tap_cli_spawn_usage(stderr); + return EINVAL; +} + +static void +tap_cli_attach_usage(FILE *stream) +{ + fprintf(stream, "usage: attach <-p pid> <-m minor>\n"); +} + +static int +tap_cli_attach(int argc, char **argv) +{ + int c, pid, minor; + + pid = -1; + minor = -1; + + optind = 0; + while ((c = getopt(argc, argv, "p:m:h")) != -1) { + switch (c) { + case 'p': + pid = atoi(optarg); + break; + case 'm': + minor = atoi(optarg); + break; + case '?': + goto usage; + case 'h': + tap_cli_attach_usage(stderr); + return 0; + } + } + + if (pid == -1 || minor == -1) + goto usage; + + return tap_ctl_attach(pid, minor); + +usage: + tap_cli_attach_usage(stderr); + return EINVAL; +} + +static void +tap_cli_detach_usage(FILE *stream) +{ + fprintf(stream, "usage: detach <-p pid> <-m minor>\n"); +} + +static int +tap_cli_detach(int argc, char **argv) +{ + int c, pid, minor; + + pid = -1; + minor = -1; + + optind = 0; + while ((c = getopt(argc, argv, "p:m:h")) != -1) { + switch (c) { + case 'p': + pid = atoi(optarg); + break; + case 'm': + minor = atoi(optarg); + break; + case '?': + goto usage; + case 'h': + tap_cli_detach_usage(stdout); + return 0; + } + } + + if (pid == -1 || minor == -1) + goto usage; + + return tap_ctl_detach(pid, minor); + +usage: + tap_cli_detach_usage(stderr); + return EINVAL; +} + +static void +tap_cli_close_usage(FILE *stream) +{ + fprintf(stream, "usage: close <-p pid> <-m minor> [-f force]\n"); +} + +static int +tap_cli_close(int argc, char **argv) +{ + int c, pid, minor, force; + + pid = -1; + minor = -1; + force = 0; + + optind = 0; + while ((c = getopt(argc, argv, "p:m:fh")) != -1) { + switch (c) { + case 'p': + pid = atoi(optarg); + break; + case 'm': + minor = atoi(optarg); + break; + case 'f': + force = -1; + break; + case '?': + goto usage; + case 'h': + tap_cli_close_usage(stdout); + return 0; + } + } + + if (pid == -1 || minor == -1) + goto usage; + + return tap_ctl_close(pid, minor, force); + +usage: + tap_cli_close_usage(stderr); + return EINVAL; +} + +static void +tap_cli_pause_usage(FILE *stream) +{ + fprintf(stream, "usage: pause <-p pid> <-m minor>\n"); +} + +static int +tap_cli_pause(int argc, char **argv) +{ + int c, pid, minor; + + pid = -1; + minor = -1; + + optind = 0; + while ((c = getopt(argc, argv, "p:m:h")) != -1) { + switch (c) { + case 'p': + pid = atoi(optarg); + break; + case 'm': + minor = atoi(optarg); + break; + case '?': + goto usage; + case 'h': + tap_cli_pause_usage(stdout); + return 0; + } + } + + if (pid == -1 || minor == -1) + goto usage; + + return tap_ctl_pause(pid, minor); + +usage: + tap_cli_pause_usage(stderr); + return EINVAL; +} + +static void +tap_cli_unpause_usage(FILE *stream) +{ + fprintf(stream, "usage: unpause <-p pid> <-m minor> [-a args]\n"); +} + +int +tap_cli_unpause(int argc, char **argv) +{ + const char *args; + int c, pid, minor; + + pid = -1; + minor = -1; + args = NULL; + + optind = 0; + while ((c = getopt(argc, argv, "p:m:a:h")) != -1) { + switch (c) { + case 'p': + pid = atoi(optarg); + break; + case 'm': + minor = atoi(optarg); + break; + case 'a': + args = optarg; + break; + case '?': + goto usage; + case 'h': + tap_cli_unpause_usage(stdout); + return 0; + } + } + + if (pid == -1 || minor == -1) + goto usage; + + return tap_ctl_unpause(pid, minor, args); + +usage: + tap_cli_unpause_usage(stderr); + return EINVAL; +} + +static void +tap_cli_major_usage(FILE *stream) +{ + fprintf(stream, "usage: major [-h]\n"); +} + +static int +tap_cli_major(int argc, char **argv) +{ + int c, chr, major; + + chr = 0; + + while ((c = getopt(argc, argv, "bch")) != -1) { + switch (c) { + case 'b': + chr = 0; + break; + case 'c': + chr = 1; + break; + case '?': + goto usage; + case 'h': + tap_cli_major_usage(stdout); + return 0; + default: + goto usage; + } + } + + if (chr) + major = -EINVAL; + else + major = tap_ctl_blk_major(); + + if (major < 0) + return -major; + + printf("%d\n", major); + + return 0; + +usage: + tap_cli_major_usage(stderr); + return EINVAL; +} + +static void +tap_cli_open_usage(FILE *stream) +{ + fprintf(stream, "usage: open <-p pid> <-m minor> <-a args>\n"); +} + +static int +tap_cli_open(int argc, char **argv) +{ + const char *args; + int c, pid, minor; + + pid = -1; + minor = -1; + args = NULL; + + optind = 0; + while ((c = getopt(argc, argv, "a:m:p:h")) != -1) { + switch (c) { + case 'p': + pid = atoi(optarg); + break; + case 'm': + minor = atoi(optarg); + break; + case 'a': + args = optarg; + break; + case '?': + goto usage; + case 'h': + tap_cli_open_usage(stdout); + return 0; + } + } + + if (pid == -1 || minor == -1 || !args) + goto usage; + + return tap_ctl_open(pid, minor, args); + +usage: + tap_cli_open_usage(stderr); + return EINVAL; +} + +static void +tap_cli_check_usage(FILE *stream) +{ + fprintf(stream, "usage: check\n" + "(checks whether environment is suitable for tapdisk2)\n"); +} + +static int +tap_cli_check(int argc, char **argv) +{ + int err; + const char *msg; + + if (argc != 1) + goto usage; + + err = tap_ctl_check(&msg); + printf("%s\n", msg); + + return err; + +usage: + tap_cli_check_usage(stderr); + return EINVAL; +} + +struct command commands[] = { + { .name = "list", .func = tap_cli_list }, + { .name = "allocate", .func = tap_cli_allocate }, + { .name = "free", .func = tap_cli_free }, + { .name = "create", .func = tap_cli_create }, + { .name = "destroy", .func = tap_cli_destroy }, + { .name = "spawn", .func = tap_cli_spawn }, + { .name = "attach", .func = tap_cli_attach }, + { .name = "detach", .func = tap_cli_detach }, + { .name = "open", .func = tap_cli_open }, + { .name = "close", .func = tap_cli_close }, + { .name = "pause", .func = tap_cli_pause }, + { .name = "unpause", .func = tap_cli_unpause }, + { .name = "major", .func = tap_cli_major }, + { .name = "check", .func = tap_cli_check }, +}; + +#define print_commands() \ + do { \ + int i, n; \ + n = sizeof(commands) / sizeof(struct command); \ + printf("COMMAND := { "); \ + printf("%s", commands[0].name); \ + for (i = 1; i < n; i++) \ + printf(" | %s", commands[i].name); \ + printf(" }\n"); \ + } while (0) + +void +help(void) +{ + printf("usage: tap-ctl COMMAND [OPTIONS]\n"); + print_commands(); + exit(0); +} + +struct command * +get_command(char *command) +{ + int i, n; + + if (strnlen(command, 25) >= 25) + return NULL; + + n = sizeof(commands) / sizeof (struct command); + + for (i = 0; i < n; i++) + if (!strcmp(command, commands[i].name)) + return &commands[i]; + + return NULL; +} + +int +main(int argc, char *argv[]) +{ + char **cargv; + const char *msg; + struct command *cmd; + int cargc, i, cnt, ret; + +#ifdef CORE_DUMP + #include + struct rlimit rlim; + rlim.rlim_cur = RLIM_INFINITY; + rlim.rlim_max = RLIM_INFINITY; + if (setrlimit(RLIMIT_CORE, &rlim) < 0) + PERROR("setrlimit failed"); +#endif + + ret = 0; + + if (argc < 2) + help(); + + cargc = argc - 1; + cmd = get_command(argv[1]); + if (!cmd) { + EPRINTF("invalid COMMAND %s", argv[1]); + help(); + } + + ret = tap_ctl_check(&msg); + if (ret) { + printf("%s\n", msg); + return ret; + } + + cargv = malloc(sizeof(char *) * cargc); + if (!cargv) + exit(ENOMEM); + + cnt = 1; + cargv[0] = cmd->name; + for (i = 1; i < cargc; i++) { + char *arg = argv[i + (argc - cargc)]; + + if (!strcmp(arg, "--debug")) { + tap_ctl_debug = 1; + continue; + } + + cargv[cnt++] = arg; + } + + ret = cmd->func(cnt, cargv); + + free(cargv); + + return (ret >= 0 ? ret : -ret); +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/control/tap-ctl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/control/tap-ctl.h Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __TAP_CTL_H__ +#define __TAP_CTL_H__ + +#include +#include + +#include "tapdisk-message.h" + +extern int tap_ctl_debug; + +#ifdef TAPCTL +#define DBG(_f, _a...) \ + do { \ + if (tap_ctl_debug) \ + printf(_f, ##_a); \ + } while (0) + +#define DPRINTF(_f, _a...) syslog(LOG_INFO, _f, ##_a) +#define EPRINTF(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f, __func__, ##_a) +#define PERROR(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f ": %s", __func__, ##_a, \ + strerror(errno)) +#endif + +void tap_ctl_version(int *major, int *minor); +int tap_ctl_kernel_version(int *major, int *minor); + +int tap_ctl_check_blktap(const char **message); +int tap_ctl_check_version(const char **message); +int tap_ctl_check(const char **message); + +int tap_ctl_connect(const char *path, int *socket); +int tap_ctl_connect_id(int id, int *socket); +int tap_ctl_read_message(int fd, tapdisk_message_t *message, int timeout); +int tap_ctl_write_message(int fd, tapdisk_message_t *message, int timeout); +int tap_ctl_send_and_receive(int fd, tapdisk_message_t *message, int timeout); +int tap_ctl_connect_send_and_receive(int id, + tapdisk_message_t *message, int timeout); +char *tap_ctl_socket_name(int id); + +typedef struct { + int id; + pid_t pid; + int minor; + int state; + char *type; + char *path; +} tap_list_t; + +int tap_ctl_get_driver_id(const char *handle); + +int tap_ctl_list(tap_list_t ***list); +void tap_ctl_free_list(tap_list_t **list); + +int tap_ctl_allocate(int *minor, char **devname); +int tap_ctl_free(const int minor); + +int tap_ctl_create(const char *params, char **devname); +int tap_ctl_destroy(const int id, const int minor); + +int tap_ctl_spawn(void); +pid_t tap_ctl_get_pid(const int id); + +int tap_ctl_attach(const int id, const int minor); +int tap_ctl_detach(const int id, const int minor); + +int tap_ctl_open(const int id, const int minor, const char *params); +int tap_ctl_close(const int id, const int minor, const int force); + +int tap_ctl_pause(const int id, const int minor); +int tap_ctl_unpause(const int id, const int minor, const char *params); + +int tap_ctl_blk_major(void); + +#endif diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/drivers/Makefile --- a/tools/blktap2/drivers/Makefile Mon Jun 07 14:53:15 2010 -0700 +++ b/tools/blktap2/drivers/Makefile Mon Jun 07 14:53:16 2010 -0700 @@ -12,8 +12,7 @@ CFLAGS += -Werror -g -O0 CFLAGS += -Wno-unused CFLAGS += -fno-strict-aliasing -CFLAGS += -I../lib -I../../libxc -CFLAGS += -I../include -I../../include +CFLAGS += -I$(BLKTAP_ROOT)/include -I$(BLKTAP_ROOT)/drivers CFLAGS += $(CFLAGS_libxenctrl) CFLAGS += -I $(LIBAIO_DIR) CFLAGS += -I $(MEMSHR_DIR) @@ -75,6 +74,7 @@ TAP-OBJS-y := scheduler.o TAP-OBJS-y += tapdisk-vbd.o +TAP-OBJS-y += tapdisk-control.o TAP-OBJS-y += tapdisk-image.o TAP-OBJS-y += tapdisk-driver.o TAP-OBJS-y += tapdisk-disktype.o diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/drivers/blktap2.h --- a/tools/blktap2/drivers/blktap2.h Mon Jun 07 14:53:15 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2008, XenSource Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of XenSource Inc. nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _BLKTAP_2_H_ -#define _BLKTAP_2_H_ - -#define MISC_MAJOR_NUMBER 10 - -#define BLKTAP2_MAX_MESSAGE_LEN 256 - -#define BLKTAP2_RING_MESSAGE_PAUSE 1 -#define BLKTAP2_RING_MESSAGE_RESUME 2 -#define BLKTAP2_RING_MESSAGE_CLOSE 3 - -#define BLKTAP2_IOCTL_KICK_FE 1 -#define BLKTAP2_IOCTL_ALLOC_TAP 200 -#define BLKTAP2_IOCTL_FREE_TAP 201 -#define BLKTAP2_IOCTL_CREATE_DEVICE 202 -#define BLKTAP2_IOCTL_SET_PARAMS 203 -#define BLKTAP2_IOCTL_PAUSE 204 -#define BLKTAP2_IOCTL_REOPEN 205 -#define BLKTAP2_IOCTL_RESUME 206 - -#define BLKTAP2_CONTROL_NAME "blktap-control" -#define BLKTAP2_DIRECTORY "/dev/xen/blktap-2" -#define BLKTAP2_CONTROL_DEVICE BLKTAP2_DIRECTORY"/control" -#define BLKTAP2_RING_DEVICE BLKTAP2_DIRECTORY"/blktap" -#define BLKTAP2_IO_DEVICE BLKTAP2_DIRECTORY"/tapdev" - -struct blktap2_handle { - unsigned int ring; - unsigned int device; - unsigned int minor; -}; - -struct blktap2_params { - char name[BLKTAP2_MAX_MESSAGE_LEN]; - unsigned long long capacity; - unsigned long sector_size; -}; - -#endif diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/drivers/tapdisk-control.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/drivers/tapdisk-control.c Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,836 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "list.h" +#include "tapdisk.h" +#include "blktap2.h" +#include "blktaplib.h" +#include "tapdisk-vbd.h" +#include "tapdisk-utils.h" +#include "tapdisk-server.h" +#include "tapdisk-message.h" +#include "tapdisk-disktype.h" + +struct tapdisk_control { + char *path; + int socket; + int event_id; +}; + +struct tapdisk_control_connection { + int socket; + event_id_t event_id; +}; + +static struct tapdisk_control td_control; + +static void +tapdisk_control_initialize(void) +{ + td_control.socket = -1; + td_control.event_id = -1; + + signal(SIGPIPE, SIG_IGN); +} + +void +tapdisk_control_close(void) +{ + if (td_control.path) { + unlink(td_control.path); + free(td_control.path); + td_control.path = NULL; + } + + if (td_control.socket != -1) { + close(td_control.socket); + td_control.socket = -1; + } +} + +static struct tapdisk_control_connection * +tapdisk_control_allocate_connection(int fd) +{ + struct tapdisk_control_connection *connection; + size_t sz; + + connection = calloc(1, sizeof(*connection)); + if (!connection) { + EPRINTF("calloc"); + return NULL; + } + + connection->socket = fd; + return connection; +} + +static void +tapdisk_control_close_connection(struct tapdisk_control_connection *connection) +{ + tapdisk_server_unregister_event(connection->event_id); + close(connection->socket); + free(connection); +} + +static int +tapdisk_control_read_message(int fd, tapdisk_message_t *message, int timeout) +{ + fd_set readfds; + int ret, len, offset; + struct timeval tv, *t; + + t = NULL; + offset = 0; + len = sizeof(tapdisk_message_t); + + if (timeout) { + tv.tv_sec = timeout; + tv.tv_usec = 0; + t = &tv; + } + + memset(message, 0, sizeof(tapdisk_message_t)); + + while (offset < len) { + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + ret = select(fd + 1, &readfds, NULL, NULL, t); + if (ret == -1) + break; + else if (FD_ISSET(fd, &readfds)) { + ret = read(fd, message + offset, len - offset); + if (ret <= 0) + break; + offset += ret; + } else + break; + } + + if (offset != len) { + EPRINTF("failure reading message (wanted %d but got %d)\n", + len, offset); + return -EIO; + } + + DPRINTF("received '%s' message (uuid = %u)\n", + tapdisk_message_name(message->type), message->cookie); + + return 0; +} + +static int +tapdisk_control_write_message(int fd, tapdisk_message_t *message, int timeout) +{ + fd_set writefds; + int ret, len, offset; + struct timeval tv, *t; + + t = NULL; + offset = 0; + len = sizeof(tapdisk_message_t); + + if (timeout) { + tv.tv_sec = timeout; + tv.tv_usec = 0; + t = &tv; + } + + DPRINTF("sending '%s' message (uuid = %u)\n", + tapdisk_message_name(message->type), message->cookie); + + while (offset < len) { + FD_ZERO(&writefds); + FD_SET(fd, &writefds); + + /* we don't bother reinitializing tv. at worst, it will wait a + * bit more time than expected. */ + + ret = select(fd + 1, NULL, &writefds, NULL, t); + if (ret == -1) + break; + else if (FD_ISSET(fd, &writefds)) { + ret = write(fd, message + offset, len - offset); + if (ret <= 0) + break; + offset += ret; + } else + break; + } + + if (offset != len) { + EPRINTF("failure writing message\n"); + return -EIO; + } + + return 0; +} + +static int +tapdisk_control_validate_request(tapdisk_message_t *request) +{ + if (strnlen(request->u.params.path, + TAPDISK_MESSAGE_MAX_PATH_LENGTH) >= + TAPDISK_MESSAGE_MAX_PATH_LENGTH) + return EINVAL; + + return 0; +} + +static void +tapdisk_control_list_minors(struct tapdisk_control_connection *connection, + tapdisk_message_t *request) +{ + int i; + td_vbd_t *vbd; + struct list_head *head; + tapdisk_message_t response; + + i = 0; + memset(&response, 0, sizeof(response)); + + response.type = TAPDISK_MESSAGE_LIST_MINORS_RSP; + response.cookie = request->cookie; + + head = tapdisk_server_get_all_vbds(); + + list_for_each_entry(vbd, head, next) { + response.u.minors.list[i++] = vbd->minor; + if (i >= TAPDISK_MESSAGE_MAX_MINORS) { + response.type = TAPDISK_MESSAGE_ERROR; + response.u.response.error = ERANGE; + break; + } + } + + response.u.minors.count = i; + tapdisk_control_write_message(connection->socket, &response, 2); + tapdisk_control_close_connection(connection); +} + +static void +tapdisk_control_list(struct tapdisk_control_connection *connection, + tapdisk_message_t *request) +{ + td_vbd_t *vbd; + struct list_head *head; + tapdisk_message_t response; + int count, i; + + memset(&response, 0, sizeof(response)); + response.type = TAPDISK_MESSAGE_LIST_RSP; + response.cookie = request->cookie; + + head = tapdisk_server_get_all_vbds(); + + count = 0; + list_for_each_entry(vbd, head, next) + count++; + + list_for_each_entry(vbd, head, next) { + response.u.list.count = count--; + response.u.list.minor = vbd->minor; + response.u.list.state = vbd->state; + response.u.list.path[0] = 0; + + if (!list_empty(&vbd->images)) { + td_image_t *image = list_entry(vbd->images.next, + td_image_t, next); + snprintf(response.u.list.path, + sizeof(response.u.list.path), + "%s:%s", + tapdisk_disk_types[image->type]->name, + image->name); + } + + tapdisk_control_write_message(connection->socket, &response, 2); + } + + response.u.list.count = count; + response.u.list.minor = -1; + response.u.list.path[0] = 0; + + tapdisk_control_write_message(connection->socket, &response, 2); + tapdisk_control_close_connection(connection); +} + +static void +tapdisk_control_get_pid(struct tapdisk_control_connection *connection, + tapdisk_message_t *request) +{ + tapdisk_message_t response; + + memset(&response, 0, sizeof(response)); + response.type = TAPDISK_MESSAGE_PID_RSP; + response.cookie = request->cookie; + response.u.tapdisk_pid = getpid(); + + tapdisk_control_write_message(connection->socket, &response, 2); + tapdisk_control_close_connection(connection); +} + +static void +tapdisk_control_attach_vbd(struct tapdisk_control_connection *connection, + tapdisk_message_t *request) +{ + tapdisk_message_t response; + char *devname; + td_vbd_t *vbd; + struct blktap2_params params; + image_t image; + int minor, err; + + /* + * TODO: check for max vbds per process + */ + + vbd = tapdisk_server_get_vbd(request->cookie); + if (vbd) { + err = -EEXIST; + goto out; + } + + minor = request->cookie; + if (minor < 0) { + err = -EINVAL; + goto out; + } + + vbd = tapdisk_vbd_create(minor); + if (!vbd) { + err = -ENOMEM; + goto out; + } + + err = asprintf(&devname, BLKTAP2_RING_DEVICE"%d", minor); + if (err == -1) { + err = -ENOMEM; + goto fail_vbd; + } + + err = tapdisk_vbd_attach(vbd, devname, minor); + free(devname); + if (err) + goto fail_vbd; + + tapdisk_server_add_vbd(vbd); + +out: + memset(&response, 0, sizeof(response)); + response.type = TAPDISK_MESSAGE_ATTACH_RSP; + response.cookie = request->cookie; + response.u.response.error = -err; + + tapdisk_control_write_message(connection->socket, &response, 2); + tapdisk_control_close_connection(connection); + + return; + +fail_vbd: + tapdisk_vbd_detach(vbd); + free(vbd); + goto out; +} + + +static void +tapdisk_control_detach_vbd(struct tapdisk_control_connection *connection, + tapdisk_message_t *request) +{ + tapdisk_message_t response; + td_vbd_t *vbd; + int err; + + vbd = tapdisk_server_get_vbd(request->cookie); + if (!vbd) { + err = -EINVAL; + goto out; + } + + tapdisk_vbd_detach(vbd); + + if (list_empty(&vbd->images)) { + tapdisk_server_remove_vbd(vbd); + free(vbd); + } + + err = 0; +out: + memset(&response, 0, sizeof(response)); + response.type = TAPDISK_MESSAGE_DETACH_RSP; + response.cookie = request->cookie; + response.u.response.error = -err; + + tapdisk_control_write_message(connection->socket, &response, 2); + tapdisk_control_close_connection(connection); +} + +static void +tapdisk_control_open_image(struct tapdisk_control_connection *connection, + tapdisk_message_t *request) +{ + int err; + image_t image; + td_vbd_t *vbd; + td_flag_t flags; + tapdisk_message_t response; + struct blktap2_params params; + + vbd = tapdisk_server_get_vbd(request->cookie); + if (!vbd) { + err = -EINVAL; + goto out; + } + + if (vbd->minor == -1) { + err = -EINVAL; + goto out; + } + + if (vbd->name) { + err = -EALREADY; + goto out; + } + + flags = 0; + if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_RDONLY) + flags |= TD_OPEN_RDONLY; + if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_SHARED) + flags |= TD_OPEN_SHAREABLE; + if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_ADD_CACHE) + flags |= TD_OPEN_ADD_CACHE; + if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_VHD_INDEX) + flags |= TD_OPEN_VHD_INDEX; + if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_LOG_DIRTY) + flags |= TD_OPEN_LOG_DIRTY; + + vbd->name = strndup(request->u.params.path, + sizeof(request->u.params.path)); + if (!vbd->name) { + err = -ENOMEM; + goto out; + } + + err = tapdisk_vbd_parse_stack(vbd, request->u.params.path); + if (err) + goto out; + + err = tapdisk_vbd_open_stack(vbd, request->u.params.storage, flags); + if (err) + goto out; + + err = tapdisk_vbd_get_image_info(vbd, &image); + if (err) + goto fail_close; + + params.capacity = image.size; + params.sector_size = image.secsize; + + err = ioctl(vbd->ring.fd, BLKTAP2_IOCTL_CREATE_DEVICE, ¶ms); + if (err && errno != EEXIST) { + err = -errno; + EPRINTF("create device failed: %d\n", err); + goto fail_close; + } + + err = 0; + +out: + memset(&response, 0, sizeof(response)); + response.cookie = request->cookie; + + if (err) { + response.type = TAPDISK_MESSAGE_ERROR; + response.u.response.error = -err; + } else { + response.u.image.sectors = image.size; + response.u.image.sector_size = image.secsize; + response.u.image.info = image.info; + response.type = TAPDISK_MESSAGE_OPEN_RSP; + } + + tapdisk_control_write_message(connection->socket, &response, 2); + tapdisk_control_close_connection(connection); + + return; + +fail_close: + tapdisk_vbd_close_vdi(vbd); + free(vbd->name); + vbd->name = NULL; + goto out; +} + +static void +tapdisk_control_close_image(struct tapdisk_control_connection *connection, + tapdisk_message_t *request) +{ + tapdisk_message_t response; + td_vbd_t *vbd; + int err; + + vbd = tapdisk_server_get_vbd(request->cookie); + if (!vbd) { + err = -EINVAL; + goto out; + } + + if (!list_empty(&vbd->pending_requests)) { + err = -EAGAIN; + goto out; + } + + tapdisk_vbd_close_vdi(vbd); + + /* NB. vbd->name free should probably belong into close_vdi, + but the current blktap1 reopen-stuff likely depends on a + lifetime extended until shutdown. */ + free(vbd->name); + vbd->name = NULL; + + if (vbd->minor == -1) { + tapdisk_server_remove_vbd(vbd); + tapdisk_vbd_free(vbd); + } + + err = 0; +out: + memset(&response, 0, sizeof(response)); + response.type = TAPDISK_MESSAGE_CLOSE_RSP; + response.cookie = request->cookie; + response.u.response.error = -err; + + tapdisk_control_write_message(connection->socket, &response, 2); + tapdisk_control_close_connection(connection); +} + +static void +tapdisk_control_pause_vbd(struct tapdisk_control_connection *connection, + tapdisk_message_t *request) +{ + int err; + td_vbd_t *vbd; + tapdisk_message_t response; + + memset(&response, 0, sizeof(response)); + + response.type = TAPDISK_MESSAGE_PAUSE_RSP; + + vbd = tapdisk_server_get_vbd(request->cookie); + if (!vbd) { + err = -EINVAL; + goto out; + } + + do { + err = tapdisk_vbd_pause(vbd); + + if (!err || err != -EAGAIN) + break; + + tapdisk_server_iterate(); + } while (1); + +out: + response.cookie = request->cookie; + response.u.response.error = -err; + tapdisk_control_write_message(connection->socket, &response, 2); + tapdisk_control_close_connection(connection); +} + +static void +tapdisk_control_resume_vbd(struct tapdisk_control_connection *connection, + tapdisk_message_t *request) +{ + int err; + td_vbd_t *vbd; + tapdisk_message_t response; + + memset(&response, 0, sizeof(response)); + + response.type = TAPDISK_MESSAGE_RESUME_RSP; + + vbd = tapdisk_server_get_vbd(request->cookie); + if (!vbd) { + err = -EINVAL; + goto out; + } + + if (!td_flag_test(vbd->state, TD_VBD_PAUSED)) { + err = -EINVAL; + goto out; + } + + if (request->u.params.path[0]) { + free(vbd->name); + vbd->name = strndup(request->u.params.path, + sizeof(request->u.params.path)); + if (!vbd->name) { + err = -ENOMEM; + goto out; + } + } else if (!vbd->name) { + err = -EINVAL; + goto out; + } + + err = tapdisk_vbd_parse_stack(vbd, vbd->name); + if (err) + goto out; + + err = tapdisk_vbd_resume(vbd, NULL, -1); + if (err) + goto out; + +out: + response.cookie = request->cookie; + response.u.response.error = -err; + tapdisk_control_write_message(connection->socket, &response, 2); + tapdisk_control_close_connection(connection); +} + +static void +tapdisk_control_handle_request(event_id_t id, char mode, void *private) +{ + int err; + tapdisk_message_t message; + struct tapdisk_control_connection *connection = + (struct tapdisk_control_connection *)private; + + if (tapdisk_control_read_message(connection->socket, &message, 2)) { + EPRINTF("failed to read message from %d\n", connection->socket); + tapdisk_control_close_connection(connection); + return; + } + + err = tapdisk_control_validate_request(&message); + if (err) + goto fail; + + switch (message.type) { + case TAPDISK_MESSAGE_PID: + return tapdisk_control_get_pid(connection, &message); + case TAPDISK_MESSAGE_LIST_MINORS: + return tapdisk_control_list_minors(connection, &message); + case TAPDISK_MESSAGE_LIST: + return tapdisk_control_list(connection, &message); + case TAPDISK_MESSAGE_ATTACH: + return tapdisk_control_attach_vbd(connection, &message); + case TAPDISK_MESSAGE_DETACH: + return tapdisk_control_detach_vbd(connection, &message); + case TAPDISK_MESSAGE_OPEN: + return tapdisk_control_open_image(connection, &message); + case TAPDISK_MESSAGE_PAUSE: + return tapdisk_control_pause_vbd(connection, &message); + case TAPDISK_MESSAGE_RESUME: + return tapdisk_control_resume_vbd(connection, &message); + case TAPDISK_MESSAGE_CLOSE: + return tapdisk_control_close_image(connection, &message); + default: { + tapdisk_message_t response; + fail: + + EPRINTF("received unsupported message '%s'\n", + tapdisk_message_name(message.type)); + + memset(&response, 0, sizeof(response)); + + response.type = TAPDISK_MESSAGE_ERROR; + response.u.response.error = (err ? -err : EINVAL); + tapdisk_control_write_message(connection->socket, &response, 2); + + tapdisk_control_close_connection(connection); + break; + } + } +} + +static void +tapdisk_control_accept(event_id_t id, char mode, void *private) +{ + int err, fd; + struct tapdisk_control_connection *connection; + + fd = accept(td_control.socket, NULL, NULL); + if (fd == -1) { + EPRINTF("failed to accept new control connection: %d\n", errno); + return; + } + + connection = tapdisk_control_allocate_connection(fd); + if (!connection) { + close(fd); + EPRINTF("failed to allocate new control connection\n"); + } + + err = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD, + connection->socket, 0, + tapdisk_control_handle_request, + connection); + if (err == -1) { + close(fd); + free(connection); + EPRINTF("failed to register new control event: %d\n", err); + } + + connection->event_id = err; +} + +static int +tapdisk_control_mkdir(const char *dir) +{ + int err; + char *ptr, *name, *start; + + err = access(dir, W_OK | R_OK); + if (!err) + return 0; + + name = strdup(dir); + if (!name) + return -ENOMEM; + + start = name; + + for (;;) { + ptr = strchr(start + 1, '/'); + if (ptr) + *ptr = '\0'; + + err = mkdir(name, 0755); + if (err && errno != EEXIST) { + err = -errno; + EPRINTF("failed to create directory %s: %d\n", + name, err); + break; + } + + if (!ptr) + break; + else { + *ptr = '/'; + start = ptr + 1; + } + } + + free(name); + return err; +} + +static int +tapdisk_control_create_socket(char **socket_path) +{ + int err, flags; + struct sockaddr_un saddr; + + err = tapdisk_control_mkdir(BLKTAP2_CONTROL_DIR); + if (err) { + EPRINTF("failed to create directory %s: %d\n", + BLKTAP2_CONTROL_DIR, err); + return err; + } + + err = asprintf(&td_control.path, "%s/%s%d", + BLKTAP2_CONTROL_DIR, BLKTAP2_CONTROL_SOCKET, getpid()); + if (err == -1) { + td_control.path = NULL; + err = (errno ? : ENOMEM); + goto fail; + } + + if (unlink(td_control.path) && errno != ENOENT) { + err = errno; + EPRINTF("failed to unlink %s: %d\n", td_control.path, errno); + goto fail; + } + + td_control.socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (td_control.socket == -1) { + err = errno; + EPRINTF("failed to create control socket: %d\n", err); + goto fail; + } + + memset(&saddr, 0, sizeof(saddr)); + strncpy(saddr.sun_path, td_control.path, sizeof(saddr.sun_path)); + saddr.sun_family = AF_UNIX; + + err = bind(td_control.socket, + (const struct sockaddr *)&saddr, sizeof(saddr)); + if (err == -1) { + err = errno; + EPRINTF("failed to bind to %s: %d\n", saddr.sun_path, err); + goto fail; + } + + err = listen(td_control.socket, 10); + if (err == -1) { + err = errno; + EPRINTF("failed to listen: %d\n", err); + goto fail; + } + + err = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD, + td_control.socket, 0, + tapdisk_control_accept, NULL); + if (err < 0) { + EPRINTF("failed to add watch: %d\n", err); + goto fail; + } + + td_control.event_id = err; + *socket_path = td_control.path; + + return 0; + +fail: + tapdisk_control_close(); + return err; +} + +int +tapdisk_control_open(char **path) +{ + int err; + + tapdisk_control_initialize(); + + return tapdisk_control_create_socket(path); +} diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/drivers/tapdisk-control.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/drivers/tapdisk-control.h Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TAPDISK_CONTROL_H__ +#define __TAPDISK_CONTROL_H__ + +int tapdisk_control_open(char **path); +void tapdisk_control_close(void); + +#endif diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/drivers/tapdisk-server.c --- a/tools/blktap2/drivers/tapdisk-server.c Mon Jun 07 14:53:15 2010 -0700 +++ b/tools/blktap2/drivers/tapdisk-server.c Mon Jun 07 14:53:16 2010 -0700 @@ -63,6 +63,12 @@ return NULL; } +struct list_head * +tapdisk_server_get_all_vbds(void) +{ + return &server.vbds; +} + td_vbd_t * tapdisk_server_get_vbd(uint16_t uuid) { @@ -218,24 +224,29 @@ tapdisk_server_close_aio(); } +void +tapdisk_server_iterate(void) +{ + int ret; + + tapdisk_server_assert_locks(); + tapdisk_server_set_retry_timeout(); + tapdisk_server_check_progress(); + + ret = scheduler_wait_for_events(&server.scheduler); + if (ret < 0) + DBG(TLOG_WARN, "server wait returned %d\n", ret); + + tapdisk_server_check_vbds(); + tapdisk_server_submit_tiocbs(); + tapdisk_server_kick_responses(); +} + static void __tapdisk_server_run(void) { - int ret; - - while (server.run) { - tapdisk_server_assert_locks(); - tapdisk_server_set_retry_timeout(); - tapdisk_server_check_progress(); - - ret = scheduler_wait_for_events(&server.scheduler); - if (ret < 0) - DBG(TLOG_WARN, "server wait returned %d\n", ret); - - tapdisk_server_check_vbds(); - tapdisk_server_submit_tiocbs(); - tapdisk_server_kick_responses(); - } + while (server.run) + tapdisk_server_iterate(); } static void @@ -267,22 +278,50 @@ } int +tapdisk_server_init(void) +{ + memset(&server, 0, sizeof(server)); + INIT_LIST_HEAD(&server.vbds); + + scheduler_initialize(&server.scheduler); + + return 0; +} + +int +tapdisk_server_complete(void) +{ + int err; + + err = tapdisk_server_init_aio(); + if (err) + goto fail; + + server.run = 1; + + return 0; + +fail: + tapdisk_server_close_aio(); + return err; +} + +int tapdisk_server_initialize(void) { int err; - memset(&server, 0, sizeof(tapdisk_server_t)); - INIT_LIST_HEAD(&server.vbds); + tapdisk_server_init(); - scheduler_initialize(&server.scheduler); - - err = tapdisk_server_init_aio(); + err = tapdisk_server_complete(); if (err) - return err; - - server.run = 1; + goto fail; return 0; + +fail: + tapdisk_server_close(); + return err; } int diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/drivers/tapdisk-server.h --- a/tools/blktap2/drivers/tapdisk-server.h Mon Jun 07 14:53:15 2010 -0700 +++ b/tools/blktap2/drivers/tapdisk-server.h Mon Jun 07 14:53:16 2010 -0700 @@ -28,6 +28,7 @@ #ifndef _TAPDISK_SERVER_H_ #define _TAPDISK_SERVER_H_ +#include "list.h" #include "tapdisk-vbd.h" #include "tapdisk-queue.h" @@ -35,6 +36,7 @@ td_image_t *tapdisk_server_get_shared_image(td_image_t *); +struct list_head *tapdisk_server_get_all_vbds(void); td_vbd_t *tapdisk_server_get_vbd(td_uuid_t); void tapdisk_server_add_vbd(td_vbd_t *); void tapdisk_server_remove_vbd(td_vbd_t *); @@ -47,8 +49,11 @@ void tapdisk_server_unregister_event(event_id_t); void tapdisk_server_set_max_timeout(int); +int tapdisk_server_init(void); int tapdisk_server_initialize(void); +int tapdisk_server_complete(void); int tapdisk_server_run(void); +void tapdisk_server_iterate(void); #define TAPDISK_TIOCBS (TAPDISK_DATA_REQUESTS + 50) diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/drivers/tapdisk-vbd.c --- a/tools/blktap2/drivers/tapdisk-vbd.c Mon Jun 07 14:53:15 2010 -0700 +++ b/tools/blktap2/drivers/tapdisk-vbd.c Mon Jun 07 14:53:16 2010 -0700 @@ -38,7 +38,6 @@ #include #endif -#include "libvhd.h" #include "tapdisk-image.h" #include "tapdisk-driver.h" #include "tapdisk-server.h" @@ -93,25 +92,20 @@ } } -int -tapdisk_vbd_initialize(uint16_t uuid) +td_vbd_t* +tapdisk_vbd_create(uint16_t uuid) { + td_vbd_t *vbd; int i; - td_vbd_t *vbd; - - vbd = tapdisk_server_get_vbd(uuid); - if (vbd) { - EPRINTF("duplicate vbds! %u\n", uuid); - return -EEXIST; - } vbd = calloc(1, sizeof(td_vbd_t)); if (!vbd) { EPRINTF("failed to allocate tapdisk state\n"); - return -ENOMEM; + return NULL; } vbd->uuid = uuid; + vbd->minor = -1; vbd->ring.fd = -1; /* default blktap ring completion */ @@ -134,6 +128,22 @@ for (i = 0; i < MAX_REQUESTS; i++) tapdisk_vbd_initialize_vreq(vbd->request_list + i); + return vbd; +} + +int +tapdisk_vbd_initialize(uint16_t uuid) +{ + td_vbd_t *vbd; + + vbd = tapdisk_server_get_vbd(uuid); + if (vbd) { + EPRINTF("duplicate vbds! %u\n", uuid); + return -EEXIST; + } + + vbd = tapdisk_vbd_create(uuid); + tapdisk_server_add_vbd(vbd); return 0; @@ -181,6 +191,8 @@ INIT_LIST_HEAD(&vbd->images); td_flag_set(vbd->state, TD_VBD_CLOSED); + + tapdisk_vbd_free_stack(vbd); } static int @@ -646,9 +658,42 @@ return 0; } +void +tapdisk_vbd_detach(td_vbd_t *vbd) +{ + tapdisk_vbd_unregister_events(vbd); + + tapdisk_vbd_unmap_device(vbd); + vbd->minor = -1; +} + + +int +tapdisk_vbd_attach(td_vbd_t *vbd, const char *devname, int minor) +{ + int err; + + err = tapdisk_vbd_map_device(vbd, devname); + if (err) + goto fail; + + err = tapdisk_vbd_register_event_watches(vbd); + if (err) + goto fail; + + vbd->minor = minor; + + return 0; + +fail: + tapdisk_vbd_detach(vbd); + + return err; +} + int tapdisk_vbd_open(td_vbd_t *vbd, const char *name, uint16_t type, - uint16_t storage, const char *ring, td_flag_t flags) + uint16_t storage, int minor, const char *ring, td_flag_t flags) { int err; @@ -656,20 +701,15 @@ if (err) goto out; - err = tapdisk_vbd_map_device(vbd, ring); - if (err) - goto out; - - err = tapdisk_vbd_register_event_watches(vbd); + err = tapdisk_vbd_attach(vbd, ring, minor); if (err) goto out; return 0; out: + tapdisk_vbd_detach(vbd); tapdisk_vbd_close_vdi(vbd); - tapdisk_vbd_unmap_device(vbd); - tapdisk_vbd_unregister_events(vbd); free(vbd->name); vbd->name = NULL; return err; @@ -727,11 +767,9 @@ vbd->kicked); tapdisk_vbd_close_vdi(vbd); - tapdisk_vbd_unregister_events(vbd); - tapdisk_vbd_unmap_device(vbd); + tapdisk_vbd_detach(vbd); tapdisk_server_remove_vbd(vbd); - free(vbd->name); - free(vbd); + tapdisk_vbd_free(vbd); tlog_print_errors(); @@ -941,17 +979,18 @@ return -EINVAL; } - free(vbd->name); - vbd->name = strdup(path); - if (!vbd->name) { - EPRINTF("copying new vbd %s name failed\n", path); - return -EINVAL; + if (path) { + free(vbd->name); + vbd->name = strdup(path); + if (!vbd->name) { + EPRINTF("copying new vbd %s name failed\n", path); + return -EINVAL; + } } - vbd->type = drivertype; for (i = 0; i < TD_VBD_EIO_RETRIES; i++) { err = __tapdisk_vbd_open_vdi(vbd, TD_OPEN_STRICT); - if (!err) + if (err != -EIO) break; sleep(TD_VBD_EIO_SLEEP); @@ -963,6 +1002,7 @@ tapdisk_vbd_start_queue(vbd); td_flag_clear(vbd->state, TD_VBD_PAUSED); td_flag_clear(vbd->state, TD_VBD_PAUSE_REQUESTED); + tapdisk_vbd_check_state(vbd); return 0; } @@ -1607,7 +1647,6 @@ err = -ENOMEM; goto out; } - vbd->type = type; tapdisk_vbd_start_queue(vbd); diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/drivers/tapdisk-vbd.h --- a/tools/blktap2/drivers/tapdisk-vbd.h Mon Jun 07 14:53:15 2010 -0700 +++ b/tools/blktap2/drivers/tapdisk-vbd.h Mon Jun 07 14:53:16 2010 -0700 @@ -89,7 +89,7 @@ char *name; td_uuid_t uuid; - int type; + int minor; struct list_head driver_stack; @@ -168,18 +168,24 @@ return list_entry(image->next.next, td_image_t, next); } +td_vbd_t *tapdisk_vbd_create(td_uuid_t); int tapdisk_vbd_initialize(td_uuid_t); void tapdisk_vbd_set_callback(td_vbd_t *, td_vbd_cb_t, void *); int tapdisk_vbd_parse_stack(td_vbd_t *vbd, const char *path); int tapdisk_vbd_open(td_vbd_t *, const char *, uint16_t, - uint16_t, const char *, td_flag_t); + uint16_t, int, const char *, td_flag_t); int tapdisk_vbd_close(td_vbd_t *); +void tapdisk_vbd_free(td_vbd_t *); void tapdisk_vbd_free_stack(td_vbd_t *); +int tapdisk_vbd_open_stack(td_vbd_t *, uint16_t, td_flag_t); int tapdisk_vbd_open_vdi(td_vbd_t *, const char *, uint16_t, uint16_t, td_flag_t); void tapdisk_vbd_close_vdi(td_vbd_t *); +int tapdisk_vbd_attach(td_vbd_t *, const char *, int); +void tapdisk_vbd_detach(td_vbd_t *); + void tapdisk_vbd_forward_request(td_request_t); int tapdisk_vbd_get_image_info(td_vbd_t *, image_t *); diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/drivers/tapdisk2.c --- a/tools/blktap2/drivers/tapdisk2.c Mon Jun 07 14:53:15 2010 -0700 +++ b/tools/blktap2/drivers/tapdisk2.c Mon Jun 07 14:53:16 2010 -0700 @@ -28,397 +28,37 @@ #include #include #include +#include #include -#include -#include -#include -#include -#include #ifdef MEMSHR #include #endif #include "tapdisk.h" -#include "blktap2.h" -#include "tapdisk-vbd.h" #include "tapdisk-utils.h" #include "tapdisk-server.h" -#include "tapdisk-disktype.h" - -#define TAPDISK2_VBD 0 - -#define cprintf(_err, _f, _a...) \ - do { \ - if (child_out) { \ - fprintf(child_out, "%d: " _f, _err, ##_a); \ - fflush(child_out); \ - } \ - } while (0) - -#define CHILD_ERR(_err, _f, _a...) \ - do { \ - EPRINTF(_f, ##_a); \ - cprintf(_err, _f, ##_a); \ - } while (0) - -static int channel[2]; -static FILE *child_out; -static struct blktap2_handle handle; - -static int -tapdisk2_prepare_directory(void) -{ - int err; - char *ptr, *name, *start; - - err = access(BLKTAP2_DIRECTORY, W_OK | R_OK); - if (!err) - return 0; - - name = strdup(BLKTAP2_DIRECTORY); - if (!name) - return -ENOMEM; - - start = name; - - for (;;) { - ptr = strchr(start + 1, '/'); - if (ptr) - *ptr = '\0'; - - err = mkdir(name, 0755); - if (err && errno != EEXIST) { - err = -errno; - CHILD_ERR(err, "failed to create directory %s: %d\n", - name, err); - break; - } - - if (!ptr) - break; - else { - *ptr = '/'; - start = ptr + 1; - } - } - - free(name); - return err; -} - -static int -tapdisk2_make_device(char *devname, int major, int minor, int perm) -{ - int err; - struct stat st; - - err = tapdisk2_prepare_directory(); - if (err) - return err; - - if (!access(devname, F_OK)) - if (unlink(devname)) { - CHILD_ERR(errno, "error unlinking %s: %d\n", - devname, errno); - return -errno; - } - - err = mknod(devname, perm, makedev(major, minor)); - if (err) { - CHILD_ERR(errno, "mknod %s failed: %d\n", devname, -errno); - return -errno; - } - - DPRINTF("Created %s device\n", devname); - return 0; -} - -static int -tapdisk2_check_environment(void) -{ - FILE *f; - int err, minor; - char name[256]; - - if (!access(BLKTAP2_CONTROL_DEVICE, R_OK | W_OK)) - return 0; - - memset(name, 0, sizeof(name)); - - f = fopen("/proc/misc", "r"); - if (!f) { - CHILD_ERR(errno, "failed to open /proc/misc: %d\n", errno); - return -errno; - } - - while (fscanf(f, "%d %256s", &minor, name) == 2) - if (!strcmp(name, BLKTAP2_CONTROL_NAME)) { - err = tapdisk2_make_device(BLKTAP2_CONTROL_DEVICE, - MISC_MAJOR_NUMBER, - minor, S_IFCHR | 0600); - goto out; - } - - err = -ENOSYS; - CHILD_ERR(err, "didn't find %s in /proc/misc\n", BLKTAP2_CONTROL_NAME); - -out: - fclose(f); - return err; -} - -static void -tapdisk2_free_device(void) -{ - int fd, err; - - fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY); - if (fd == -1) { - CHILD_ERR(errno, "failed to open control device: %d\n", errno); - return; - } - - err = ioctl(fd, BLKTAP2_IOCTL_FREE_TAP, handle.minor); - close(fd); -} - -static int -tapdisk2_prepare_device(void) -{ - char *name; - int fd, err; - - fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY); - if (fd == -1) { - CHILD_ERR(errno, "failed to open control device: %d\n", errno); - return -errno; - } - - err = ioctl(fd, BLKTAP2_IOCTL_ALLOC_TAP, &handle); - close(fd); - if (err == -1) { - CHILD_ERR(errno, "failed to allocate new device: %d\n", errno); - return -errno; - } - - err = asprintf(&name, "%s%d", BLKTAP2_RING_DEVICE, handle.minor); - if (err == -1) { - err = -ENOMEM; - goto fail; - } - - err = tapdisk2_make_device(name, handle.ring, - handle.minor, S_IFCHR | 0600); - free(name); - if (err) { - CHILD_ERR(err, "creating ring device for %d failed: %d\n", - handle.minor, err); - goto fail; - } - - err = asprintf(&name, "%s%d", BLKTAP2_IO_DEVICE, handle.minor); - if (err == -1) { - err = -ENOMEM; - goto fail; - } - - err = tapdisk2_make_device(name, handle.device, - handle.minor, S_IFBLK | 0600); - free(name); - if (err) { - CHILD_ERR(err, "creating IO device for %d failed: %d\n", - handle.minor, err); - goto fail; - } - - DPRINTF("new interface: ring: %u, device: %u, minor: %u\n", - handle.ring, handle.device, handle.minor); - - return 0; - -fail: - tapdisk2_free_device(); - return err; -} - -static int -tapdisk2_open_device(int type, const char *path, const char *name) -{ - int err; - td_vbd_t *vbd; - image_t image; - char *devname; - struct blktap2_params params; - - err = tapdisk_vbd_initialize(TAPDISK2_VBD); - if (err) - return err; - - vbd = tapdisk_server_get_vbd(TAPDISK2_VBD); - if (!vbd) { - err = -ENODEV; - CHILD_ERR(err, "couldn't find vbd\n"); - return err; - } - - err = asprintf(&devname, "%s%d", BLKTAP2_RING_DEVICE, handle.minor); - if (err == -1) { - err = -ENOMEM; - CHILD_ERR(err, "couldn't allocate ring\n"); - return err; - } - - err = tapdisk_vbd_parse_stack(vbd, name); - if (err) { - CHILD_ERR(err, "vbd_parse_stack failed: %d\n", err); - return err; - } - - /* TODO: clean this up */ - err = tapdisk_vbd_open(vbd, path, type, - TAPDISK_STORAGE_TYPE_DEFAULT, - devname, 0); - free(devname); - if (err) { - CHILD_ERR(err, "vbd open failed: %d\n", err); - return err; - } - - memset(¶ms, 0, sizeof(params)); - tapdisk_vbd_get_image_info(vbd, &image); - - params.capacity = image.size; - params.sector_size = image.secsize; - snprintf(params.name, sizeof(params.name) - 1, "%s", name); - - err = ioctl(vbd->ring.fd, BLKTAP2_IOCTL_CREATE_DEVICE, ¶ms); - if (err) { - err = -errno; - CHILD_ERR(err, "create device failed: %d\n", err); - return err; - } - - return 0; -} - -static int -tapdisk2_set_child_fds(void) -{ - int i, err; - - err = dup2(channel[1], STDOUT_FILENO); - if (err == -1) { - CHILD_ERR(errno, "failed duping pipe: %d\n", errno); - return errno; - } - - child_out = fdopen(STDOUT_FILENO, "w"); - if (!child_out) { - CHILD_ERR(errno, "failed setting child_out: %d\n", errno); - return errno; - } - - for (i = 0; i < sysconf(_SC_OPEN_MAX); i++) - if (i != STDOUT_FILENO) - close(i); - - return 0; -} - -static int -tapdisk2_create_device(const char *params) -{ - const char *path; - int err, type; - - chdir("/"); - tapdisk_start_logging("tapdisk2"); - - err = tapdisk2_set_child_fds(); - if (err) - goto out; - - err = tapdisk2_check_environment(); - if (err) - goto out; - - err = tapdisk_parse_disk_type(params, &path, &type); - if (err) - goto out; - - err = tapdisk2_prepare_device(); - if (err) - goto out; - - err = tapdisk_server_initialize(); - if (err) - goto fail; - - err = tapdisk2_open_device(type, path, params); - if (err) - goto fail; - - cprintf(0, "%s%d\n", BLKTAP2_IO_DEVICE, handle.minor); - close(STDOUT_FILENO); - - err = tapdisk_server_run(); - if (err) - goto fail; - - err = 0; - -out: - tapdisk_stop_logging(); - return err; - -fail: - tapdisk2_free_device(); - goto out; -} - -static int -tapdisk2_wait_for_device(void) -{ - int err; - char msg[1024]; - FILE *parent_in; - - close(channel[1]); - parent_in = fdopen(channel[0], "r"); - if (!parent_in) { - printf("failed to connect to child: %d\n", errno); - return errno; - } - - memset(msg, 0, sizeof(msg)); - if (fscanf(parent_in, "%d: %1023[^\n]", &err, msg) != 2) { - printf("unrecognized child response\n"); - return EINVAL; - } - - printf("%s\n", msg); - return (err >= 0 ? err : -err); -} +#include "tapdisk-control.h" static void usage(const char *app, int err) { - fprintf(stderr, "usage: %s <-n file>\n", app); + fprintf(stderr, "usage: %s <-u uuid> <-c control socket>\n", app); exit(err); } int main(int argc, char *argv[]) { - int c; - char *params; + char *control; + int c, err, nodaemon; - params = NULL; + control = NULL; + nodaemon = 0; - while ((c = getopt(argc, argv, "n:s:h")) != -1) { + while ((c = getopt(argc, argv, "s:Dh")) != -1) { switch (c) { - case 'n': - params = optarg; + case 'D': + nodaemon = 1; break; case 'h': usage(argv[0], 0); @@ -436,21 +76,58 @@ } } - if (!params || optind != argc) + if (optind != argc) usage(argv[0], EINVAL); - if (pipe(channel) == -1) { - printf("pipe failed: %d\n", errno); - return errno; + chdir("/"); + tapdisk_start_logging("tapdisk2"); + + err = tapdisk_server_init(); + if (err) { + DPRINTF("failed to initialize server: %d\n", err); + goto out; } - switch (fork()) { - case -1: - printf("fork failed: %d\n", errno); - return errno; - case 0: - return tapdisk2_create_device(params); - default: - return tapdisk2_wait_for_device(); + if (!nodaemon) { + err = daemon(0, 1); + if (err) { + DPRINTF("failed to daemonize: %d\n", errno); + goto out; + } } + + err = tapdisk_control_open(&control); + if (err) { + DPRINTF("failed to open control socket: %d\n", err); + goto out; + } + + fprintf(stdout, "%s\n", control); + fflush(stdout); + + if (!nodaemon) { + int fd; + + fd = open("/dev/null", O_RDWR); + if (fd != -1) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > 2) + close(fd); + } + } + + err = tapdisk_server_complete(); + if (err) { + DPRINTF("failed to complete server: %d\n", err); + goto out; + } + + err = tapdisk_server_run(); + +out: + tapdisk_control_close(); + tapdisk_stop_logging(); + return err; } diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/include/blktap2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/blktap2/include/blktap2.h Mon Jun 07 14:53:16 2010 -0700 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _BLKTAP_2_H_ +#define _BLKTAP_2_H_ + +#define BLKTAP2_MAX_MESSAGE_LEN 256 + +#define BLKTAP2_RING_MESSAGE_PAUSE 1 +#define BLKTAP2_RING_MESSAGE_RESUME 2 +#define BLKTAP2_RING_MESSAGE_CLOSE 3 + +#define BLKTAP2_IOCTL_KICK_FE 1 +#define BLKTAP2_IOCTL_ALLOC_TAP 200 +#define BLKTAP2_IOCTL_FREE_TAP 201 +#define BLKTAP2_IOCTL_CREATE_DEVICE 202 +#define BLKTAP2_IOCTL_SET_PARAMS 203 +#define BLKTAP2_IOCTL_PAUSE 204 +#define BLKTAP2_IOCTL_REOPEN 205 +#define BLKTAP2_IOCTL_RESUME 206 + +#define BLKTAP2_SYSFS_DIR "/sys/class/blktap2" +#define BLKTAP2_CONTROL_NAME "blktap-control" +#define BLKTAP2_CONTROL_DIR "/var/run/"BLKTAP2_CONTROL_NAME +#define BLKTAP2_CONTROL_SOCKET "ctl" +#define BLKTAP2_DIRECTORY "/dev/xen/blktap-2" +#define BLKTAP2_CONTROL_DEVICE BLKTAP2_DIRECTORY"/control" +#define BLKTAP2_RING_DEVICE BLKTAP2_DIRECTORY"/blktap" +#define BLKTAP2_IO_DEVICE BLKTAP2_DIRECTORY"/tapdev" + +struct blktap2_handle { + unsigned int ring; + unsigned int device; + unsigned int minor; +}; + +struct blktap2_params { + char name[BLKTAP2_MAX_MESSAGE_LEN]; + unsigned long long capacity; + unsigned long sector_size; +}; + +#endif diff -r 3ea1751e3fe7 -r ccef87cf5f41 tools/blktap2/include/tapdisk-message.h --- a/tools/blktap2/include/tapdisk-message.h Mon Jun 07 14:53:15 2010 -0700 +++ b/tools/blktap2/include/tapdisk-message.h Mon Jun 07 14:53:16 2010 -0700 @@ -33,6 +33,9 @@ #define TAPDISK_MESSAGE_MAX_PATH_LENGTH 256 #define TAPDISK_MESSAGE_STRING_LENGTH 256 +#define TAPDISK_MESSAGE_MAX_MINORS \ + ((TAPDISK_MESSAGE_MAX_PATH_LENGTH / sizeof(int)) - 1) + #define TAPDISK_MESSAGE_FLAG_SHARED 0x01 #define TAPDISK_MESSAGE_FLAG_RDONLY 0x02 #define TAPDISK_MESSAGE_FLAG_ADD_CACHE 0x04 @@ -44,10 +47,13 @@ typedef struct tapdisk_message_image tapdisk_message_image_t; typedef struct tapdisk_message_params tapdisk_message_params_t; typedef struct tapdisk_message_string tapdisk_message_string_t; +typedef struct tapdisk_message_response tapdisk_message_response_t; +typedef struct tapdisk_message_minors tapdisk_message_minors_t; +typedef struct tapdisk_message_list tapdisk_message_list_t; struct tapdisk_message_params { tapdisk_message_flag_t flags; - + uint8_t storage; uint32_t devnum; uint32_t domid; @@ -65,6 +71,23 @@ char text[TAPDISK_MESSAGE_STRING_LENGTH]; }; +struct tapdisk_message_response { + int error; + char message[TAPDISK_MESSAGE_STRING_LENGTH]; +}; + +struct tapdisk_message_minors { + int count; + int list[TAPDISK_MESSAGE_MAX_MINORS]; +}; + +struct tapdisk_message_list { + int count; + int minor; + int state; + char path[TAPDISK_MESSAGE_MAX_PATH_LENGTH]; +}; + struct tapdisk_message { uint16_t type; uint16_t cookie; @@ -74,6 +97,9 @@ tapdisk_message_image_t image; tapdisk_message_params_t params; tapdisk_message_string_t string; + tapdisk_message_minors_t minors; + tapdisk_message_response_t response; + tapdisk_message_list_t list; } u; }; @@ -82,6 +108,8 @@ TAPDISK_MESSAGE_RUNTIME_ERROR, TAPDISK_MESSAGE_PID, TAPDISK_MESSAGE_PID_RSP, + TAPDISK_MESSAGE_ATTACH, + TAPDISK_MESSAGE_ATTACH_RSP, TAPDISK_MESSAGE_OPEN, TAPDISK_MESSAGE_OPEN_RSP, TAPDISK_MESSAGE_PAUSE, @@ -90,6 +118,13 @@ TAPDISK_MESSAGE_RESUME_RSP, TAPDISK_MESSAGE_CLOSE, TAPDISK_MESSAGE_CLOSE_RSP, + TAPDISK_MESSAGE_DETACH, + TAPDISK_MESSAGE_DETACH_RSP, + TAPDISK_MESSAGE_LIST_MINORS, + TAPDISK_MESSAGE_LIST_MINORS_RSP, + TAPDISK_MESSAGE_LIST, + TAPDISK_MESSAGE_LIST_RSP, + TAPDISK_MESSAGE_FORCE_SHUTDOWN, TAPDISK_MESSAGE_EXIT, }; @@ -127,9 +162,36 @@ case TAPDISK_MESSAGE_CLOSE: return "close"; + case TAPDISK_MESSAGE_FORCE_SHUTDOWN: + return "force shutdown"; + case TAPDISK_MESSAGE_CLOSE_RSP: return "close response"; + case TAPDISK_MESSAGE_ATTACH: + return "attach"; + + case TAPDISK_MESSAGE_ATTACH_RSP: + return "attach response"; + + case TAPDISK_MESSAGE_DETACH: + return "detach"; + + case TAPDISK_MESSAGE_DETACH_RSP: + return "detach response"; + + case TAPDISK_MESSAGE_LIST_MINORS: + return "list minors"; + + case TAPDISK_MESSAGE_LIST_MINORS_RSP: + return "list minors response"; + + case TAPDISK_MESSAGE_LIST: + return "list"; + + case TAPDISK_MESSAGE_LIST_RSP: + return "list response"; + case TAPDISK_MESSAGE_EXIT: return "exit";