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/drivers | |
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/drivers')
-rw-r--r-- | tools/blktap2/drivers/Makefile | 4 | ||||
-rw-r--r-- | tools/blktap2/drivers/tapdisk-control.c | 836 | ||||
-rw-r--r-- | tools/blktap2/drivers/tapdisk-control.h (renamed from tools/blktap2/drivers/blktap2.h) | 39 | ||||
-rw-r--r-- | tools/blktap2/drivers/tapdisk-server.c | 75 | ||||
-rw-r--r-- | tools/blktap2/drivers/tapdisk-server.h | 5 | ||||
-rw-r--r-- | tools/blktap2/drivers/tapdisk-vbd.c | 101 | ||||
-rw-r--r-- | tools/blktap2/drivers/tapdisk-vbd.h | 10 | ||||
-rw-r--r-- | tools/blktap2/drivers/tapdisk2.c | 441 |
8 files changed, 1041 insertions, 470 deletions
diff --git a/tools/blktap2/drivers/Makefile b/tools/blktap2/drivers/Makefile index 88d3a8c8b5..446c8c6fb7 100644 --- a/tools/blktap2/drivers/Makefile +++ b/tools/blktap2/drivers/Makefile @@ -12,8 +12,7 @@ INST_DIR = $(SBINDIR) 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) @@ -63,6 +62,7 @@ PORTABLE-OBJS-$(CONFIG_NetBSD) += blk_netbsd.o 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 --git a/tools/blktap2/drivers/tapdisk-control.c b/tools/blktap2/drivers/tapdisk-control.c new file mode 100644 index 0000000000..a48c11301e --- /dev/null +++ b/tools/blktap2/drivers/tapdisk-control.c @@ -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 <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <sys/un.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#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 --git a/tools/blktap2/drivers/blktap2.h b/tools/blktap2/drivers/tapdisk-control.h index 38350d2fad..10c18112f3 100644 --- a/tools/blktap2/drivers/blktap2.h +++ b/tools/blktap2/drivers/tapdisk-control.h @@ -25,42 +25,11 @@ * 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 +#ifndef __TAPDISK_CONTROL_H__ +#define __TAPDISK_CONTROL_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_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; -}; +int tapdisk_control_open(char **path); +void tapdisk_control_close(void); #endif diff --git a/tools/blktap2/drivers/tapdisk-server.c b/tools/blktap2/drivers/tapdisk-server.c index 73e9717815..eecde3d23f 100644 --- a/tools/blktap2/drivers/tapdisk-server.c +++ b/tools/blktap2/drivers/tapdisk-server.c @@ -63,6 +63,12 @@ tapdisk_server_get_shared_image(td_image_t *image) 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(void) tapdisk_server_close_aio(); } -static void -__tapdisk_server_run(void) +void +tapdisk_server_iterate(void) { int ret; - while (server.run) { - tapdisk_server_assert_locks(); - tapdisk_server_set_retry_timeout(); - tapdisk_server_check_progress(); + 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); + 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(); - } + tapdisk_server_check_vbds(); + tapdisk_server_submit_tiocbs(); + tapdisk_server_kick_responses(); +} + +static void +__tapdisk_server_run(void) +{ + while (server.run) + tapdisk_server_iterate(); } static void @@ -267,22 +278,50 @@ tapdisk_server_signal_handler(int signal) } int -tapdisk_server_initialize(void) +tapdisk_server_init(void) { - int err; - - memset(&server, 0, sizeof(tapdisk_server_t)); + 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) - return err; + goto fail; server.run = 1; return 0; + +fail: + tapdisk_server_close_aio(); + return err; +} + +int +tapdisk_server_initialize(void) +{ + int err; + + tapdisk_server_init(); + + err = tapdisk_server_complete(); + if (err) + goto fail; + + return 0; + +fail: + tapdisk_server_close(); + return err; } int diff --git a/tools/blktap2/drivers/tapdisk-server.h b/tools/blktap2/drivers/tapdisk-server.h index f401b049b2..d9c1a03bb5 100644 --- a/tools/blktap2/drivers/tapdisk-server.h +++ b/tools/blktap2/drivers/tapdisk-server.h @@ -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 @@ struct tap_disk *tapdisk_server_find_driver_interface(int); 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 @@ event_id_t tapdisk_server_register_event(char, int, int, event_cb_t, void *); 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 --git a/tools/blktap2/drivers/tapdisk-vbd.c b/tools/blktap2/drivers/tapdisk-vbd.c index f39fdadb1a..e6d18594ce 100644 --- a/tools/blktap2/drivers/tapdisk-vbd.c +++ b/tools/blktap2/drivers/tapdisk-vbd.c @@ -38,7 +38,6 @@ #include <memshr.h> #endif -#include "libvhd.h" #include "tapdisk-image.h" #include "tapdisk-driver.h" #include "tapdisk-server.h" @@ -93,25 +92,20 @@ tapdisk_vbd_free(td_vbd_t *vbd) } } -int -tapdisk_vbd_initialize(uint16_t uuid) +td_vbd_t* +tapdisk_vbd_create(uint16_t uuid) { - int i; td_vbd_t *vbd; - - vbd = tapdisk_server_get_vbd(uuid); - if (vbd) { - EPRINTF("duplicate vbds! %u\n", uuid); - return -EEXIST; - } + int i; 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 @@ tapdisk_vbd_initialize(uint16_t uuid) 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 @@ tapdisk_vbd_close_vdi(td_vbd_t *vbd) INIT_LIST_HEAD(&vbd->images); td_flag_set(vbd->state, TD_VBD_CLOSED); + + tapdisk_vbd_free_stack(vbd); } static int @@ -646,30 +658,58 @@ tapdisk_vbd_unmap_device(td_vbd_t *vbd) 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_open(td_vbd_t *vbd, const char *name, uint16_t type, - uint16_t storage, const char *ring, td_flag_t flags) +tapdisk_vbd_attach(td_vbd_t *vbd, const char *devname, int minor) { int err; - err = tapdisk_vbd_open_stack(vbd, storage, flags); + err = tapdisk_vbd_map_device(vbd, devname); if (err) - goto out; + goto fail; - err = tapdisk_vbd_map_device(vbd, ring); + 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, int minor, const char *ring, td_flag_t flags) +{ + int err; + + err = tapdisk_vbd_open_stack(vbd, storage, flags); 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 @@ tapdisk_vbd_shutdown(td_vbd_t *vbd) 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 @@ tapdisk_vbd_resume(td_vbd_t *vbd, const char *path, uint16_t drivertype) 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_resume(td_vbd_t *vbd, const char *path, uint16_t drivertype) 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 @@ tapdisk_vbd_resume_ring(td_vbd_t *vbd) err = -ENOMEM; goto out; } - vbd->type = type; tapdisk_vbd_start_queue(vbd); diff --git a/tools/blktap2/drivers/tapdisk-vbd.h b/tools/blktap2/drivers/tapdisk-vbd.h index 0fea53e4f9..be084b2e03 100644 --- a/tools/blktap2/drivers/tapdisk-vbd.h +++ b/tools/blktap2/drivers/tapdisk-vbd.h @@ -89,7 +89,7 @@ struct td_vbd_handle { char *name; td_uuid_t uuid; - int type; + int minor; struct list_head driver_stack; @@ -168,18 +168,24 @@ tapdisk_vbd_next_image(td_image_t *image) 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 --git a/tools/blktap2/drivers/tapdisk2.c b/tools/blktap2/drivers/tapdisk2.c index 0eb10cb5e5..d30f73984a 100644 --- a/tools/blktap2/drivers/tapdisk2.c +++ b/tools/blktap2/drivers/tapdisk2.c @@ -28,397 +28,37 @@ #include <stdio.h> #include <errno.h> #include <fcntl.h> -#include <unistd.h> #include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/ioctl.h> +#include <unistd.h> #ifdef MEMSHR #include <memshr.h> #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 @@ main(int argc, char *argv[]) } } - 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; + } + + 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); + } } - 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(); + 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; } |