DPRINTF("Received a poll for a new vbd\n");
if ( ((blk=blkif->info) != NULL) && (blk->params != NULL) ) {
- if (blktap_interface_create(ctlfd, &major, &minor, blkif) < 0)
- return -1;
-
if (test_path(blk->params, &ptr, &type, &exist, &use_ioemu) != 0) {
DPRINTF("Error in blktap device string(%s).\n",
blk->params);
blkif->fds[WRITE] = exist->fds[WRITE];
}
- add_disktype(blkif, type);
- blkif->major = major;
- blkif->minor = minor;
-
image = (image_t *)malloc(sizeof(image_t));
blkif->prv = (void *)image;
blkif->ops = &tapdisk_ops;
goto fail;
}
+ if (blktap_interface_create(ctlfd, &major, &minor, blkif) < 0)
+ return -1;
+
+ blkif->major = major;
+ blkif->minor = minor;
+
+ add_disktype(blkif, type);
+
} else return -1;
return 0;
fail:
- ioctl(ctlfd, BLKTAP_IOCTL_FREEINTF, minor);
return -EINVAL;
}
#include <poll.h>
#include <time.h>
#include <sys/time.h>
+#include <unistd.h>
#include "blktaplib.h"
#include "list.h"
#include "xs_api.h"
return 0;
}
+static int check_sharing(struct xs_handle *h, struct backend_info *be)
+{
+ char *dom_uuid;
+ char *cur_dom_uuid;
+ char *path;
+ char *mode;
+ char *params;
+ char **domains;
+ char **devices;
+ int i, j;
+ unsigned int num_dom, num_dev;
+ blkif_info_t *info;
+ int ret = 0;
+
+ /* If the mode contains '!' or doesn't contain 'w' don't check anything */
+ xs_gather(h, be->backpath, "mode", NULL, &mode, NULL);
+ if (strchr(mode, '!'))
+ goto out;
+ if (strchr(mode, 'w') == NULL)
+ goto out;
+
+ /* Get the UUID of the domain we want to attach to */
+ if (asprintf(&path, "/local/domain/%ld", be->frontend_id) == -1)
+ goto fail;
+ xs_gather(h, path, "vm", NULL, &dom_uuid, NULL);
+ free(path);
+
+ /* Iterate through the devices of all VMs */
+ domains = xs_directory(h, XBT_NULL, "backend/tap", &num_dom);
+ if (domains == NULL)
+ num_dom = 0;
+
+ for (i = 0; !ret && (i < num_dom); i++) {
+
+ /* If it's the same VM, no action needed */
+ if (asprintf(&path, "/local/domain/%s", domains[i]) == -1) {
+ ret = -1;
+ break;
+ }
+ xs_gather(h, path, "vm", NULL, &cur_dom_uuid, NULL);
+ free(path);
+
+ if (!strcmp(cur_dom_uuid, dom_uuid)) {
+ free(cur_dom_uuid);
+ continue;
+ }
+
+ /* Check the devices */
+ if (asprintf(&path, "backend/tap/%s", domains[i]) == -1) {
+ ret = -1;
+ free(cur_dom_uuid);
+ break;
+ }
+ devices = xs_directory(h, XBT_NULL, path, &num_dev);
+ if (devices == NULL)
+ num_dev = 0;
+ free(path);
+
+ for (j = 0; !ret && (j < num_dev); j++) {
+ if (asprintf(&path, "backend/tap/%s/%s", domains[i], devices[j]) == -1) {
+ ret = -1;
+ break;
+ }
+ xs_gather(h, path, "params", NULL, ¶ms, NULL);
+ free(path);
+
+ info = be->blkif->info;
+ if (strcmp(params, info->params)) {
+ ret = -1;
+ }
+
+ free(params);
+ }
+
+ free(cur_dom_uuid);
+ free(devices);
+ }
+ free(domains);
+ free(dom_uuid);
+ goto out;
+
+fail:
+ ret = -1;
+out:
+ free(mode);
+ return ret;
+}
+
+static int check_image(struct xs_handle *h, struct backend_info *be,
+ const char** errmsg)
+{
+ const char *tmp;
+ const char *path;
+ int mode;
+ blkif_t *blkif = be->blkif;
+ blkif_info_t *info = blkif->info;
+
+ /* Strip off the image type */
+ path = info->params;
+
+ if (!strncmp(path, "tapdisk:", strlen("tapdisk:"))) {
+ path += strlen("tapdisk:");
+ } else if (!strncmp(path, "ioemu:", strlen("ioemu:"))) {
+ path += strlen("ioemu:");
+ }
+
+ tmp = strchr(path, ':');
+ if (tmp != NULL)
+ path = tmp + 1;
+
+ /* Check if the image exists and access is permitted */
+ mode = R_OK;
+ if (!be->readonly)
+ mode |= W_OK;
+ if (access(path, mode)) {
+ if (errno == ENOENT)
+ *errmsg = "File not found.";
+ else
+ *errmsg = "Insufficient file permissions.";
+ return -1;
+ }
+
+ /* Check that the image is not attached to a different VM */
+ if (check_sharing(h, be)) {
+ *errmsg = "File already in use by other domain";
+ return -1;
+ }
+
+ return 0;
+}
+
static void ueblktap_setup(struct xs_handle *h, char *bepath)
{
struct backend_info *be;
int len, er, deverr;
long int pdev = 0, handle;
blkif_info_t *blk;
+ const char* errmsg = NULL;
be = be_lookup_be(bepath);
if (be == NULL)
be->pdev = pdev;
}
+ if (check_image(h, be, &errmsg))
+ goto fail;
+
er = blkif_init(be->blkif, handle, be->pdev, be->readonly);
if (er != 0) {
DPRINTF("Unable to open device %s\n",blk->params);
}
be->blkif->state = CONNECTED;
+ xs_printf(h, be->backpath, "hotplug-status", "connected");
+
DPRINTF("[SETUP] Complete\n\n");
goto close;
fail:
- if ( (be != NULL) && (be->blkif != NULL) )
+ if (be) {
+ if (errmsg == NULL)
+ errmsg = "Setting up the backend failed. See the log "
+ "files in /var/log/xen/ for details.";
+ xs_printf(h, be->backpath, "hotplug-error", errmsg);
+ xs_printf(h, be->backpath, "hotplug-status", "error");
+
backend_remove(h, be);
+ }
close:
if (path)
free(path);
len = strsep_len(bepath, '/', 7);
if (len < 0)
goto free_be;
- bepath[len] = '\0';
+ if (bepath[len] != '\0')
+ goto free_be;
be = malloc(sizeof(*be));
if (!be) {
+++ /dev/null
-#!/bin/bash
-
-# Copyright (c) 2005, XenSource Ltd.
-
-dir=$(dirname "$0")
-. "$dir/xen-hotplug-common.sh"
-. "$dir/block-common.sh"
-
-findCommand "$@"
-
-##
-# check_blktap_sharing file mode
-#
-# Perform the sharing check for the given blktap and mode.
-#
-check_blktap_sharing()
-{
- local file="$1"
- local mode="$2"
-
- local base_path="$XENBUS_BASE_PATH/$XENBUS_TYPE"
- for dom in $(xenstore-list "$base_path")
- do
- for dev in $(xenstore-list "$base_path/$dom")
- do
- params=$(xenstore_read "$base_path/$dom/$dev/params" | cut -d: -f2)
- if [ "$file" = "$params" ]
- then
-
- if [ "$mode" = 'w' ]
- then
- if ! same_vm "$dom"
- then
- echo 'guest'
- return
- fi
- else
- local m=$(xenstore_read "$base_path/$dom/$dev/mode")
- m=$(canonicalise_mode "$m")
-
- if [ "$m" = 'w' ]
- then
- if ! same_vm "$dom"
- then
- echo 'guest'
- return
- fi
- fi
- fi
- fi
- done
- done
-
- echo 'ok'
-}
-
-
-t=$(xenstore_read_default "$XENBUS_PATH/type" 'MISSING')
-if [ -n "$t" ]
-then
- p=$(xenstore_read "$XENBUS_PATH/params")
- # if we have a ':', chew from head including :
- if echo $p | grep -q \:
- then
- p=${p#*:}
- fi
-fi
-# some versions of readlink cannot be passed a regular file
-if [ -L "$p" ]; then
- file=$(readlink -f "$p") || fatal "$p link does not exist."
-else
- file="$p"
-fi
-
-if [ "$command" = 'add' ]
-then
- [ -e "$file" ] || { fatal $file does not exist; }
-
- FRONTEND_ID=$(xenstore_read "$XENBUS_PATH/frontend-id")
- FRONTEND_UUID=$(xenstore_read "/local/domain/$FRONTEND_ID/vm")
- mode=$(xenstore_read "$XENBUS_PATH/mode")
- mode=$(canonicalise_mode "$mode")
-
- if [ "$mode" != '!' ]
- then
- result=$(check_blktap_sharing "$file" "$mode")
- [ "$result" = 'ok' ] || ebusy "$file already in use by other domain"
- fi
-
- success
-fi
-
-exit 0