diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2010-06-08 08:05:09 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2010-06-08 08:05:09 +0100 |
commit | 4b1af8b188ccf532742ed5f2a49f480d9a702333 (patch) | |
tree | a34e14bc4e972f3ec7af5870b6a7ed634cd3282b /tools/blktap2/control | |
parent | c6913b5aaf48107f7bb9fb4e01c7f74c863b3713 (diff) | |
download | xen-4b1af8b188ccf532742ed5f2a49f480d9a702333.tar.gz xen-4b1af8b188ccf532742ed5f2a49f480d9a702333.tar.bz2 xen-4b1af8b188ccf532742ed5f2a49f480d9a702333.zip |
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 <jake.wires@citrix.com>
Signed-off-by: Daniel Stodden <daniel.stodden@citrix.com>
Diffstat (limited to 'tools/blktap2/control')
-rw-r--r-- | tools/blktap2/control/Makefile | 57 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-allocate.c | 242 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-attach.c | 61 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-check.c | 79 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-close.c | 87 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-create.c | 65 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-destroy.c | 56 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-detach.c | 61 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-free.c | 54 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-ipc.c | 237 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-list.c | 506 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-major.c | 69 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-open.c | 75 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-pause.c | 59 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-spawn.c | 174 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl-unpause.c | 64 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl.c | 815 | ||||
-rw-r--r-- | tools/blktap2/control/tap-ctl.h | 101 |
18 files changed, 2862 insertions, 0 deletions
diff --git a/tools/blktap2/control/Makefile b/tools/blktap2/control/Makefile new file mode 100644 index 0000000000..68b4285ba8 --- /dev/null +++ b/tools/blktap2/control/Makefile @@ -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 --git a/tools/blktap2/control/tap-ctl-allocate.c b/tools/blktap2/control/tap-ctl-allocate.c new file mode 100644 index 0000000000..8a6471e987 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-allocate.c @@ -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 <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <getopt.h> +#include <libgen.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <linux/major.h> + +#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 --git a/tools/blktap2/control/tap-ctl-attach.c b/tools/blktap2/control/tap-ctl-attach.c new file mode 100644 index 0000000000..3cb933cec8 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-attach.c @@ -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 <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> + +#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 --git a/tools/blktap2/control/tap-ctl-check.c b/tools/blktap2/control/tap-ctl-check.c new file mode 100644 index 0000000000..e98583a73b --- /dev/null +++ b/tools/blktap2/control/tap-ctl-check.c @@ -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 <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> + +#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 --git a/tools/blktap2/control/tap-ctl-close.c b/tools/blktap2/control/tap-ctl-close.c new file mode 100644 index 0000000000..2e5f80b29d --- /dev/null +++ b/tools/blktap2/control/tap-ctl-close.c @@ -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 <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <getopt.h> + +#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 --git a/tools/blktap2/control/tap-ctl-create.c b/tools/blktap2/control/tap-ctl-create.c new file mode 100644 index 0000000000..46d135e93c --- /dev/null +++ b/tools/blktap2/control/tap-ctl-create.c @@ -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 <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <getopt.h> + +#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 --git a/tools/blktap2/control/tap-ctl-destroy.c b/tools/blktap2/control/tap-ctl-destroy.c new file mode 100644 index 0000000000..dc5dbaa1a2 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-destroy.c @@ -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 <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <getopt.h> + +#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 --git a/tools/blktap2/control/tap-ctl-detach.c b/tools/blktap2/control/tap-ctl-detach.c new file mode 100644 index 0000000000..7d7bbf30d3 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-detach.c @@ -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 <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> + +#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 --git a/tools/blktap2/control/tap-ctl-free.c b/tools/blktap2/control/tap-ctl-free.c new file mode 100644 index 0000000000..9ae7295747 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-free.c @@ -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 <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <getopt.h> +#include <sys/ioctl.h> + +#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 --git a/tools/blktap2/control/tap-ctl-ipc.c b/tools/blktap2/control/tap-ctl-ipc.c new file mode 100644 index 0000000000..cc6160e9da --- /dev/null +++ b/tools/blktap2/control/tap-ctl-ipc.c @@ -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 <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/un.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/socket.h> + +#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 --git a/tools/blktap2/control/tap-ctl-list.c b/tools/blktap2/control/tap-ctl-list.c new file mode 100644 index 0000000000..af5922772c --- /dev/null +++ b/tools/blktap2/control/tap-ctl-list.c @@ -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 <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <glob.h> + +#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 --git a/tools/blktap2/control/tap-ctl-major.c b/tools/blktap2/control/tap-ctl-major.c new file mode 100644 index 0000000000..847af28708 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-major.c @@ -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 <stdio.h> +#include <errno.h> + +#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 --git a/tools/blktap2/control/tap-ctl-open.c b/tools/blktap2/control/tap-ctl-open.c new file mode 100644 index 0000000000..5961c99183 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-open.c @@ -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 <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <getopt.h> + +#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 --git a/tools/blktap2/control/tap-ctl-pause.c b/tools/blktap2/control/tap-ctl-pause.c new file mode 100644 index 0000000000..5e31a5866d --- /dev/null +++ b/tools/blktap2/control/tap-ctl-pause.c @@ -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 <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#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 --git a/tools/blktap2/control/tap-ctl-spawn.c b/tools/blktap2/control/tap-ctl-spawn.c new file mode 100644 index 0000000000..31a651ec38 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-spawn.c @@ -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 <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> + +#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 --git a/tools/blktap2/control/tap-ctl-unpause.c b/tools/blktap2/control/tap-ctl-unpause.c new file mode 100644 index 0000000000..dfb7450226 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-unpause.c @@ -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 <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <getopt.h> + +#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 --git a/tools/blktap2/control/tap-ctl.c b/tools/blktap2/control/tap-ctl.c new file mode 100644 index 0000000000..80fc933a89 --- /dev/null +++ b/tools/blktap2/control/tap-ctl.c @@ -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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> + +#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 <sys/resource.h> + 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 --git a/tools/blktap2/control/tap-ctl.h b/tools/blktap2/control/tap-ctl.h new file mode 100644 index 0000000000..850f9f024b --- /dev/null +++ b/tools/blktap2/control/tap-ctl.h @@ -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 <syslog.h> +#include <errno.h> + +#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 |