+++ /dev/null
-/*
- * Copyright (c) 2008 Xensource Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation; or, when distributed
- * separately from the Linux kernel or incorporated into other
- * software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdarg.h>
-#include <sys/wait.h>
-#include <sys/ioctl.h>
-#include <sys/resource.h>
-
-#include <xs.h>
-#include "tapdisk-dispatch.h"
-
-static inline const char*
-tapdisk_channel_state_name(channel_state_t state)
-{
- switch (state) {
- case TAPDISK_CHANNEL_DEAD:
- return "dead";
- case TAPDISK_CHANNEL_LAUNCHED:
- return "launched";
- case TAPDISK_CHANNEL_WAIT_PID:
- return "wait-pid";
- case TAPDISK_CHANNEL_PID:
- return "pid";
- case TAPDISK_CHANNEL_WAIT_OPEN:
- return "wait-open";
- case TAPDISK_CHANNEL_RUNNING:
- return "running";
- case TAPDISK_CHANNEL_WAIT_PAUSE:
- return "wait-pause";
- case TAPDISK_CHANNEL_PAUSED:
- return "paused";
- case TAPDISK_CHANNEL_WAIT_RESUME:
- return "wait-resume";
- case TAPDISK_CHANNEL_WAIT_CLOSE:
- return "wait-close";
- case TAPDISK_CHANNEL_CLOSED:
- return "closed";
- }
-
- return "unknown";
-}
-
-static inline const char*
-tapdisk_channel_vbd_state_name(vbd_state_t state)
-{
- switch (state) {
- case TAPDISK_VBD_UNPAUSED:
- return "unpaused";
- case TAPDISK_VBD_PAUSING:
- return "pausing";
- case TAPDISK_VBD_PAUSED:
- return "paused";
- case TAPDISK_VBD_BROKEN:
- return "broken";
- case TAPDISK_VBD_DEAD:
- return "dead";
- case TAPDISK_VBD_RECYCLED:
- return "recycled";
- }
-
- return "unknown";
-}
-
-static inline int
-tapdisk_channel_vbd_fenced(tapdisk_channel_t *channel)
-{
- return
- channel->vbd_state == TAPDISK_VBD_BROKEN ||
- channel->vbd_state == TAPDISK_VBD_DEAD ||
- channel->vbd_state == TAPDISK_VBD_RECYCLED;
-}
-
-static inline int
-tapdisk_channel_enter_vbd_state(tapdisk_channel_t *channel, vbd_state_t state)
-{
- int err = 0;
-
- if (tapdisk_channel_vbd_fenced(channel))
- err = -EINVAL;
-
- DPRINTF("%s: vbd state %s -> %s: %d",
- channel->path,
- tapdisk_channel_vbd_state_name(channel->vbd_state),
- tapdisk_channel_vbd_state_name(state),
- err);
-
- if (!err)
- channel->vbd_state = state;
-
- return err;
-}
-
-static inline const char*
-tapdisk_channel_shutdown_state_name(shutdown_state_t state)
-{
- switch (state) {
- case TAPDISK_VBD_UP:
- return "up";
- case TAPDISK_VBD_DOWN:
- return "down";
- }
-
- return "unknown";
-}
-
-static int tapdisk_channel_write_atomic(tapdisk_channel_t *,
- const char *, const void *,
- unsigned int);
-static void tapdisk_channel_error(tapdisk_channel_t *,
- const char *fmt, ...)
- __attribute__((format(printf, 2, 3)));
-static void tapdisk_channel_fatal(tapdisk_channel_t *,
- const char *fmt, ...)
- __attribute__((format(printf, 2, 3)));
-static int tapdisk_channel_refresh_params(tapdisk_channel_t *);
-static int tapdisk_channel_connect(tapdisk_channel_t *);
-static void tapdisk_channel_close_tapdisk(tapdisk_channel_t *);
-static void tapdisk_channel_destroy(tapdisk_channel_t *);
-
-static int
-__tapdisk_channel_check_uuid(tapdisk_channel_t *channel, xs_transaction_t xbt)
-{
- uint32_t uuid;
- char *uuid_str;
-
- uuid_str = xs_read(channel->xsh, xbt, channel->uuid_str, NULL);
- if (!uuid_str)
- return -errno;
-
- uuid = strtoul(uuid_str, NULL, 10);
- free(uuid_str);
-
- if (uuid != channel->cookie)
- return -EINVAL;
-
- return 0;
-}
-
-int
-tapdisk_channel_check_uuid(tapdisk_channel_t *channel)
-{
- return __tapdisk_channel_check_uuid(channel, XBT_NULL);
-}
-
-static inline int
-tapdisk_channel_validate_watch(tapdisk_channel_t *channel, const char *path)
-{
- int err, len;
-
- len = strsep_len(path, '/', 7);
- if (len < 0)
- return -EINVAL;
-
- if (tapdisk_channel_vbd_fenced(channel))
- return -ENOENT;
-
- err = tapdisk_channel_check_uuid(channel);
- if (err)
- return -ENOENT;
-
- return 0;
-}
-
-static inline int
-tapdisk_channel_validate_message(tapdisk_channel_t *channel,
- tapdisk_message_t *message)
-{
- switch (message->type) {
- case TAPDISK_MESSAGE_PID_RSP:
- if (channel->state != TAPDISK_CHANNEL_WAIT_PID)
- return -EINVAL;
- break;
-
- case TAPDISK_MESSAGE_OPEN_RSP:
- if (channel->state != TAPDISK_CHANNEL_WAIT_OPEN)
- return -EINVAL;
- break;
-
- case TAPDISK_MESSAGE_PAUSE_RSP:
- if (channel->state != TAPDISK_CHANNEL_WAIT_PAUSE)
- return -EINVAL;
- break;
-
- case TAPDISK_MESSAGE_RESUME_RSP:
- if (channel->state != TAPDISK_CHANNEL_WAIT_RESUME)
- return -EINVAL;
- break;
-
- case TAPDISK_MESSAGE_CLOSE_RSP:
- if (channel->state != TAPDISK_CHANNEL_WAIT_CLOSE)
- return -EINVAL;
- break;
-
- case TAPDISK_MESSAGE_RUNTIME_ERROR:
- /*
- * runtime errors can be received at any time
- * and should not affect the state machine
- */
- return 0;
- }
-
- return 0;
-}
-
-static int
-tapdisk_channel_send_message(tapdisk_channel_t *channel,
- tapdisk_message_t *message, int timeout)
-{
- fd_set writefds;
- struct timeval tv;
- int ret, len, offset;
-
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
- offset = 0;
- len = sizeof(tapdisk_message_t);
-
- DPRINTF("%s: sending '%s' message to %d:%d, state %s\n",
- channel->path, tapdisk_message_name(message->type),
- channel->channel_id, channel->cookie,
- tapdisk_channel_state_name(channel->state));
-
- if (!TAPDISK_CHANNEL_IPC_IDLE(channel))
- EPRINTF("%s: writing message to non-idle channel, state %s (%d)\n",
- channel->path,
- tapdisk_channel_state_name(channel->state),
- channel->state);
-
- while (offset < len) {
- FD_ZERO(&writefds);
- FD_SET(channel->write_fd, &writefds);
-
- /* we don't bother reinitializing tv. at worst, it will wait a
- * bit more time than expected. */
-
- ret = select(channel->write_fd + 1,
- NULL, &writefds, NULL, &tv);
- if (ret == -1)
- break;
- else if (FD_ISSET(channel->write_fd, &writefds)) {
- ret = write(channel->write_fd,
- message + offset, len - offset);
- if (ret <= 0)
- break;
- offset += ret;
- } else
- break;
- }
-
- if (offset != len) {
- EPRINTF("%s: error writing '%s' message to %d:%d\n",
- channel->path, tapdisk_message_name(message->type),
- channel->channel_id, channel->cookie);
- return -EIO;
- }
-
- switch (message->type) {
- case TAPDISK_MESSAGE_PID:
- channel->state = TAPDISK_CHANNEL_WAIT_PID;
- break;
-
- case TAPDISK_MESSAGE_OPEN:
- channel->state = TAPDISK_CHANNEL_WAIT_OPEN;
- break;
-
- case TAPDISK_MESSAGE_PAUSE:
- channel->state = TAPDISK_CHANNEL_WAIT_PAUSE;
- break;
-
- case TAPDISK_MESSAGE_RESUME:
- channel->state = TAPDISK_CHANNEL_WAIT_RESUME;
- break;
-
- case TAPDISK_MESSAGE_CLOSE:
- channel->state = TAPDISK_CHANNEL_WAIT_CLOSE;
- break;
-
- case TAPDISK_MESSAGE_FORCE_SHUTDOWN:
- channel->state = TAPDISK_CHANNEL_WAIT_CLOSE;
- break;
-
- default:
- EPRINTF("%s: unrecognized message type %d\n",
- channel->path, message->type);
- }
-
- return 0;
-}
-
-static void
-__tapdisk_channel_error(tapdisk_channel_t *channel,
- const char *fmt, va_list ap)
-{
- int err;
- char *dir, *buf, *message;
-
- err = vasprintf(&buf, fmt, ap);
- if (err == -1) {
- EPRINTF("failed to allocate error message\n");
- buf = NULL;
- }
-
- if (buf)
- message = buf;
- else
- message = "tapdisk error";
-
- EPRINTF("%s: %s\n", channel->path, message);
-
- err = asprintf(&dir, "%s/tapdisk-error", channel->path);
- if (err == -1) {
- EPRINTF("%s: failed to write %s\n", __func__, message);
- dir = NULL;
- goto out;
- }
-
- tapdisk_channel_write_atomic(channel, dir, message, strlen(message));
-
-out:
- free(dir);
- free(buf);
-}
-
-static void
-tapdisk_channel_error(tapdisk_channel_t *channel, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- __tapdisk_channel_error(channel, fmt, ap);
- va_end(ap);
-}
-
-static void
-tapdisk_channel_fatal(tapdisk_channel_t *channel, const char *fmt, ...)
-{
- va_list ap;
-
- tapdisk_channel_enter_vbd_state(channel, TAPDISK_VBD_BROKEN);
-
- va_start(ap, fmt);
- __tapdisk_channel_error(channel, fmt, ap);
- va_end(ap);
-}
-
-static int
-tapdisk_channel_connect_backdev(tapdisk_channel_t *channel)
-{
- int err, major, minor;
- char *s, *path, *devname;
-
- s = NULL;
- path = NULL;
- devname = NULL;
-
- err = ioctl(channel->blktap_fd,
- BLKTAP_IOCTL_BACKDEV_SETUP, channel->minor);
- if (err) {
- err = -errno;
- goto fail;
- }
-
- err = asprintf(&path, "%s/backdev-node", channel->path);
- if (err == -1) {
- path = NULL;
- err = -ENOMEM;
- goto fail;
- }
-
- s = xs_read(channel->xsh, XBT_NULL, path, NULL);
- if (!s) {
- err = -errno;
- goto fail;
- }
-
- err = sscanf(s, "%d:%d", &major, &minor);
- if (err != 2) {
- err = -EINVAL;
- goto fail;
- }
-
- err = asprintf(&devname,"%s/%s%d",
- BLKTAP_DEV_DIR, BACKDEV_NAME, minor);
- if (err == -1) {
- devname = NULL;
- err = -ENOMEM;
- goto fail;
- }
-
- err = make_blktap_device(devname, major, minor, S_IFBLK | 0600);
- if (err)
- goto fail;
-
- free(path);
- err = asprintf(&path, "%s/backdev-path", channel->path);
- if (err == -1) {
- path = NULL;
- err = -ENOMEM;
- goto fail;
- }
-
- err = xs_write(channel->xsh, XBT_NULL, path, devname, strlen(devname));
- if (err == 0) {
- err = -errno;
- goto fail;
- }
-
- err = 0;
- out:
- free(devname);
- free(path);
- free(s);
- return err;
-
- fail:
- EPRINTF("backdev setup failed [%d]\n", err);
- goto out;
-}
-
-static int
-tapdisk_channel_complete_connection(tapdisk_channel_t *channel)
-{
- int err;
- char *path;
-
- if (!xs_printf(channel->xsh, channel->path,
- "tapdisk-pid", "%d", channel->tapdisk_pid)) {
- EPRINTF("ERROR: Failed writing tapdisk-pid");
- return -errno;
- }
-
- if (!xs_printf(channel->xsh, channel->path,
- "sectors", "%llu", channel->image.size)) {
- EPRINTF("ERROR: Failed writing sectors");
- return -errno;
- }
-
- if (!xs_printf(channel->xsh, channel->path,
- "sector-size", "%lu", channel->image.secsize)) {
- EPRINTF("ERROR: Failed writing sector-size");
- return -errno;
- }
-
- if (!xs_printf(channel->xsh, channel->path,
- "info", "%u", channel->image.info)) {
- EPRINTF("ERROR: Failed writing info");
- return -errno;
- }
-
- err = tapdisk_channel_connect_backdev(channel);
- if (err)
- goto clean;
-
- return 0;
-
- clean:
- if (asprintf(&path, "%s/info", channel->path) == -1)
- return err;
-
- if (!xs_rm(channel->xsh, XBT_NULL, path))
- goto clean_out;
-
- free(path);
- if (asprintf(&path, "%s/sector-size", channel->path) == -1)
- return err;
-
- if (!xs_rm(channel->xsh, XBT_NULL, path))
- goto clean_out;
-
- free(path);
- if (asprintf(&path, "%s/sectors", channel->path) == -1)
- return err;
-
- if (!xs_rm(channel->xsh, XBT_NULL, path))
- goto clean_out;
-
- free(path);
- if (asprintf(&path, "%s/tapdisk-pid", channel->path) == -1)
- return err;
-
- xs_rm(channel->xsh, XBT_NULL, path);
-
- clean_out:
- free(path);
- return err;
-}
-
-static int
-tapdisk_channel_send_open_request(tapdisk_channel_t *channel)
-{
- int len;
- tapdisk_message_t message;
-
- memset(&message, 0, sizeof(tapdisk_message_t));
-
- message.type = TAPDISK_MESSAGE_OPEN;
- message.cookie = channel->cookie;
- message.u.params.storage = channel->storage;
- message.u.params.devnum = channel->minor;
- message.u.params.domid = channel->domid;
- snprintf(message.u.params.path, sizeof(message.u.params.path),
- "%s:%s", channel->vdi_type, channel->vdi_path);
-
- if (channel->mode == 'r')
- message.u.params.flags |= TAPDISK_MESSAGE_FLAG_RDONLY;
- if (channel->shared)
- message.u.params.flags |= TAPDISK_MESSAGE_FLAG_SHARED;
-
- /* TODO: clean this up */
- if (xs_exists(channel->xsh, "/local/domain/0/tapdisk/add-cache"))
- message.u.params.flags |= TAPDISK_MESSAGE_FLAG_ADD_CACHE;
- if (xs_exists(channel->xsh, "/local/domain/0/tapdisk/vhd-index"))
- message.u.params.flags |= TAPDISK_MESSAGE_FLAG_VHD_INDEX;
- if (xs_exists(channel->xsh, "/local/domain/0/tapdisk/log-dirty"))
- message.u.params.flags |= TAPDISK_MESSAGE_FLAG_LOG_DIRTY;
-
- return tapdisk_channel_send_message(channel, &message, 2);
-}
-
-static int
-tapdisk_channel_receive_open_response(tapdisk_channel_t *channel,
- tapdisk_message_t *message)
-{
- int err;
-
- channel->state = TAPDISK_CHANNEL_RUNNING;
-
- channel->image.size = message->u.image.sectors;
- channel->image.secsize = message->u.image.sector_size;
- channel->image.info = message->u.image.info;
-
- err = tapdisk_channel_complete_connection(channel);
- if (err) {
- tapdisk_channel_fatal(channel,
- "failure completing connection: %d", err);
- return err;
- }
-
- return 0;
-}
-
-static int
-tapdisk_channel_send_shutdown_request(tapdisk_channel_t *channel)
-{
- tapdisk_message_t message;
-
- memset(&message, 0, sizeof(tapdisk_message_t));
-
- message.type = TAPDISK_MESSAGE_CLOSE;
- message.cookie = channel->cookie;
-
- return tapdisk_channel_send_message(channel, &message, 2);
-}
-
-static int
-tapdisk_channel_send_force_shutdown_request(tapdisk_channel_t *channel)
-{
- tapdisk_message_t message;
-
- memset(&message, 0, sizeof(tapdisk_message_t));
-
- message.type = TAPDISK_MESSAGE_FORCE_SHUTDOWN;
- message.cookie = channel->cookie;
-
- return tapdisk_channel_send_message(channel, &message, 2);
-}
-
-
-static int
-tapdisk_channel_receive_shutdown_response(tapdisk_channel_t *channel,
- tapdisk_message_t *message)
-{
- channel->state = TAPDISK_CHANNEL_CLOSED;
- tapdisk_channel_close_tapdisk(channel);
- return 0;
-}
-
-static int
-tapdisk_channel_receive_runtime_error(tapdisk_channel_t *channel,
- tapdisk_message_t *message)
-{
- tapdisk_channel_error(channel,
- "runtime error: %s", message->u.string.text);
- return 0;
-}
-
-static int
-tapdisk_channel_send_pid_request(tapdisk_channel_t *channel)
-{
- int err;
- tapdisk_message_t message;
-
- memset(&message, 0, sizeof(tapdisk_message_t));
-
- message.type = TAPDISK_MESSAGE_PID;
- message.cookie = channel->cookie;
-
- err = tapdisk_channel_send_message(channel, &message, 2);
-
- return err;
-}
-
-static int
-tapdisk_channel_receive_pid_response(tapdisk_channel_t *channel,
- tapdisk_message_t *message)
-{
- int err;
-
- channel->state = TAPDISK_CHANNEL_PID;
- channel->tapdisk_pid = message->u.tapdisk_pid;
- DPRINTF("%s: tapdisk pid: %d\n", channel->path, channel->tapdisk_pid);
-
- err = setpriority(PRIO_PROCESS, channel->tapdisk_pid, PRIO_SPECIAL_IO);
- if (err) {
- tapdisk_channel_fatal(channel,
- "setting tapdisk priority: %d", err);
- return err;
- }
-
- return 0;
-}
-
-static int
-tapdisk_channel_send_pause_request(tapdisk_channel_t *channel)
-{
- tapdisk_message_t message;
-
- memset(&message, 0, sizeof(tapdisk_message_t));
-
- DPRINTF("pausing %s\n", channel->path);
-
- message.type = TAPDISK_MESSAGE_PAUSE;
- message.cookie = channel->cookie;
-
- return tapdisk_channel_send_message(channel, &message, 2);
-}
-
-static int
-tapdisk_channel_write_atomic(tapdisk_channel_t *channel,
- const char *_path, const void *_data,
- unsigned int _len)
-{
- xs_transaction_t xbt;
- int err, abort;
- unsigned int len;
- void *data;
- bool ok;
-
-again:
- err = 0;
-
- xbt = xs_transaction_start(channel->xsh);
- if (!xbt) {
- err = -errno;
- EPRINTF("error starting transaction: %d\n", err);
- return err;
- }
-
- abort = 1;
-
- err = __tapdisk_channel_check_uuid(channel, xbt);
- if (err) {
- if (err == -ENOENT)
- goto abort;
- EPRINTF("error reading %s: %d\n", channel->path, err);
- goto abort;
- }
-
- ok = xs_write(channel->xsh, xbt, _path, _data, _len);
- if (!ok) {
- err = -errno;
- EPRINTF("error writing %s: %d\n", _path, err);
- goto abort;
- }
-
- abort = 0;
-
-abort:
- ok = xs_transaction_end(channel->xsh, xbt, abort);
- if (!ok) {
- err = -errno;
- if (err == -EAGAIN && !abort)
- goto again;
- EPRINTF("error ending transaction: %d\n", err);
- }
-
- return err;
-}
-
-static int
-tapdisk_channel_trigger_reprobe(tapdisk_channel_t *channel)
-{
- int err;
-
- /*
- * NB. Kick the probe watch, paranoia-style. Performing an
- * atomic test/set on the directory path. Abort if it's
- * already gone again. Accidentally recreating the node would
- * lead to a spurious start failure.
- */
-
- err = tapdisk_channel_write_atomic(channel, channel->path, "", 0);
- if (err && err != -ENOENT)
- EPRINTF("error writing %s: %d\n", channel->pause_done_str, err);
-
- DPRINTF("write %s: %d\n", channel->path, err);
- return err;
-}
-
-static int
-tapdisk_channel_signal_paused(tapdisk_channel_t *channel)
-{
- bool ok;
- int err;
-
- err = tapdisk_channel_write_atomic(channel,
- channel->pause_done_str, "", 0);
- if (err && errno != -ENOENT)
- EPRINTF("error writing %s: %d\n", channel->pause_done_str, err);
-
- DPRINTF("write %s: %d\n", channel->pause_done_str, err);
- return err;
-}
-
-static int
-tapdisk_channel_signal_unpaused(tapdisk_channel_t *channel)
-{
- bool ok;
- int err;
-
- ok = xs_rm(channel->xsh, XBT_NULL, channel->pause_done_str);
- err = ok ? 0 : -errno;
- if (err && err != -ENOENT)
- EPRINTF("error removing %s: %d\n", channel->pause_done_str, err);
-
- DPRINTF("clear %s: %d\n", channel->pause_done_str, err);
- return err;
-}
-
-static int
-tapdisk_channel_receive_pause_response(tapdisk_channel_t *channel,
- tapdisk_message_t *message)
-{
- channel->state = TAPDISK_CHANNEL_PAUSED;
- return 0;
-}
-
-static int
-tapdisk_channel_send_resume_request(tapdisk_channel_t *channel)
-{
- int len;
- tapdisk_message_t message;
-
- memset(&message, 0, sizeof(tapdisk_message_t));
-
- len = strlen(channel->vdi_path);
-
- DPRINTF("resuming %s\n", channel->path);
-
- message.type = TAPDISK_MESSAGE_RESUME;
- message.cookie = channel->cookie;
- snprintf(message.u.params.path, sizeof(message.u.params.path),
- "%s:%s", channel->vdi_type, channel->vdi_path);
-
- return tapdisk_channel_send_message(channel, &message, 2);
-}
-
-static int
-tapdisk_channel_receive_resume_response(tapdisk_channel_t *channel,
- tapdisk_message_t *message)
-{
- channel->state = TAPDISK_CHANNEL_RUNNING;
- return 0;
-}
-
-static int
-tapdisk_channel_check_start_request(tapdisk_channel_t *channel)
-{
- char *s;
- int err;
-
- err = 0;
-
- s = xs_read(channel->xsh, XBT_NULL, channel->start_str, NULL);
- if (!s) {
- if (errno == ENOENT)
- goto down;
-
- err = -errno;
- EPRINTF("error reading %s: %d\n", channel->path, err);
- goto out;
- }
-
- if (!strcmp(s, "start")) {
- channel->shutdown_state = TAPDISK_VBD_UP;
- channel->shutdown_force = 0;
- goto out;
-
- } else if (!strcmp(s, "shutdown-force")) {
- channel->shutdown_state = TAPDISK_VBD_DOWN;
- channel->shutdown_force = 1;
- goto out;
-
- } else if (strcmp(s, "shutdown-normal")) {
- EPRINTF("%s: invalid request '%s'", channel->path, s);
- err = -EINVAL;
- goto out;
- }
-
-down:
- channel->shutdown_state = TAPDISK_VBD_DOWN;
- channel->shutdown_force = 0;
-out:
- DPRINTF("%s: got tapdisk-request '%s', shutdown state %s (%s): %d\n",
- channel->path, s,
- tapdisk_channel_shutdown_state_name(channel->shutdown_state),
- channel->shutdown_force ? "force" : "normal", err);
- free(s);
- return err;
-}
-
-static void
-tapdisk_channel_shutdown_event(struct xs_handle *xsh,
- struct xenbus_watch *watch, const char *path)
-{
- tapdisk_channel_t *channel;
- int err;
-
- channel = watch->data;
-
- DPRINTF("%s: got start/shutdown watch on %s\n",
- channel->path, path);
-
- err = tapdisk_channel_validate_watch(channel, path);
- if (err) {
- if (err == -EINVAL)
- tapdisk_channel_fatal(channel,
- "bad shutdown watch");
- goto out;
- }
-
- err = tapdisk_channel_check_start_request(channel);
- if (err)
- tapdisk_channel_error(channel,
- "shutdown event failed: %d", err);
- else
- tapdisk_channel_drive_vbd_state(channel);
-
-out:
- DPRINTF("%s: handled start/shutdown watch on %s\n",
- channel->path, path);
-}
-
-static int
-tapdisk_channel_drive_paused(tapdisk_channel_t *channel)
-{
- int err;
-
- switch (channel->state) {
- case TAPDISK_CHANNEL_WAIT_PID:
- case TAPDISK_CHANNEL_WAIT_OPEN:
- case TAPDISK_CHANNEL_WAIT_PAUSE:
- case TAPDISK_CHANNEL_WAIT_RESUME:
- case TAPDISK_CHANNEL_WAIT_CLOSE:
- return -EAGAIN;
-
- case TAPDISK_CHANNEL_PID:
- case TAPDISK_CHANNEL_PAUSED:
- case TAPDISK_CHANNEL_CLOSED:
- case TAPDISK_CHANNEL_DEAD:
- return 0;
-
- case TAPDISK_CHANNEL_RUNNING:
- err = tapdisk_channel_send_pause_request(channel);
- if (err)
- goto fail_msg;
- return -EAGAIN;
-
- default:
- EPRINTF("%s: invalid channel state %d\n",
- __func__, channel->state);
- return -EINVAL;
- }
-
-fail_msg:
- tapdisk_channel_fatal(channel, "sending message: %d", err);
- return -EIO;
-}
-
-static int
-tapdisk_channel_drive_shutdown(tapdisk_channel_t *channel)
-{
- int err;
-
- switch (channel->state) {
-
- case TAPDISK_CHANNEL_DEAD:
- return 0;
-
- case TAPDISK_CHANNEL_CLOSED:
- if (channel->shared)
- return 0;
- /* let's duely wait for a clean exit */
- return -EAGAIN;
-
- case TAPDISK_CHANNEL_LAUNCHED:
- case TAPDISK_CHANNEL_WAIT_PID:
- case TAPDISK_CHANNEL_WAIT_OPEN:
- case TAPDISK_CHANNEL_WAIT_PAUSE:
- case TAPDISK_CHANNEL_WAIT_RESUME:
- case TAPDISK_CHANNEL_WAIT_CLOSE:
- return -EAGAIN;
-
- case TAPDISK_CHANNEL_PID:
- case TAPDISK_CHANNEL_RUNNING:
- case TAPDISK_CHANNEL_PAUSED:
- if (channel->shutdown_force)
- err = tapdisk_channel_send_force_shutdown_request(channel);
- else
- err = tapdisk_channel_send_shutdown_request(channel);
- if (err)
- goto fail_msg;
- return -EAGAIN;
-
- default:
- EPRINTF("%s: invalid channel state %d\n",
- __func__, channel->state);
- return -EINVAL;
- }
-
-fail_msg:
- tapdisk_channel_fatal(channel, "sending message: %d", err);
- return -EIO;
-}
-
-static int
-tapdisk_channel_drive_running(tapdisk_channel_t *channel)
-{
- int err;
-
- switch (channel->state) {
- case TAPDISK_CHANNEL_DEAD:
- case TAPDISK_CHANNEL_CLOSED:
- err = tapdisk_channel_connect(channel);
- if (err) {
- tapdisk_channel_fatal(channel, "failed connect: %d", err);
- return err;
- }
- return -EAGAIN;
-
- case TAPDISK_CHANNEL_LAUNCHED:
- case TAPDISK_CHANNEL_WAIT_PID:
- case TAPDISK_CHANNEL_WAIT_OPEN:
- case TAPDISK_CHANNEL_WAIT_PAUSE:
- case TAPDISK_CHANNEL_WAIT_RESUME:
- case TAPDISK_CHANNEL_WAIT_CLOSE:
- return -EAGAIN;
-
- case TAPDISK_CHANNEL_PID:
- err = tapdisk_channel_send_open_request(channel);
- if (err)
- goto fail_msg;
- return -EAGAIN;
-
- case TAPDISK_CHANNEL_RUNNING:
- return 0;
-
- case TAPDISK_CHANNEL_PAUSED:
- err = tapdisk_channel_send_resume_request(channel);
- if (err)
- goto fail_msg;
- return -EAGAIN;
-
- default:
- EPRINTF("%s: invalid channel state %d\n",
- __func__, channel->state);
- return -EINVAL;
- }
-
-fail_msg:
- tapdisk_channel_fatal(channel, "sending message: %d", err);
- return -EIO;
-}
-
-static channel_state_t
-tapdisk_channel_map_vbd_state(tapdisk_channel_t *channel)
-{
- channel_state_t next;
-
- switch (channel->shutdown_state) {
- case TAPDISK_VBD_DOWN:
- return TAPDISK_CHANNEL_CLOSED;
-
- case TAPDISK_VBD_UP:
- switch (channel->vbd_state) {
- case TAPDISK_VBD_UNPAUSED:
- return TAPDISK_CHANNEL_RUNNING;
-
- case TAPDISK_VBD_PAUSING:
- case TAPDISK_VBD_PAUSED:
- return TAPDISK_CHANNEL_PAUSED;
-
- case TAPDISK_VBD_BROKEN:
- case TAPDISK_VBD_DEAD:
- case TAPDISK_VBD_RECYCLED:
- return TAPDISK_CHANNEL_CLOSED;
-
- default:
- EPRINTF("%s: invalid vbd state %d\n",
- __func__, channel->vbd_state);
- return -EINVAL;
- }
- break;
- default:
- EPRINTF("%s: invalid shutdown state %d\n",
- __func__, channel->shutdown_state);
- return -EINVAL;
- }
-}
-
-void
-tapdisk_channel_drive_vbd_state(tapdisk_channel_t *channel)
-{
- channel_state_t next;
-
- next = tapdisk_channel_map_vbd_state(channel);
- DPRINTF("driving channel state %s, vbd %s, %s to %s (%d)\n",
- tapdisk_channel_state_name(channel->state),
- tapdisk_channel_shutdown_state_name(channel->shutdown_state),
- tapdisk_channel_vbd_state_name(channel->vbd_state),
- tapdisk_channel_state_name(next), next);
- if (next < 0)
- return;
-
- if (channel->state != next) {
- int err = 0;
-
- switch (next) {
- case TAPDISK_CHANNEL_RUNNING:
- err = tapdisk_channel_drive_running(channel);
- break;
- case TAPDISK_CHANNEL_PAUSED:
- err = tapdisk_channel_drive_paused(channel);
- break;
- case TAPDISK_CHANNEL_CLOSED:
- err = tapdisk_channel_drive_shutdown(channel);
- break;
- default:
- EPRINTF("%s: invalid target state %d\n", __func__, next);
- err = -EINVAL;
- break;
- }
- if (err)
- /* -EAGAIN: not there yet */
- return;
- }
-
- switch (channel->vbd_state) {
- case TAPDISK_VBD_UNPAUSED:
- case TAPDISK_VBD_PAUSED:
- case TAPDISK_VBD_BROKEN:
- break;
-
- case TAPDISK_VBD_PAUSING:
- tapdisk_channel_enter_vbd_state(channel, TAPDISK_VBD_PAUSED);
- tapdisk_channel_signal_paused(channel);
- break;
-
- case TAPDISK_VBD_RECYCLED:
- tapdisk_channel_trigger_reprobe(channel);
- /* then destroy */
- case TAPDISK_VBD_DEAD:
- tapdisk_channel_destroy(channel);
- }
-}
-
-static int
-tapdisk_channel_check_pause_request(tapdisk_channel_t *channel)
-{
- int pause, err = 0;
-
- pause = xs_exists(channel->xsh, channel->pause_str);
- if (pause)
- tapdisk_channel_enter_vbd_state(channel, TAPDISK_VBD_PAUSING);
- else {
- err = tapdisk_channel_refresh_params(channel);
- if (!err)
- err = tapdisk_channel_enter_vbd_state(channel, TAPDISK_VBD_UNPAUSED);
- if (!err)
- err = tapdisk_channel_signal_unpaused(channel);
- }
-
- return err;
-}
-
-static void
-tapdisk_channel_pause_event(struct xs_handle *xsh,
- struct xenbus_watch *watch, const char *path)
-{
- int err, count;
- tapdisk_channel_t *channel;
-
- channel = watch->data;
-
- DPRINTF("%s: got pause watch on %s\n",
- channel->path, path);
-
- err = tapdisk_channel_validate_watch(channel, path);
- if (err) {
- if (err == -EINVAL)
- tapdisk_channel_fatal(channel,
- "bad pause watch");
- goto out;
- }
-
- err = tapdisk_channel_check_pause_request(channel);
- if (err)
- tapdisk_channel_error(channel,
- "pause event failed: %d", err);
- else
- tapdisk_channel_drive_vbd_state(channel);
-
-out:
- DPRINTF("%s: handled pause watch on %s\n",
- channel->path, path);
-}
-
-static int
-tapdisk_channel_open_control_socket(char *devname)
-{
- int err, fd;
- fd_set socks;
- struct timeval timeout;
-
- err = mkdir(BLKTAP_CTRL_DIR, 0755);
- if (err == -1 && errno != EEXIST) {
- EPRINTF("Failure creating %s directory: %d\n",
- BLKTAP_CTRL_DIR, errno);
- return -errno;
- }
-
- err = mkfifo(devname, S_IRWXU | S_IRWXG | S_IRWXO);
- if (err) {
- if (errno == EEXIST) {
- /*
- * Remove fifo since it may have data from
- * it's previous use --- earlier invocation
- * of tapdisk may not have read all messages.
- */
- err = unlink(devname);
- if (err) {
- EPRINTF("ERROR: unlink(%s) failed (%d)\n",
- devname, errno);
- return -errno;
- }
-
- err = mkfifo(devname, S_IRWXU | S_IRWXG | S_IRWXO);
- }
-
- if (err) {
- EPRINTF("ERROR: pipe failed (%d)\n", errno);
- return -errno;
- }
- }
-
- fd = open(devname, O_RDWR | O_NONBLOCK);
- if (fd == -1) {
- EPRINTF("Failed to open %s\n", devname);
- return -errno;
- }
-
- return fd;
-}
-
-static int
-tapdisk_channel_get_device_number(tapdisk_channel_t *channel)
-{
- char *devname;
- domid_translate_t tr;
- int major, minor, err;
-
- tr.domid = channel->domid;
- tr.busid = channel->busid;
-
- minor = ioctl(channel->blktap_fd, BLKTAP_IOCTL_NEWINTF, tr);
- if (minor <= 0) {
- EPRINTF("invalid dev id: %d\n", minor);
- return -EINVAL;
- }
-
- if (minor > MAX_TAP_DEV) {
- EPRINTF("dev id %d exceeds maximum devices (%d)\n",
- minor, MAX_TAP_DEV);
- return -EINVAL;
- }
-
- major = ioctl(channel->blktap_fd, BLKTAP_IOCTL_MAJOR, minor);
- if (major < 0) {
- EPRINTF("invalid major id: %d\n", major);
- return -EINVAL;
- }
-
- err = asprintf(&devname, "%s/%s%d",
- BLKTAP_DEV_DIR, BLKTAP_DEV_NAME, minor);
- if (err == -1) {
- EPRINTF("get_new_dev: malloc failed\n");
- return -ENOMEM;
- }
-
- err = make_blktap_device(devname, major, minor, S_IFCHR | 0600);
- free(devname);
-
- if (err)
- return err;
-
- DPRINTF("Received device id %d and major %d, "
- "sent domid %d and be_id %d\n",
- minor, major, tr.domid, tr.busid);
-
- channel->major = major;
- channel->minor = minor;
-
- return 0;
-}
-
-static int
-tapdisk_channel_start_process(tapdisk_channel_t *channel,
- char *write_dev, char *read_dev)
-{
- pid_t child;
- char opt_facility[32];
- char *argv[] = { "tapdisk", opt_facility, write_dev, read_dev, NULL };
- const char *tapdisk;
- int i;
-
- if ((child = fork()) == -1)
- return -errno;
-
- if (child)
- return child;
-
- for (i = 0; i < sysconf(_SC_OPEN_MAX) ; i++)
- if (i != STDIN_FILENO &&
- i != STDOUT_FILENO &&
- i != STDERR_FILENO)
- close(i);
-
- snprintf(opt_facility, sizeof(opt_facility),
- "-l%d", tapdisk_daemon_log_facility);
-
- tapdisk = getenv("TAPDISK");
- if (!tapdisk)
- tapdisk = argv[0];
-
- execvp(tapdisk, argv);
-
- PERROR("execvp");
- _exit(1);
-}
-
-static void
-tapdisk_channel_close_tapdisk(tapdisk_channel_t *channel)
-{
- if (channel->read_fd >= 0) {
- close(channel->read_fd);
- channel->read_fd = -1;
- }
-
- if (channel->write_fd >= 0) {
- close(channel->write_fd);
- channel->write_fd = -1;
- }
-}
-
-static int
-tapdisk_channel_launch_tapdisk(tapdisk_channel_t *channel)
-{
- int err;
- char *read_dev, *write_dev;
-
- read_dev = NULL;
- write_dev = NULL;
-
- err = tapdisk_channel_get_device_number(channel);
- if (err)
- return err;
-
- err = asprintf(&write_dev,
- "%s/tapctrlwrite%d", BLKTAP_CTRL_DIR, channel->minor);
- if (err == -1) {
- err = -ENOMEM;
- write_dev = NULL;
- goto fail;
- }
-
- err = asprintf(&read_dev,
- "%s/tapctrlread%d", BLKTAP_CTRL_DIR, channel->minor);
- if (err == -1) {
- err = -ENOMEM;
- read_dev = NULL;
- goto fail;
- }
-
- channel->write_fd = tapdisk_channel_open_control_socket(write_dev);
- if (channel->write_fd < 0) {
- err = channel->write_fd;
- channel->write_fd = -1;
- goto fail;
- }
-
- channel->read_fd = tapdisk_channel_open_control_socket(read_dev);
- if (channel->read_fd < 0) {
- err = channel->read_fd;
- channel->read_fd = -1;
- goto fail;
- }
-
- channel->tapdisk_pid =
- tapdisk_channel_start_process(channel, write_dev, read_dev);
- if (channel->tapdisk_pid < 0) {
- err = channel->tapdisk_pid;
- channel->tapdisk_pid = -1;
- goto fail;
- }
-
- channel->channel_id = channel->write_fd;
-
- free(read_dev);
- free(write_dev);
-
- DPRINTF("process launched, channel = %d:%d\n",
- channel->channel_id, channel->cookie);
-
- channel->state = TAPDISK_CHANNEL_LAUNCHED;
- return tapdisk_channel_send_pid_request(channel);
-
-fail:
- free(read_dev);
- free(write_dev);
- tapdisk_channel_close_tapdisk(channel);
- return err;
-}
-
-static int
-tapdisk_channel_connect(tapdisk_channel_t *channel)
-{
- int err;
-
- tapdisk_daemon_maybe_clone_channel(channel);
- if (channel->tapdisk_pid)
- channel->state = TAPDISK_CHANNEL_PID;
- else
- return tapdisk_channel_launch_tapdisk(channel);
-
- DPRINTF("%s: process exists: %d, channel = %d:%d\n",
- channel->path, channel->tapdisk_pid,
- channel->channel_id, channel->cookie);
-
- err = tapdisk_channel_get_device_number(channel);
- if (err)
- return err;
-
- return tapdisk_channel_send_pid_request(channel);
-}
-
-static void
-tapdisk_channel_uninit(tapdisk_channel_t *channel)
-{
- free(channel->uuid_str);
- channel->uuid_str = NULL;
-
- free(channel->start_str);
- channel->start_str = NULL;
-
- free(channel->pause_str);
- channel->pause_str = NULL;
-
- free(channel->pause_done_str);
- channel->pause_done_str = NULL;
-
- channel->share_tapdisk_str = NULL;
-}
-
-static int
-tapdisk_channel_init(tapdisk_channel_t *channel)
-{
- int err;
-
- channel->uuid_str = NULL;
- channel->pause_str = NULL;
- channel->pause_done_str = NULL;
- channel->start_str = NULL;
- channel->share_tapdisk_str = NULL;
-
- err = asprintf(&channel->uuid_str,
- "%s/tapdisk-uuid", channel->path);
- if (err == -1) {
- channel->uuid_str = NULL;
- goto fail;
- }
-
- err = asprintf(&channel->start_str,
- "%s/tapdisk-request", channel->path);
- if (err == -1) {
- channel->start_str = NULL;
- goto fail;
- }
-
- err = asprintf(&channel->pause_str, "%s/pause", channel->path);
- if (err == -1) {
- channel->pause_str = NULL;
- goto fail;
- }
-
- err = asprintf(&channel->pause_done_str,
- "%s/pause-done", channel->path);
- if (err == -1) {
- channel->pause_done_str = NULL;
- goto fail;
- }
-
- channel->share_tapdisk_str = "/local/domain/0/tapdisk/share-tapdisks";
-
- return 0;
-
-fail:
- tapdisk_channel_uninit(channel);
- return -ENOMEM;
-}
-
-static void
-tapdisk_channel_clear_watches(tapdisk_channel_t *channel)
-{
- if (channel->start_watch.node) {
- unregister_xenbus_watch(channel->xsh, &channel->start_watch);
- channel->start_watch.node = NULL;
- }
-
- if (channel->pause_watch.node) {
- unregister_xenbus_watch(channel->xsh, &channel->pause_watch);
- channel->pause_watch.node = NULL;
- }
-}
-
-static int
-tapdisk_channel_set_watches(tapdisk_channel_t *channel)
-{
- int err;
-
- /* watch for start/shutdown events */
- channel->start_watch.node = channel->start_str;
- channel->start_watch.callback = tapdisk_channel_shutdown_event;
- channel->start_watch.data = channel;
- err = register_xenbus_watch(channel->xsh, &channel->start_watch);
- if (err) {
- channel->start_watch.node = NULL;
- goto fail;
- }
-
- /* watch for pause events */
- channel->pause_watch.node = channel->pause_str;
- channel->pause_watch.callback = tapdisk_channel_pause_event;
- channel->pause_watch.data = channel;
- err = register_xenbus_watch(channel->xsh, &channel->pause_watch);
- if (err) {
- channel->pause_watch.node = NULL;
- goto fail;
- }
-
- return 0;
-
-fail:
- tapdisk_channel_clear_watches(channel);
- return err;
-}
-
-static void
-tapdisk_channel_get_storage_type(tapdisk_channel_t *channel)
-{
- int err, type;
- unsigned int len;
- char *path, *stype;
-
- channel->storage = TAPDISK_STORAGE_TYPE_DEFAULT;
-
- err = asprintf(&path, "%s/sm-data/storage-type", channel->path);
- if (err == -1)
- return;
-
- stype = xs_read(channel->xsh, XBT_NULL, path, &len);
- if (!stype)
- goto out;
- else if (!strcmp(stype, "nfs"))
- channel->storage = TAPDISK_STORAGE_TYPE_NFS;
- else if (!strcmp(stype, "ext"))
- channel->storage = TAPDISK_STORAGE_TYPE_EXT;
- else if (!strcmp(stype, "lvm"))
- channel->storage = TAPDISK_STORAGE_TYPE_LVM;
-
-out:
- free(path);
- free(stype);
-}
-
-
-static int
-tapdisk_channel_parse_params(tapdisk_channel_t *channel)
-{
- char *vdi_type_path;
- char *ptr, *path;
- size_t len;
- int err;
-
- path = channel->params;
-
- ptr = strchr(path, ':');
- if (!ptr)
- goto fail;
-
- channel->vdi_path = ptr + 1;
- channel->vdi_type = strndup(path, ptr - path);
-
- err = asprintf(&vdi_type_path, "%s/sm-data/vdi-type", channel->path);
- if (err == -1)
- goto fail;
-
- if (xs_exists(channel->xsh, vdi_type_path)) {
- free(channel->vdi_type);
-
- channel->vdi_type =
- xs_read(channel->xsh, XBT_NULL, vdi_type_path, &len);
- free(vdi_type_path);
-
- if (!channel->vdi_type)
- goto fail;
- }
-
- len = strlen(channel->vdi_type);
- len += strlen(":");
- len += strlen(channel->vdi_path);
-
- if (len + 1 >= TAPDISK_MESSAGE_MAX_PATH_LENGTH)
- goto fail;
-
- return 0;
-
-fail:
- EPRINTF("%s: invalid blktap params: %s\n",
- channel->path, channel->params);
- channel->vdi_path = NULL;
- channel->vdi_type = NULL;
- return -EINVAL;
-}
-
-
-static void
-tapdisk_channel_release_info(tapdisk_channel_t *channel)
-{
- free(channel->params);
- channel->params = NULL;
-
- free(channel->frontpath);
- channel->frontpath = NULL;
-}
-
-static int
-tapdisk_channel_gather_info(tapdisk_channel_t *channel)
-{
- int err;
-
- err = xs_gather(channel->xsh, channel->path,
- "frontend", NULL, &channel->frontpath,
- "params", NULL, &channel->params,
- "mode", "%c", &channel->mode, NULL);
- if (err) {
- EPRINTF("could not find device info: %d\n", err);
- goto fail;
- }
-
- err = tapdisk_channel_parse_params(channel);
- if (err)
- goto fail;
-
- tapdisk_channel_get_storage_type(channel);
-
- return 0;
-
-fail:
- tapdisk_channel_release_info(channel);
- return err;
-}
-
-static int
-tapdisk_channel_refresh_params(tapdisk_channel_t *channel)
-{
- int err;
-
- free(channel->params);
- channel->params = NULL;
- channel->vdi_path = NULL;
-
- err = xs_gather(channel->xsh, channel->path,
- "params", NULL, &channel->params, NULL);
- if (err) {
- EPRINTF("failure re-reading params: %d\n", err);
- channel->params = NULL;
- return err;
- }
-
- return tapdisk_channel_parse_params(channel);
-}
-
-static void
-tapdisk_channel_destroy(tapdisk_channel_t *channel)
-{
- DPRINTF("destroying channel %d:%d, state %s\n",
- channel->channel_id, channel->cookie,
- tapdisk_channel_state_name(channel->state));
-
- tapdisk_channel_clear_watches(channel);
- tapdisk_daemon_close_channel(channel);
- tapdisk_channel_release_info(channel);
- tapdisk_channel_uninit(channel);
- free(channel->path);
- free(channel);
-}
-
-int
-tapdisk_channel_open(tapdisk_channel_t **_channel,
- const char *path, struct xs_handle *xsh,
- int blktap_fd, uint16_t cookie,
- int domid, int busid)
-{
- int err;
- char *msg;
- tapdisk_channel_t *channel;
-
- msg = NULL;
- *_channel = NULL;
-
- channel = calloc(1, sizeof(tapdisk_channel_t));
- if (!channel)
- return -ENOMEM;
-
- channel->xsh = xsh;
- channel->blktap_fd = blktap_fd;
- channel->cookie = cookie;
- channel->domid = domid;
- channel->busid = busid;
- channel->state = TAPDISK_CHANNEL_DEAD;
- channel->read_fd = -1;
- channel->write_fd = -1;
-
- INIT_LIST_HEAD(&channel->list);
-
- channel->path = strdup(path);
- if (!channel->path) {
- err = -ENOMEM;
- goto fail;
- }
-
- err = tapdisk_channel_init(channel);
- if (err) {
- msg = "allocating device";
- goto fail;
- }
-
- err = tapdisk_channel_check_uuid(channel);
- if (err) {
- msg = "checking uuid";
- goto fail;
- }
-
- err = tapdisk_channel_gather_info(channel);
- if (err) {
- msg = "gathering parameters";
- goto fail;
- }
-
- err = tapdisk_channel_set_watches(channel);
- if (err) {
- msg = "registering xenstore watches";
- goto fail;
- }
-
- err = tapdisk_channel_check_start_request(channel);
- if (err && err != -ENOENT) {
- msg = "initializing shutdown state";
- goto fail;
- }
-
- err = tapdisk_channel_check_pause_request(channel);
- if (err) {
- msg = "initializing pause state";
- goto fail;
- }
-
- *_channel = channel;
- return 0;
-
-fail:
- tapdisk_channel_fatal(channel, "%s: %d", (msg ? : "failure"), err);
- return err;
-}
-
-void
-tapdisk_channel_reap(tapdisk_channel_t *channel, int status)
-{
- const char *chn_state, *vbd_state, *krn_state;
-
- chn_state = tapdisk_channel_state_name(channel->state);
- vbd_state = tapdisk_channel_vbd_state_name(channel->vbd_state);
- krn_state = tapdisk_channel_shutdown_state_name(channel->shutdown_state);
-
- DPRINTF("reaping tapdisk, status %x, channel state %s, vbd %s, %s\n",
- status, chn_state, vbd_state, krn_state);
-
- if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
- tapdisk_channel_fatal(channel,
- "tapdisk died with status %d",
- WEXITSTATUS(status));
- } else if (WIFSIGNALED(status)) {
- tapdisk_channel_fatal(channel,
- "tapdisk killed by signal %d",
- WTERMSIG(status));
- }
-
- tapdisk_channel_close_tapdisk(channel);
- channel->state = TAPDISK_CHANNEL_DEAD;
-
- /* NB. we're in VBD_BROKEN state if we didn't exit properly,
- implicitly avoiding an unwanted restart */
- tapdisk_channel_drive_vbd_state(channel);
-}
-
-int
-tapdisk_channel_receive_message(tapdisk_channel_t *c, tapdisk_message_t *m)
-{
- int err;
-
- err = tapdisk_channel_validate_message(c, m);
- if (err)
- goto fail;
-
- switch (m->type) {
- case TAPDISK_MESSAGE_PID_RSP:
- err = tapdisk_channel_receive_pid_response(c, m);
- break;
-
- case TAPDISK_MESSAGE_OPEN_RSP:
- err = tapdisk_channel_receive_open_response(c, m);
- break;
-
- case TAPDISK_MESSAGE_PAUSE_RSP:
- err = tapdisk_channel_receive_pause_response(c, m);
- break;
-
- case TAPDISK_MESSAGE_RESUME_RSP:
- err = tapdisk_channel_receive_resume_response(c, m);
- break;
-
- case TAPDISK_MESSAGE_CLOSE_RSP:
- err = tapdisk_channel_receive_shutdown_response(c, m);
- break;
-
- case TAPDISK_MESSAGE_RUNTIME_ERROR:
- err = tapdisk_channel_receive_runtime_error(c, m);
- break;
-
- default:
- fail:
- tapdisk_channel_fatal(c, "received unexpected message %s in state %d",
- tapdisk_message_name(m->type), c->state);
- return -EINVAL;
- }
-
- tapdisk_channel_drive_vbd_state(c);
- return 0;
-}
+++ /dev/null
-/*
- * Copyright (c) 2008 Xensource Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation; or, when distributed
- * separately from the Linux kernel or incorporated into other
- * software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <getopt.h>
-#define SYSLOG_NAMES
-#include <syslog.h>
-
-#include <xs.h>
-#include "tapdisk-dispatch.h"
-
-#define TAPDISK_DAEMON_DOMID_WATCH "domid-watch"
-#define TAPDISK_DAEMON_PIDFILE "/var/run/blktapctrl.pid"
-
-typedef struct tapdisk_daemon {
- char *node;
- int blktap_fd;
- uint16_t cookie;
-
- struct xs_handle *xsh;
- struct list_head channels;
- int n_channels;
- struct xenbus_watch watch;
-
- sigset_t sigunmask;
-} tapdisk_daemon_t;
-
-static tapdisk_daemon_t tapdisk_daemon;
-int tapdisk_daemon_log_facility;
-
-#define tapdisk_daemon_for_each_channel(c, tmp) \
- list_for_each_entry_safe(c, tmp, &tapdisk_daemon.channels, list)
-
-#define MAX(a, b) ((a) >= (b) ? (a) : (b))
-
-static void
-tapdisk_daemon_print_drivers(void)
-{
- int i, size;
-
- DPRINTF("blktap-daemon: v1.0.2\n");
- DPRINTF("Syslog facility %d\n", tapdisk_daemon_log_facility);
-}
-
-static int
-tapdisk_daemon_write_pidfile(long pid)
-{
- char buf[100];
- int len, fd, flags, err;
-
- fd = open(TAPDISK_DAEMON_PIDFILE, O_RDWR | O_CREAT, 0600);
- if (fd == -1) {
- EPRINTF("Opening pid file failed (%d)\n", errno);
- return -errno;
- }
-
- /* We exit silently if daemon already running */
- err = lockf(fd, F_TLOCK, 0);
- if (err == -1)
- exit(0);
-
- /* Set FD_CLOEXEC, so that tapdisk doesn't get this file descriptor */
- flags = fcntl(fd, F_GETFD);
- if (flags == -1) {
- EPRINTF("F_GETFD failed (%d)\n", errno);
- return -errno;
- }
-
- flags |= FD_CLOEXEC;
- err = fcntl(fd, F_SETFD, flags);
- if (err == -1) {
- EPRINTF("F_SETFD failed (%d)\n", errno);
- return -errno;
- }
-
- len = sprintf(buf, "%ld\n", pid);
- err = write(fd, buf, len);
- if (err != len) {
- EPRINTF("Writing pid file failed (%d)\n", errno);
- return -errno;
- }
-
- return 0;
-}
-
-static void
-tapdisk_daemon_sa_none(int signo)
-{
- /* only take a syscall restart */
-}
-
-static int
-tapdisk_daemon_init(void)
-{
- char *devname;
- int i, err, blktap_major;
- sigset_t mask;
-
- memset(&tapdisk_daemon, 0, sizeof(tapdisk_daemon_t));
-
- err = asprintf(&devname, "%s/%s0", BLKTAP_DEV_DIR, BLKTAP_DEV_NAME);
- if (err == -1) {
- devname = NULL;
- err = -ENOMEM;
- goto fail;
- }
-
- err = xc_find_device_number("blktap0");
- if (err < 0)
- goto fail;
-
- blktap_major = major(err);
- err = make_blktap_device(devname, blktap_major, 0, S_IFCHR | 0600);
- if (err)
- goto fail;
-
- tapdisk_daemon.blktap_fd = open(devname, O_RDWR);
- if (tapdisk_daemon.blktap_fd == -1) {
- err = -errno;
- EPRINTF("blktap0 open failed\n");
- goto fail;
- }
-
- /*
- * Spoil any opportunity for set/check races by forcing
- * children to later serialize their demise into the event
- * loop.
- *
- * NB. It's no coincidence we're blocking those signals right
- * here. XS watches spawn threads [*shiver*]. The new mask is
- * heritage.
- */
- sigemptyset(&mask);
-
- sigaddset(&mask, SIGCHLD);
- signal(SIGCHLD, tapdisk_daemon_sa_none);
-
- sigprocmask(SIG_BLOCK, &mask, &tapdisk_daemon.sigunmask);
-
- for (i = 0; i < 2; i++) {
- tapdisk_daemon.xsh = xs_daemon_open();
- if (!tapdisk_daemon.xsh) {
- EPRINTF("xs_daemon_open failed -- is xenstore running?\n");
- sleep(2);
- } else
- break;
- }
-
- if (!tapdisk_daemon.xsh) {
- err = -ENOSYS;
- goto fail;
- }
-
- fcntl(xs_fileno(tapdisk_daemon.xsh), F_SETFD, O_NONBLOCK);
-
- INIT_LIST_HEAD(&tapdisk_daemon.channels);
-
- free(devname);
- return 0;
-
-fail:
- if (tapdisk_daemon.blktap_fd > 0)
- close(tapdisk_daemon.blktap_fd);
- free(devname);
- memset(&tapdisk_daemon, 0, sizeof(tapdisk_daemon_t));
- EPRINTF("%s: %d\n", __func__, err);
-
- return err;
-}
-
-static int
-tapdisk_daemon_set_node(void)
-{
- int err;
- char *domid;
-
- domid = get_dom_domid(tapdisk_daemon.xsh);
- if (!domid)
- return -EAGAIN;
-
- err = asprintf(&tapdisk_daemon.node,
- "/local/domain/%s/backend/tap", domid);
- if (err == -1) {
- tapdisk_daemon.node = NULL;
- err = -ENOMEM;
- goto out;
- }
-
- err = 0;
-
-out:
- free(domid);
- return err;
-}
-
-static int
-tapdisk_daemon_get_domid(void)
-{
- int err;
- unsigned int num;
- char **res, *node, *token, *domid;
-
- res = xs_read_watch(tapdisk_daemon.xsh, &num);
- if (!res)
- return -EAGAIN;
-
- err = 0;
- node = res[XS_WATCH_PATH];
- token = res[XS_WATCH_TOKEN];
-
- if (strcmp(token, TAPDISK_DAEMON_DOMID_WATCH)) {
- err = -EINVAL;
- goto out;
- }
-
- err = tapdisk_daemon_set_node();
-
-out:
- free(res);
- return err;
-}
-
-static int
-tapdisk_daemon_wait_for_domid(void)
-{
- int err;
- char *domid;
- fd_set readfds;
-
- err = tapdisk_daemon_set_node();
- if (!err)
- return 0;
-
- if (!xs_watch(tapdisk_daemon.xsh, "/local/domain",
- TAPDISK_DAEMON_DOMID_WATCH)) {
- EPRINTF("unable to set domain id watch\n");
- return -EINVAL;
- }
-
- do {
- FD_ZERO(&readfds);
- FD_SET(xs_fileno(tapdisk_daemon.xsh), &readfds);
-
- select(xs_fileno(tapdisk_daemon.xsh) + 1,
- &readfds, NULL, NULL, NULL);
-
- if (FD_ISSET(xs_fileno(tapdisk_daemon.xsh), &readfds))
- err = tapdisk_daemon_get_domid();
- else
- err = -EAGAIN;
- } while (err == -EAGAIN);
-
- xs_unwatch(tapdisk_daemon.xsh,
- "/local/domain", TAPDISK_DAEMON_DOMID_WATCH);
- return err;
-}
-
-static int
-tapdisk_daemon_write_uuid(const char *path, uint32_t uuid)
-{
- int err;
- char *cpath, uuid_str[12];
-
- snprintf(uuid_str, sizeof(uuid_str), "%u", uuid);
-
- err = asprintf(&cpath, "%s/tapdisk-uuid", path);
- if (err == -1)
- return -ENOMEM;
-
- err = xs_write(tapdisk_daemon.xsh, XBT_NULL,
- cpath, uuid_str, strlen(uuid_str));
- free(cpath);
-
- return (err ? 0 : -errno);
-}
-
-static tapdisk_channel_t*
-tapdisk_daemon_find_channel(int domid, int busid)
-{
- tapdisk_channel_t *channel, *next;
-
- tapdisk_daemon_for_each_channel(channel, next)
- if (channel->domid == domid &&
- channel->busid == busid)
- return channel;
-
- return NULL;
-}
-
-static void
-tapdisk_daemon_probe_vbd(int domid, int busid, const char *path)
-{
- tapdisk_channel_t *channel;
- uint32_t cookie;
- int err;
-
- channel = tapdisk_daemon_find_channel(domid, busid);
- if (channel) {
- err = tapdisk_channel_check_uuid(channel);
- if (err == -ENOENT) {
- /* NB. Fast unplug/plug and we missed the path
- removal. Typically a dom0 phenonmenon */
- DPRINTF("%s: pending re-probe: uuid %d, state %d\n",
- path, channel->cookie, channel->vbd_state);
- channel->vbd_state = TAPDISK_VBD_RECYCLED;
- tapdisk_channel_drive_vbd_state(channel);
- return;
- }
-
- DPRINTF("%s: ignoring duplicate probe event:"
- " uuid %d, state %d\n",
- path, channel->cookie, channel->vbd_state);
- return;
- }
-
- cookie = tapdisk_daemon.cookie++;
- err = tapdisk_daemon_write_uuid(path, cookie);
- if (err)
- return;
-
- if (tapdisk_daemon.n_channels >= TAPDISK_DAEMON_MAX_CHANNELS) {
- err = -EMFILE;
- goto fail;
- }
-
- DPRINTF("%s: creating channel, uuid %u\n", path, cookie);
-
- err = tapdisk_channel_open(&channel, path,
- tapdisk_daemon.xsh,
- tapdisk_daemon.blktap_fd,
- cookie, domid, busid);
- if (err)
- goto fail;
-
- list_add(&channel->list, &tapdisk_daemon.channels);
- tapdisk_daemon.n_channels++;
- return;
-
-fail:
- EPRINTF("failed to open tapdisk channel for %s: %d\n", path, err);
-}
-
-static void
-tapdisk_daemon_remove_vbd(int domid, int busid, const char *path)
-{
- tapdisk_channel_t *channel;
-
- channel = tapdisk_daemon_find_channel(domid, busid);
- if (!channel) {
- DPRINTF("%s: ignoring remove event:"
- " no channel.\n",
- path);
- return;
- }
-
- DPRINTF("%s: marking channel dead, uuid %u\n", path, channel->cookie);
-
- channel->vbd_state = TAPDISK_VBD_DEAD;
- tapdisk_channel_drive_vbd_state(channel);
-}
-
-static void
-tapdisk_daemon_node_event(struct xs_handle *xsh,
- struct xenbus_watch *watch, const char *path)
-{
- int count, domid, busid, offset;
- char slash;
-
- count = sscanf(path, "/local/domain/%*d/backend/tap/%d/%d%c",
- &domid, &busid, &slash);
-
- if (count == 2) {
- const char *action;
- int exists;
-
- exists = xs_exists(xsh, path);
- action = exists ? "probe" : "remove";
-
- DPRINTF("got %s watch on %s\n", action, path);
-
- if (exists)
- tapdisk_daemon_probe_vbd(domid, busid, path);
- else
- tapdisk_daemon_remove_vbd(domid, busid, path);
-
- DPRINTF("handled %s watch on %s\n", action, path);
- }
-}
-
-static int
-tapdisk_daemon_start(void)
-{
- int err;
-
- err = tapdisk_daemon_wait_for_domid();
- if (err)
- return err;
-
- tapdisk_daemon.watch.node = tapdisk_daemon.node;
- tapdisk_daemon.watch.callback = tapdisk_daemon_node_event;
-
- err = register_xenbus_watch(tapdisk_daemon.xsh, &tapdisk_daemon.watch);
- if (err)
- goto fail;
-
- ioctl(tapdisk_daemon.blktap_fd,
- BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_INTERPOSE);
- ioctl(tapdisk_daemon.blktap_fd, BLKTAP_IOCTL_SENDPID, getpid());
-
- return 0;
-
-fail:
- free(tapdisk_daemon.node);
- tapdisk_daemon.node = NULL;
- tapdisk_daemon.watch.node = NULL;
- EPRINTF("%s: %d\n", __func__, err);
- return err;
-}
-
-static int
-tapdisk_daemon_stop(void)
-{
- unregister_xenbus_watch(tapdisk_daemon.xsh, &tapdisk_daemon.watch);
-
- ioctl(tapdisk_daemon.blktap_fd,
- BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_PASSTHROUGH);
- close(tapdisk_daemon.blktap_fd);
-
- return 0;
-}
-
-static void
-tapdisk_daemon_free(void)
-{
- free(tapdisk_daemon.node);
- xs_daemon_close(tapdisk_daemon.xsh);
- memset(&tapdisk_daemon, 0, sizeof(tapdisk_daemon_t));
-}
-
-static pid_t
-tapdisk_daemon_wait(int *_status)
-{
- tapdisk_channel_t *channel;
- pid_t pid;
- int status;
-
- pid = waitpid(-1, &status, WNOHANG);
- if (pid == 0)
- return -1; /* No state changes */
-
- if (pid < 0) {
- if (errno != ECHILD) /* No children */
- PERROR("waitpid");
- return -1;
- }
-
- *_status = status;
-
- if (WIFEXITED(status)) {
- DPRINTF("child %d exited with status %d", pid,
- WEXITSTATUS(status));
- return pid;
- }
-
- if (WIFSIGNALED(status)) {
- DPRINTF("child %d killed by signal %d", pid, WTERMSIG(status));
- return pid;
- }
-
- /* WIFSTOPPED? Oh well. */
- DPRINTF("ignoring child %d transition to state 0x%x.", pid, status);
-
- return 0;
-}
-
-static void
-tapdisk_daemon_reap_channels(void)
-{
- do {
- tapdisk_channel_t *channel, *next;
- pid_t pid;
- int status;
-
- pid = tapdisk_daemon_wait(&status);
- if (pid < 0)
- break;
-
- if (!pid)
- /* ignorable child state. */
- continue;
-
- tapdisk_daemon_for_each_channel(channel, next)
- if (channel->tapdisk_pid == pid)
- tapdisk_channel_reap(channel, status);
- } while (1);
-}
-
-static int
-tapdisk_daemon_read_message(int fd, tapdisk_message_t *message, int timeout)
-{
- fd_set readfds;
- struct timeval tv;
- int ret, len, offset;
-
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
- offset = 0;
- len = sizeof(tapdisk_message_t);
-
- memset(message, 0, sizeof(tapdisk_message_t));
-
- while (offset < len) {
- FD_ZERO(&readfds);
- FD_SET(fd, &readfds);
-
- /* we don't bother reinitializing tv. at worst, it will wait a
- * bit more time than expected. */
-
- ret = select(fd + 1, &readfds, NULL, NULL, &tv);
- 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;
- }
-
- return (offset == len ? 0 : -EIO);
-}
-
-static int
-tapdisk_daemon_receive_message(int fd)
-{
- int err;
- tapdisk_message_t m;
- tapdisk_channel_t *c, *tmp;
-
- err = tapdisk_daemon_read_message(fd, &m, 2);
- if (err) {
- EPRINTF("failed reading message on %d: %d\n", fd, err);
- return err;
- }
-
- tapdisk_daemon_for_each_channel(c, tmp)
- if (c->cookie == m.cookie && c->read_fd == fd) {
- DPRINTF("got '%s' message from %d:%d\n",
- tapdisk_message_name(m.type),
- c->channel_id, c->cookie);
-
- return tapdisk_channel_receive_message(c, &m);
- }
-
- EPRINTF("unrecognized message on %d: '%s' (uuid = %u)\n",
- fd, tapdisk_message_name(m.type), m.cookie);
-
- return -EINVAL;
-}
-
-static int
-tapdisk_daemon_set_fds(fd_set *readfds)
-{
- int max, fd;
- tapdisk_channel_t *channel, *tmp;
-
- max = xs_fileno(tapdisk_daemon.xsh);
-
- FD_ZERO(readfds);
- FD_SET(max, readfds);
-
- tapdisk_daemon_for_each_channel(channel, tmp) {
- if (!TAPDISK_CHANNEL_IPC_OPEN(channel))
- continue;
- fd = channel->read_fd;
- max = MAX(fd, max);
- FD_SET(fd, readfds);
- }
-
- return max;
-}
-
-static void
-tapdisk_daemon_check_fds(fd_set *readfds)
-{
- int err;
- tapdisk_channel_t *channel, *tmp;
-
- if (FD_ISSET(xs_fileno(tapdisk_daemon.xsh), readfds))
- xs_fire_next_watch(tapdisk_daemon.xsh);
-
- tapdisk_daemon_for_each_channel(channel, tmp) {
- if (!TAPDISK_CHANNEL_IPC_OPEN(channel))
- continue;
-
- if (FD_ISSET(channel->read_fd, readfds)) {
- tapdisk_daemon_receive_message(channel->read_fd);
- return;
- }
- }
-}
-
-static int
-tapdisk_daemon_run(void)
-{
- int nfds, max;
- fd_set readfds;
-
- while (1) {
- max = tapdisk_daemon_set_fds(&readfds);
-
- nfds = pselect(max + 1, &readfds, NULL, NULL, NULL,
- &tapdisk_daemon.sigunmask);
- if (nfds < 0) {
- if (errno != EINTR)
- PERROR("select");
- }
-
- if (nfds > 0)
- tapdisk_daemon_check_fds(&readfds);
-
- tapdisk_daemon_reap_channels();
- }
-
- return 0;
-}
-
-void
-tapdisk_daemon_maybe_clone_channel(tapdisk_channel_t *channel)
-{
- tapdisk_channel_t *c, *tmp;
-
- channel->tapdisk_pid = 0;
-
- /* do we want multiple vbds per tapdisk? */
- if (!xs_exists(tapdisk_daemon.xsh, channel->share_tapdisk_str)) {
- channel->shared = 0;
- return;
- }
-
- channel->shared = 1;
-
- /* check if we already have a process started */
- tapdisk_daemon_for_each_channel(c, tmp)
- if (!strcmp(c->vdi_type, channel->vdi_type)) {
- channel->write_fd = c->write_fd;
- channel->read_fd = c->read_fd;
- channel->channel_id = c->channel_id;
- channel->tapdisk_pid = c->tapdisk_pid;
- return;
- }
-}
-
-void
-tapdisk_daemon_close_channel(tapdisk_channel_t *channel)
-{
- tapdisk_channel_t *c, *tmp;
-
- list_del(&channel->list);
- tapdisk_daemon.n_channels--;
-
- tapdisk_daemon_for_each_channel(c, tmp)
- if (c->channel_id == channel->channel_id)
- return;
-
- close(channel->read_fd);
- close(channel->write_fd);
-}
-
-static void
-tapdisk_daemon_openlog(const char *ident, const char *facility_name)
-{
- static char buf[128];
- int facility;
-
- facility = LOG_DAEMON;
-
- if (facility_name) {
- char *endptr;
-
- facility = strtol(facility_name, &endptr, 0);
- if (*endptr != 0) {
- CODE *c;
-
- facility = LOG_DAEMON;
- for (c = facilitynames; c->c_name != NULL; ++c)
- if (!strcmp(c->c_name, facility_name))
- facility = c->c_val;
- }
- }
-
- snprintf(buf, sizeof(buf), "%s[%d]", ident, getpid());
- openlog(buf, LOG_CONS | LOG_ODELAY, facility);
- tapdisk_daemon_log_facility = facility;
-}
-
-static const char *program;
-
-static void
-usage(FILE *stream)
-{
- fprintf(stream, "Usage: %s [-h] [-l <syslog_facility>]\n", program);
-}
-
-int
-main(int argc, char *argv[])
-{
- int err, gcc;
- const char *facility;
-
- program = basename(argv[0]);
- facility = "daemon";
-
- do {
- char c;
-
- c = getopt(argc, argv, "hl:");
- if (c < 0)
- break;
-
- switch (c) {
- case 'h':
- usage(stdout);
- return 0;
- case 'l':
- facility = optarg;
- break;
- default:
- goto usage;
- }
- } while (1);
-
- gcc = daemon(0, 0);
-
-#define CORE_DUMP
-#if defined(CORE_DUMP)
-#include <sys/resource.h>
- {
- /* set up core-dumps*/
- struct rlimit rlim;
- rlim.rlim_cur = RLIM_INFINITY;
- rlim.rlim_max = RLIM_INFINITY;
- if (setrlimit(RLIMIT_CORE, &rlim) < 0)
- EPRINTF("setrlimit failed: %d\n", errno);
- }
-#endif
-
- tapdisk_daemon_openlog("BLKTAP-DAEMON", facility);
-
- err = tapdisk_daemon_write_pidfile(getpid());
- if (err)
- goto out;
-
- tapdisk_daemon_print_drivers();
-
- err = tapdisk_daemon_init();
- if (err)
- goto out;
-
- err = tapdisk_daemon_start();
- if (err) {
- EPRINTF("failed to start %s: %d\n", argv[0], err);
- goto out;
- }
-
- err = tapdisk_daemon_run();
-
- tapdisk_daemon_stop();
-
- tapdisk_daemon_free();
-
-
-out:
- closelog();
- return err ? 1 : 0;
-
-usage:
- usage(stderr);
- return EINVAL;
-
-}