libxenlight: implement cdrom insert/eject

This patch implements functions in libxenlight to change the cdrom in
a VM at run time and to handle cdrom eject requests from guests.

This patch adds two new commands to xl: cd-insert and cd-eject; it
also modifies xl to handle cdrom eject requests coming from guests
(actually coming from qemu).

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
This commit is contained in:
Keir Fraser committed 2009-12-08 07:47:52 +00:00
1 parent 4baca0b560
commit 7b4effff89
7 files changed
+406 -31

No files matched your search

+183 -11
View File
@@ -460,25 +460,80 @@ int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req)
return 0;
}
int libxl_wait_for_domain_death(struct libxl_ctx *ctx, uint32_t domid, int *fd)
int libxl_get_wait_fd(struct libxl_ctx *ctx, int *fd)
{
if (!xs_watch(ctx->xsh, "@releaseDomain", "domain_death"))
return -1;
*fd = xs_fileno(ctx->xsh);
return 0;
}
int libxl_is_domain_dead(struct libxl_ctx *ctx, uint32_t domid, xc_dominfo_t *info)
int libxl_wait_for_domain_death(struct libxl_ctx *ctx, uint32_t domid, libxl_waiter *waiter)
{
waiter->path = strdup("@releaseDomain");
asprintf(&(waiter->token), "%d", DOMAIN_DEATH);
if (!xs_watch(ctx->xsh, waiter->path, waiter->token))
return -1;
return 0;
}
int libxl_wait_for_disk_ejects(struct libxl_ctx *ctx, uint32_t guest_domid, libxl_device_disk *disks, int num_disks, libxl_waiter *waiter)
{
int i;
uint32_t domid = libxl_get_stubdom_id(ctx, guest_domid);
if (!domid)
domid = guest_domid;
for (i = 0; i < num_disks; i++) {
asprintf(&(waiter[i].path), "%s/device/vbd/%d/eject", libxl_xs_get_dompath(ctx, domid), device_disk_dev_number(disks[i].virtpath));
asprintf(&(waiter[i].token), "%d", DISK_EJECT);
xs_watch(ctx->xsh, waiter->path, waiter->token);
}
return 0;
}
int libxl_get_event(struct libxl_ctx *ctx, libxl_event *event)
{
unsigned int num;
char **events = xs_read_watch(ctx->xsh, &num);
if (num != 2) {
free(events);
return -1;
}
event->path = strdup(events[XS_WATCH_PATH]);
event->token = strdup(events[XS_WATCH_TOKEN]);
event->type = atoi(event->token);
free(events);
return 0;
}
int libxl_stop_waiting(struct libxl_ctx *ctx, libxl_waiter *waiter)
{
if (!xs_unwatch(ctx->xsh, waiter->path, waiter->token))
return -1;
else
return 0;
}
int libxl_free_event(libxl_event *event)
{
free(event->path);
free(event->token);
return 0;
}
int libxl_free_waiter(libxl_waiter *waiter)
{
free(waiter->path);
free(waiter->token);
return 0;
}
int libxl_event_get_domain_death_info(struct libxl_ctx *ctx, uint32_t domid, libxl_event *event, xc_dominfo_t *info)
{
int nb_domain, i, rc = 0;
char **vec = NULL;
xc_dominfo_t *list = NULL;
vec = xs_read_watch(ctx->xsh, &num);
if (!vec)
return 0;
if (!strcmp(vec[XS_WATCH_TOKEN], "domain_death")) {
if (event && event->type == DOMAIN_DEATH) {
list = libxl_domain_infolist(ctx, &nb_domain);
for (i = 0; i < nb_domain; i++) {
if (domid == list[i].domid) {
@@ -493,13 +548,41 @@ int libxl_is_domain_dead(struct libxl_ctx *ctx, uint32_t domid, xc_dominfo_t *in
rc = 1;
goto out;
}
out:
free(list);
free(vec);
return rc;
}
int libxl_event_get_disk_eject_info(struct libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_device_disk *disk)
{
if (event && event->type == DISK_EJECT) {
char *path;
char *backend;
char *value = libxl_xs_read(ctx, XBT_NULL, event->path);
if (!value || strcmp(value, "eject"))
return 0;
path = strdup(event->path);
path[strlen(path) - 6] = '\0';
backend = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend", path));
disk->backend_domid = 0;
disk->domid = domid;
disk->physpath = NULL;
disk->phystype = 0;
/* this value is returned to the user: do not free right away */
disk->virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev", backend));
disk->unpluggable = 1;
disk->readwrite = 0;
disk->is_cdrom = 1;
free(path);
return 1;
}
return 0;
}
static int libxl_destroy_device_model(struct libxl_ctx *ctx, uint32_t domid)
{
char *pid;
@@ -1421,6 +1504,95 @@ int libxl_device_vkb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
return ERROR_NI;
}
libxl_device_disk *libxl_device_disk_list(struct libxl_ctx *ctx, uint32_t domid, int *num)
{
char *be_path_tap, *be_path_vbd;
libxl_device_disk *disks = NULL;
char **l = NULL;
unsigned int numl;
int num_disks = 0, i;
char *type;
be_path_vbd = libxl_sprintf(ctx, "%s/backend/vbd/%d", libxl_xs_get_dompath(ctx, 0), domid);
be_path_tap = libxl_sprintf(ctx, "%s/backend/tap/%d", libxl_xs_get_dompath(ctx, 0), domid);
l = libxl_xs_directory(ctx, XBT_NULL, be_path_vbd, &numl);
if (l) {
num_disks += numl;
disks = realloc(disks, sizeof(libxl_device_disk) * num_disks);
for (i = 0; i < numl; i++) {
disks[i].backend_domid = 0;
disks[i].domid = domid;
disks[i].physpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/params", be_path_vbd, l[i]));
libxl_string_to_phystype(ctx, libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/type", be_path_vbd, l[i])), &(disks[i].phystype));
disks[i].virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/dev", be_path_vbd, l[i]));
disks[i].unpluggable = atoi(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/removable", be_path_vbd, l[i])));
if (!strcmp(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/mode", be_path_vbd, l[i])), "w"))
disks[i].readwrite = 1;
else
disks[i].readwrite = 0;
type = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/device-type", libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/frontend", be_path_vbd, l[i]))));
disks[i].is_cdrom = !strcmp(type, "cdrom");
}
free(l);
}
l = libxl_xs_directory(ctx, XBT_NULL, be_path_tap, &numl);
if (l) {
num_disks += numl;
disks = realloc(disks, sizeof(libxl_device_disk) * num_disks);
for (i = 0; i < numl; i++) {
disks[i].backend_domid = 0;
disks[i].domid = domid;
disks[i].physpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/params", be_path_tap, l[i]));
libxl_string_to_phystype(ctx, libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/type", be_path_tap, l[i])), &(disks[i].phystype));
disks[i].virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/dev", be_path_tap, l[i]));
disks[i].unpluggable = atoi(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/removable", be_path_tap, l[i])));
if (!strcmp(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/mode", be_path_tap, l[i])), "w"))
disks[i].readwrite = 1;
else
disks[i].readwrite = 0;
type = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/device-type", libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/frontend", be_path_vbd, l[i]))));
disks[i].is_cdrom = !strcmp(type, "cdrom");
}
free(l);
}
*num = num_disks;
return disks;
}
int libxl_cdrom_insert(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
{
int num, i;
uint32_t stubdomid;
libxl_device_disk *disks;
if (!disk->physpath) {
disk->physpath = "";
disk->phystype = PHYSTYPE_PHY;
}
disks = libxl_device_disk_list(ctx, domid, &num);
for (i = 0; i < num; i++) {
if (disks[i].is_cdrom && !strcmp(disk->virtpath, disks[i].virtpath))
/* found */
break;
}
if (i == num) {
XL_LOG(ctx, XL_LOG_ERROR, "Virtual device not found");
return -1;
}
libxl_device_disk_del(ctx, disks + i, 1);
libxl_device_disk_add(ctx, domid, disk);
stubdomid = libxl_get_stubdom_id(ctx, domid);
if (stubdomid) {
disk_info_domid_fixup(disks + i, stubdomid);
libxl_device_disk_del(ctx, disks + i, 1);
disk_info_domid_fixup(disk, stubdomid);
libxl_device_disk_add(ctx, stubdomid, disk);
disk_info_domid_fixup(disk, domid);
}
return 0;
}
/******************************************************************************/
static int libxl_build_xenpv_qemu_args(struct libxl_ctx *ctx,
libxl_device_vfb *vfb,
+36 -2
View File
@@ -267,8 +267,40 @@ int libxl_domain_resume(struct libxl_ctx *ctx, uint32_t domid);
int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req);
int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force);
int libxl_wait_for_domain_death(struct libxl_ctx *ctx, uint32_t domid, int *fd);
int libxl_is_domain_dead(struct libxl_ctx *ctx, uint32_t domid, xc_dominfo_t *info);
/* events handling */
typedef enum {
DOMAIN_DEATH,
DISK_EJECT,
} libxl_event_type;
typedef struct {
/* event type */
libxl_event_type type;
/* data for internal use of the library */
char *path;
char *token;
} libxl_event;
typedef struct {
char *path;
char *token;
} libxl_waiter;
int libxl_get_wait_fd(struct libxl_ctx *ctx, int *fd);
/* waiter is allocated by the caller */
int libxl_wait_for_domain_death(struct libxl_ctx *ctx, uint32_t domid, libxl_waiter *waiter);
/* waiter is a preallocated array of num_disks libxl_waiter elements */
int libxl_wait_for_disk_ejects(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disks, int num_disks, libxl_waiter *waiter);
int libxl_get_event(struct libxl_ctx *ctx, libxl_event *event);
int libxl_stop_waiting(struct libxl_ctx *ctx, libxl_waiter *waiter);
int libxl_free_event(libxl_event *event);
int libxl_free_waiter(libxl_waiter *waiter);
int libxl_event_get_domain_death_info(struct libxl_ctx *ctx, uint32_t domid, libxl_event *event, xc_dominfo_t *info);
int libxl_event_get_disk_eject_info(struct libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_device_disk *disk);
int libxl_domain_pause(struct libxl_ctx *ctx, uint32_t domid);
int libxl_domain_unpause(struct libxl_ctx *ctx, uint32_t domid);
@@ -299,6 +331,8 @@ int libxl_detach_device_model(struct libxl_ctx *ctx,
int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk);
int libxl_device_disk_del(struct libxl_ctx *ctx, libxl_device_disk *disk, int wait);
libxl_device_disk *libxl_device_disk_list(struct libxl_ctx *ctx, uint32_t domid, int *num);
int libxl_cdrom_insert(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk);
int libxl_device_nic_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic);
int libxl_device_nic_del(struct libxl_ctx *ctx, libxl_device_nic *nic, int wait);
+1 -1
View File
@@ -26,7 +26,7 @@
#include "libxl.h"
#include "libxl_internal.h"
char *string_of_kinds[] = {
const char *string_of_kinds[] = {
[DEVICE_VIF] = "vif",
[DEVICE_VBD] = "vbd",
[DEVICE_TAP] = "tap",
+2
View File
@@ -45,6 +45,8 @@ typedef enum {
DEVICE_CONSOLE,
} libxl_device_kinds;
extern const char *string_of_kinds[];
typedef struct {
uint32_t backend_devid;
uint32_t backend_domid;
+30
View File
@@ -214,3 +214,33 @@ int libxl_create_logfile(struct libxl_ctx *ctx, char *name, char **full_name)
return 0;
}
int libxl_string_to_phystype(struct libxl_ctx *ctx, char *s, libxl_disk_phystype *phystype)
{
char *p;
int rc = 0;
if (!strcmp(s, "phy")) {
*phystype = PHYSTYPE_PHY;
} else if (!strcmp(s, "file")) {
*phystype = PHYSTYPE_FILE;
} else if (!strcmp(s, "tap")) {
p = strchr(s, ':');
if (!p) {
rc = -1;
goto out;
}
p++;
if (!strcmp(p, "aio")) {
*phystype = PHYSTYPE_AIO;
} else if (!strcmp(p, "vhd")) {
*phystype = PHYSTYPE_VHD;
} else if (!strcmp(p, "qcow")) {
*phystype = PHYSTYPE_QCOW;
} else if (!strcmp(p, "qcow2")) {
*phystype = PHYSTYPE_QCOW2;
}
}
out:
return rc;
}
+1
View File
@@ -32,6 +32,7 @@ int libxl_param_to_domid(struct libxl_ctx *ctx, char *p, uint32_t *domid);
int libxl_get_stubdom_id(struct libxl_ctx *ctx, int guest_domid);
int libxl_is_stubdom(struct libxl_ctx *ctx, int domid);
int libxl_create_logfile(struct libxl_ctx *ctx, char *name, char **full_name);
int libxl_string_to_phystype(struct libxl_ctx *ctx, char *s, libxl_disk_phystype *phystype);
#endif
+153 -17
View File
@@ -356,12 +356,14 @@ static void parse_config_file(const char *filename,
if (p2 == NULL) {
(*disks)[*num_disks].virtpath = strdup(p);
(*disks)[*num_disks].is_cdrom = 0;
(*disks)[*num_disks].unpluggable = 1;
} else {
*p2 = '\0';
(*disks)[*num_disks].virtpath = strdup(p);
if (!strcmp(p2 + 1, "cdrom"))
if (!strcmp(p2 + 1, "cdrom")) {
(*disks)[*num_disks].is_cdrom = 1;
else
(*disks)[*num_disks].unpluggable = 1;
} else
(*disks)[*num_disks].is_cdrom = 0;
}
p = strtok(NULL, ",");
@@ -594,6 +596,7 @@ static void create_domain(int debug, const char *config_file, const char *restor
int i, fd;
int need_daemon = 1;
libxl_device_model_starting *dm_starting = 0;
libxl_waiter *w1 = NULL, *w2 = NULL;
memset(&dm_info, 0x00, sizeof(dm_info));
printf("Parsing config file %s\n", config_file);
@@ -671,12 +674,17 @@ start:
need_daemon = 0;
}
XL_LOG(&ctx, XL_LOG_DEBUG, "Waiting for domain %s (domid %d) to die", info1.name, domid);
libxl_wait_for_domain_death(&ctx, domid, &fd);
w1 = (libxl_waiter*) malloc(sizeof(libxl_waiter) * num_disks);
w2 = (libxl_waiter*) malloc(sizeof(libxl_waiter));
libxl_wait_for_disk_ejects(&ctx, domid, disks, num_disks, w1);
libxl_wait_for_domain_death(&ctx, domid, w2);
libxl_get_wait_fd(&ctx, &fd);
while (1) {
int ret;
fd_set rfds;
xc_dominfo_t info;
libxl_event event;
libxl_device_disk disk;
memset(&info, 0x00, sizeof(xc_dominfo_t));
FD_ZERO(&rfds);
@@ -685,21 +693,35 @@ start:
ret = select(fd + 1, &rfds, NULL, NULL, NULL);
if (!ret)
continue;
if (libxl_is_domain_dead(&ctx, domid, &info)) {
XL_LOG(&ctx, XL_LOG_DEBUG, "Domain %d is dead", domid);
if (info.crashed || info.dying || (info.shutdown && (info.shutdown_reason != SHUTDOWN_suspend))) {
XL_LOG(&ctx, XL_LOG_DEBUG, "Domain %d needs to be clean: destroying the domain", domid);
libxl_domain_destroy(&ctx, domid, 0);
if (info.shutdown && (info.shutdown_reason == SHUTDOWN_reboot)) {
libxl_ctx_free(&ctx);
XL_LOG(&ctx, XL_LOG_DEBUG, "Done. Rebooting now");
goto start;
libxl_get_event(&ctx, &event);
switch (event.type) {
case DOMAIN_DEATH:
if (libxl_event_get_domain_death_info(&ctx, domid, &event, &info)) {
XL_LOG(&ctx, XL_LOG_DEBUG, "Domain %d is dead", domid);
if (info.crashed || info.dying || (info.shutdown && (info.shutdown_reason != SHUTDOWN_suspend))) {
XL_LOG(&ctx, XL_LOG_DEBUG, "Domain %d needs to be clean: destroying the domain", domid);
libxl_domain_destroy(&ctx, domid, 0);
if (info.shutdown && (info.shutdown_reason == SHUTDOWN_reboot)) {
libxl_free_waiter(w1);
libxl_free_waiter(w2);
free(w1);
free(w2);
libxl_ctx_free(&ctx);
XL_LOG(&ctx, XL_LOG_DEBUG, "Done. Rebooting now");
goto start;
}
XL_LOG(&ctx, XL_LOG_DEBUG, "Done. Exiting now");
}
XL_LOG(&ctx, XL_LOG_DEBUG, "Domain %d does not need to be clean, exiting now", domid);
exit(0);
}
XL_LOG(&ctx, XL_LOG_DEBUG, "Done. Exiting now");
}
XL_LOG(&ctx, XL_LOG_DEBUG, "Domain %d does not need to be clean, exiting now", domid);
exit(0);
break;
case DISK_EJECT:
if (libxl_event_get_disk_eject_info(&ctx, domid, &event, &disk))
libxl_cdrom_insert(&ctx, domid, &disk);
break;
}
libxl_free_event(&event);
}
close(logfile);
@@ -730,6 +752,8 @@ static void help(char *command)
printf(" console attach to domain's console\n\n");
printf(" save save a domain state to restore later\n\n");
printf(" restore restore a domain from a saved state\n\n");
printf(" cd-insert insert a cdrom into a guest's cd drive\n\n");
printf(" cd-eject eject a cdrom from a guest's cd drive\n\n");
} else if(!strcmp(command, "create")) {
printf("Usage: xl create <ConfigFile> [options] [vars]\n\n");
printf("Create a domain based on <ConfigFile>.\n\n");
@@ -772,6 +796,12 @@ static void help(char *command)
} else if (!strcmp(command, "console")) {
printf("Usage: xl console <Domain>\n\n");
printf("Attach to domain's console.\n\n");
} else if (!strcmp(command, "cd-insert")) {
printf("Usage: xl cd-insert <Domain> <VirtualDevice> <type:path>\n\n");
printf("Insert a cdrom into a guest's cd drive.\n\n");
} else if (!strcmp(command, "cd-eject")) {
printf("Usage: xl cd-eject <Domain> <VirtualDevice>\n\n");
printf("Eject a cdrom from a guest's cd drive.\n\n");
}
}
@@ -790,6 +820,108 @@ void console(char *p, int cons_num)
libxl_console_attach(&ctx, domid, cons_num);
}
void cd_insert(char *dom, char *virtdev, char *phys)
{
struct libxl_ctx ctx;
uint32_t domid;
libxl_device_disk disk;
char *p;
libxl_ctx_init(&ctx);
libxl_ctx_set_log(&ctx, log_callback, NULL);
if (libxl_param_to_domid(&ctx, dom, &domid) < 0) {
fprintf(stderr, "%s is an invalid domain identifier\n", dom);
exit(2);
}
disk.backend_domid = 0;
disk.domid = domid;
if (phys) {
p = strchr(phys, ':');
if (!p) {
fprintf(stderr, "No type specified, ");
disk.physpath = phys;
if (!strncmp(phys, "/dev", 4)) {
fprintf(stderr, "assuming phy:\n");
disk.phystype = PHYSTYPE_PHY;
} else {
fprintf(stderr, "assuming file:\n");
disk.phystype = PHYSTYPE_FILE;
}
} else {
p = '\0';
disk.physpath = strdup(p);
p++;
libxl_string_to_phystype(&ctx, p, &disk.phystype);
}
} else {
disk.physpath = NULL;
disk.phystype = 0;
}
disk.virtpath = virtdev;
disk.unpluggable = 1;
disk.readwrite = 0;
disk.is_cdrom = 1;
libxl_cdrom_insert(&ctx, domid, &disk);
}
int main_cd_eject(int argc, char **argv)
{
int opt = 0;
char *p = NULL, *virtdev;
while ((opt = getopt(argc, argv, "hn:")) != -1) {
switch (opt) {
case 'h':
help("cd-eject");
exit(0);
default:
fprintf(stderr, "option not supported\n");
break;
}
}
if (optind >= argc - 1) {
help("cd-eject");
exit(2);
}
p = argv[optind];
virtdev = argv[optind + 1];
cd_insert(p, virtdev, NULL);
exit(0);
}
int main_cd_insert(int argc, char **argv)
{
int opt = 0;
char *p = NULL, *file = NULL, *virtdev;
while ((opt = getopt(argc, argv, "hn:")) != -1) {
switch (opt) {
case 'h':
help("cd-insert");
exit(0);
default:
fprintf(stderr, "option not supported\n");
break;
}
}
if (optind >= argc - 2) {
help("cd-insert");
exit(2);
}
p = argv[optind];
virtdev = argv[optind + 1];
file = argv[optind + 2];
cd_insert(p, virtdev, file);
exit(0);
}
int main_console(int argc, char **argv)
{
int opt = 0, cons_num = 0;
@@ -1298,6 +1430,10 @@ int main(int argc, char **argv)
main_save(argc - 1, argv + 1);
} else if (!strcmp(argv[1], "restore")) {
main_restore(argc - 1, argv + 1);
} else if (!strcmp(argv[1], "cd-insert")) {
main_cd_insert(argc - 1, argv + 1);
} else if (!strcmp(argv[1], "cd-eject")) {
main_cd_eject(argc - 1, argv + 1);
} else if (!strcmp(argv[1], "help")) {
if (argc > 2)
help(argv[2]);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.