Files
xen/tools/blktap2/drivers/tapdisk-server.c
T
Keir Fraser 4b1af8b188 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>
2010-06-08 08:05:09 +01:00

346 lines
6.7 KiB
C

/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include "tapdisk-utils.h"
#include "tapdisk-server.h"
#include "tapdisk-driver.h"
#include "tapdisk-interface.h"
#define DBG(_level, _f, _a...) tlog_write(_level, _f, ##_a)
#define ERR(_err, _f, _a...) tlog_error(_err, _f, ##_a)
tapdisk_server_t server;
#define tapdisk_server_for_each_vbd(vbd, tmp) \
list_for_each_entry_safe(vbd, tmp, &server.vbds, next)
td_image_t *
tapdisk_server_get_shared_image(td_image_t *image)
{
td_vbd_t *vbd, *tmpv;
td_image_t *img, *tmpi;
if (!td_flag_test(image->flags, TD_OPEN_SHAREABLE))
return NULL;
tapdisk_server_for_each_vbd(vbd, tmpv)
tapdisk_vbd_for_each_image(vbd, img, tmpi)
if (img->type == image->type &&
!strcmp(img->name, image->name))
return img;
return NULL;
}
struct list_head *
tapdisk_server_get_all_vbds(void)
{
return &server.vbds;
}
td_vbd_t *
tapdisk_server_get_vbd(uint16_t uuid)
{
td_vbd_t *vbd, *tmp;
tapdisk_server_for_each_vbd(vbd, tmp)
if (vbd->uuid == uuid)
return vbd;
return NULL;
}
void
tapdisk_server_add_vbd(td_vbd_t *vbd)
{
list_add_tail(&vbd->next, &server.vbds);
}
void
tapdisk_server_remove_vbd(td_vbd_t *vbd)
{
list_del(&vbd->next);
INIT_LIST_HEAD(&vbd->next);
tapdisk_server_check_state();
}
void
tapdisk_server_queue_tiocb(struct tiocb *tiocb)
{
tapdisk_queue_tiocb(&server.aio_queue, tiocb);
}
void
tapdisk_server_debug(void)
{
td_vbd_t *vbd, *tmp;
tapdisk_debug_queue(&server.aio_queue);
tapdisk_server_for_each_vbd(vbd, tmp)
tapdisk_vbd_debug(vbd);
tlog_flush();
}
void
tapdisk_server_check_state(void)
{
if (list_empty(&server.vbds))
server.run = 0;
}
event_id_t
tapdisk_server_register_event(char mode, int fd,
int timeout, event_cb_t cb, void *data)
{
return scheduler_register_event(&server.scheduler,
mode, fd, timeout, cb, data);
}
void
tapdisk_server_unregister_event(event_id_t event)
{
return scheduler_unregister_event(&server.scheduler, event);
}
void
tapdisk_server_set_max_timeout(int seconds)
{
scheduler_set_max_timeout(&server.scheduler, seconds);
}
static void
tapdisk_server_assert_locks(void)
{
}
static void
tapdisk_server_set_retry_timeout(void)
{
td_vbd_t *vbd, *tmp;
tapdisk_server_for_each_vbd(vbd, tmp)
if (tapdisk_vbd_retry_needed(vbd)) {
tapdisk_server_set_max_timeout(TD_VBD_RETRY_INTERVAL);
return;
}
}
static void
tapdisk_server_check_progress(void)
{
struct timeval now;
td_vbd_t *vbd, *tmp;
gettimeofday(&now, NULL);
tapdisk_server_for_each_vbd(vbd, tmp)
tapdisk_vbd_check_progress(vbd);
}
static void
tapdisk_server_submit_tiocbs(void)
{
tapdisk_submit_all_tiocbs(&server.aio_queue);
}
static void
tapdisk_server_kick_responses(void)
{
int n;
td_vbd_t *vbd, *tmp;
tapdisk_server_for_each_vbd(vbd, tmp)
tapdisk_vbd_kick(vbd);
}
static void
tapdisk_server_check_vbds(void)
{
td_vbd_t *vbd, *tmp;
tapdisk_server_for_each_vbd(vbd, tmp)
tapdisk_vbd_check_state(vbd);
}
static void
tapdisk_server_stop_vbds(void)
{
td_vbd_t *vbd, *tmp;
tapdisk_server_for_each_vbd(vbd, tmp)
tapdisk_vbd_kill_queue(vbd);
}
static int
tapdisk_server_init_aio(void)
{
return tapdisk_init_queue(&server.aio_queue, TAPDISK_TIOCBS,
TIO_DRV_LIO, NULL);
}
static void
tapdisk_server_close_aio(void)
{
tapdisk_free_queue(&server.aio_queue);
}
static void
tapdisk_server_close(void)
{
tapdisk_server_close_aio();
}
void
tapdisk_server_iterate(void)
{
int ret;
tapdisk_server_assert_locks();
tapdisk_server_set_retry_timeout();
tapdisk_server_check_progress();
ret = scheduler_wait_for_events(&server.scheduler);
if (ret < 0)
DBG(TLOG_WARN, "server wait returned %d\n", ret);
tapdisk_server_check_vbds();
tapdisk_server_submit_tiocbs();
tapdisk_server_kick_responses();
}
static void
__tapdisk_server_run(void)
{
while (server.run)
tapdisk_server_iterate();
}
static void
tapdisk_server_signal_handler(int signal)
{
td_vbd_t *vbd, *tmp;
static int xfsz_error_sent = 0;
switch (signal) {
case SIGBUS:
case SIGINT:
tapdisk_server_for_each_vbd(vbd, tmp)
tapdisk_vbd_close(vbd);
break;
case SIGXFSZ:
ERR(EFBIG, "received SIGXFSZ");
tapdisk_server_stop_vbds();
if (xfsz_error_sent)
break;
xfsz_error_sent = 1;
break;
case SIGUSR1:
tapdisk_server_debug();
break;
}
}
int
tapdisk_server_init(void)
{
memset(&server, 0, sizeof(server));
INIT_LIST_HEAD(&server.vbds);
scheduler_initialize(&server.scheduler);
return 0;
}
int
tapdisk_server_complete(void)
{
int err;
err = tapdisk_server_init_aio();
if (err)
goto fail;
server.run = 1;
return 0;
fail:
tapdisk_server_close_aio();
return err;
}
int
tapdisk_server_initialize(void)
{
int err;
tapdisk_server_init();
err = tapdisk_server_complete();
if (err)
goto fail;
return 0;
fail:
tapdisk_server_close();
return err;
}
int
tapdisk_server_run()
{
int err;
err = tapdisk_set_resource_limits();
if (err)
return err;
signal(SIGBUS, tapdisk_server_signal_handler);
signal(SIGINT, tapdisk_server_signal_handler);
signal(SIGUSR1, tapdisk_server_signal_handler);
signal(SIGXFSZ, tapdisk_server_signal_handler);
__tapdisk_server_run();
tapdisk_server_close();
return 0;
}