mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
appliance: Add support for virtio-scsi.
This requires febootstrap >= 3.15.
This commit is contained in:
3
README
3
README
@@ -55,11 +55,12 @@ For basic functionality and the C tools:
|
||||
to make complex changes to the ./configure command line to get it
|
||||
to work if you don't have virtio)
|
||||
|
||||
- febootstrap >= 3.3 (it is best to use the latest version)
|
||||
- febootstrap >= 3.15
|
||||
|
||||
Notes: (1) febootstrap 2.x WILL NOT WORK
|
||||
(2) febootstrap 3.x is distro-independent, and is required on
|
||||
Debian and other distros as well as Fedora
|
||||
(3) that is the minimum version, but later versions are better
|
||||
|
||||
- XDR, rpcgen (on Linux these are provided by glibc)
|
||||
|
||||
|
||||
@@ -257,6 +257,9 @@ struct guestfs_h
|
||||
int ml_read_only; /* If mounted read-only. */
|
||||
int ml_debug_calls; /* Extra debug info on each FUSE call. */
|
||||
#endif
|
||||
|
||||
/* Used by src/launch.c:qemu_supports_virtio_scsi */
|
||||
int virtio_scsi;
|
||||
};
|
||||
|
||||
/* Per-filesystem data stored for inspect_os. */
|
||||
|
||||
140
src/launch.c
140
src/launch.c
@@ -78,7 +78,10 @@ static int64_t timeval_diff (const struct timeval *x, const struct timeval *y);
|
||||
static void print_qemu_command_line (guestfs_h *g, char **argv);
|
||||
static int connect_unix_socket (guestfs_h *g, const char *sock);
|
||||
static int qemu_supports (guestfs_h *g, const char *option);
|
||||
static char *qemu_drive_param (guestfs_h *g, const struct drive *drv);
|
||||
static int qemu_supports_device (guestfs_h *g, const char *device_name);
|
||||
static int qemu_supports_virtio_scsi (guestfs_h *g);
|
||||
static char *qemu_drive_param (guestfs_h *g, const struct drive *drv, size_t index);
|
||||
static char *drive_name (size_t index, char *ret);
|
||||
|
||||
#if 0
|
||||
static int qemu_supports_re (guestfs_h *g, const pcre *option_regex);
|
||||
@@ -248,7 +251,7 @@ guestfs__debug_drives (guestfs_h *g)
|
||||
ret = safe_malloc (g, sizeof (char *) * (count + 1));
|
||||
|
||||
for (i = 0, drv = g->drives; drv; i++, drv = drv->next)
|
||||
ret[i] = qemu_drive_param (g, drv);
|
||||
ret[i] = qemu_drive_param (g, drv, i);
|
||||
|
||||
ret[count] = NULL;
|
||||
|
||||
@@ -620,6 +623,7 @@ launch_appliance (guestfs_h *g)
|
||||
|
||||
if (r == 0) { /* Child (qemu). */
|
||||
char buf[256];
|
||||
int virtio_scsi = qemu_supports_virtio_scsi (g);
|
||||
|
||||
/* Set up the full command line. Do this in the subprocess so we
|
||||
* don't need to worry about cleaning up.
|
||||
@@ -660,15 +664,59 @@ launch_appliance (guestfs_h *g)
|
||||
|
||||
/* Add drives */
|
||||
struct drive *drv = g->drives;
|
||||
size_t drv_index = 0;
|
||||
|
||||
if (virtio_scsi) {
|
||||
/* Create the virtio-scsi bus. */
|
||||
add_cmdline (g, "-device");
|
||||
add_cmdline (g, "virtio-scsi-pci,id=scsi");
|
||||
}
|
||||
|
||||
while (drv != NULL) {
|
||||
/* Construct the final -drive parameter. */
|
||||
char *buf = qemu_drive_param (g, drv);
|
||||
char *buf = qemu_drive_param (g, drv, drv_index);
|
||||
|
||||
add_cmdline (g, "-drive");
|
||||
add_cmdline (g, buf);
|
||||
free (buf);
|
||||
|
||||
if (virtio_scsi && drv->iface == NULL) {
|
||||
char buf2[64];
|
||||
snprintf (buf2, sizeof buf2, "scsi-hd,drive=hd%zu", drv_index);
|
||||
add_cmdline (g, "-device");
|
||||
add_cmdline (g, buf2);
|
||||
}
|
||||
|
||||
drv = drv->next;
|
||||
drv_index++;
|
||||
}
|
||||
|
||||
char appliance_root[64] = "";
|
||||
|
||||
/* Add the ext2 appliance drive (after all the drives). */
|
||||
if (appliance) {
|
||||
const char *cachemode = "";
|
||||
if (qemu_supports (g, "cache=")) {
|
||||
if (qemu_supports (g, "unsafe"))
|
||||
cachemode = ",cache=unsafe";
|
||||
else if (qemu_supports (g, "writeback"))
|
||||
cachemode = ",cache=writeback";
|
||||
}
|
||||
|
||||
char buf2[PATH_MAX + 64];
|
||||
add_cmdline (g, "-drive");
|
||||
snprintf (buf2, sizeof buf2, "file=%s,snapshot=on,id=appliance,if=%s%s",
|
||||
appliance, virtio_scsi ? "none" : "virtio", cachemode);
|
||||
add_cmdline (g, buf2);
|
||||
|
||||
if (virtio_scsi) {
|
||||
add_cmdline (g, "-device");
|
||||
add_cmdline (g, "scsi-hd,drive=appliance");
|
||||
}
|
||||
|
||||
snprintf (appliance_root, sizeof appliance_root, "root=/dev/%cd",
|
||||
virtio_scsi ? 's' : 'v');
|
||||
drive_name (drv_index, &appliance_root[12]);
|
||||
}
|
||||
|
||||
if (STRNEQ (QEMU_OPTIONS, "")) {
|
||||
@@ -792,10 +840,12 @@ launch_appliance (guestfs_h *g)
|
||||
/* Linux kernel command line. */
|
||||
snprintf (buf, sizeof buf,
|
||||
LINUX_CMDLINE
|
||||
"%s " /* (root) */
|
||||
"%s " /* (selinux) */
|
||||
"%s " /* (verbose) */
|
||||
"TERM=%s " /* (TERM environment variable) */
|
||||
"%s", /* (append) */
|
||||
appliance_root,
|
||||
g->selinux ? "selinux=1 enforcing=0" : "selinux=0",
|
||||
g->verbose ? "guestfs_verbose=1" : "",
|
||||
getenv ("TERM") ? : "linux",
|
||||
@@ -808,23 +858,6 @@ launch_appliance (guestfs_h *g)
|
||||
add_cmdline (g, "-append");
|
||||
add_cmdline (g, buf);
|
||||
|
||||
/* Add the ext2 appliance drive (last of all). */
|
||||
if (appliance) {
|
||||
const char *cachemode = "";
|
||||
if (qemu_supports (g, "cache=")) {
|
||||
if (qemu_supports (g, "unsafe"))
|
||||
cachemode = ",cache=unsafe";
|
||||
else if (qemu_supports (g, "writeback"))
|
||||
cachemode = ",cache=writeback";
|
||||
}
|
||||
|
||||
char buf2[PATH_MAX + 64];
|
||||
add_cmdline (g, "-drive");
|
||||
snprintf (buf2, sizeof buf2, "file=%s,snapshot=on,if=virtio%s",
|
||||
appliance, cachemode);
|
||||
add_cmdline (g, buf2);
|
||||
}
|
||||
|
||||
/* Finish off the command line. */
|
||||
incr_cmdline_size (g);
|
||||
g->cmdline[g->cmdline_size-1] = NULL;
|
||||
@@ -1432,6 +1465,20 @@ qemu_supports_re (guestfs_h *g, const pcre *option_regex)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Test if device is supported by qemu (currently just greps the -device ?
|
||||
* output).
|
||||
*/
|
||||
static int
|
||||
qemu_supports_device (guestfs_h *g, const char *device_name)
|
||||
{
|
||||
if (!g->qemu_devices) {
|
||||
if (test_qemu (g) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return strstr (g->qemu_devices, device_name) != NULL;
|
||||
}
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
/* Check if a file can be opened. */
|
||||
static int
|
||||
@@ -1447,13 +1494,39 @@ is_openable (guestfs_h *g, const char *path, int flags)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Returns 1 = use virtio-scsi, or 0 = use virtio-blk. */
|
||||
static int
|
||||
qemu_supports_virtio_scsi (guestfs_h *g)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* g->virtio_scsi has these values:
|
||||
* 0 = untested (after handle creation)
|
||||
* 1 = supported
|
||||
* 2 = not supported (use virtio-blk)
|
||||
* 3 = test failed (use virtio-blk)
|
||||
*/
|
||||
if (g->virtio_scsi == 0) {
|
||||
r = qemu_supports_device (g, "virtio-scsi-pci");
|
||||
if (r > 0)
|
||||
g->virtio_scsi = 1;
|
||||
else if (r == 0)
|
||||
g->virtio_scsi = 2;
|
||||
else
|
||||
g->virtio_scsi = 3;
|
||||
}
|
||||
|
||||
return g->virtio_scsi == 1;
|
||||
}
|
||||
|
||||
static char *
|
||||
qemu_drive_param (guestfs_h *g, const struct drive *drv)
|
||||
qemu_drive_param (guestfs_h *g, const struct drive *drv, size_t index)
|
||||
{
|
||||
size_t i;
|
||||
size_t len = 64;
|
||||
size_t len = 128;
|
||||
const char *p;
|
||||
char *r;
|
||||
const char *iface;
|
||||
|
||||
len += strlen (drv->path) * 2; /* every "," could become ",," */
|
||||
if (drv->iface)
|
||||
@@ -1475,16 +1548,35 @@ qemu_drive_param (guestfs_h *g, const struct drive *drv)
|
||||
r[i++] = *p;
|
||||
}
|
||||
|
||||
snprintf (&r[i], len-i, "%s%s%s%s,if=%s",
|
||||
if (drv->iface)
|
||||
iface = drv->iface;
|
||||
else if (qemu_supports_virtio_scsi (g))
|
||||
iface = "none"; /* sic */
|
||||
else
|
||||
iface = "virtio";
|
||||
|
||||
snprintf (&r[i], len-i, "%s%s%s%s,id=hd%zu,if=%s",
|
||||
drv->readonly ? ",snapshot=on" : "",
|
||||
drv->use_cache_off ? ",cache=off" : "",
|
||||
drv->format ? ",format=" : "",
|
||||
drv->format ? drv->format : "",
|
||||
drv->iface ? drv->iface : "virtio");
|
||||
index,
|
||||
iface);
|
||||
|
||||
return r; /* caller frees */
|
||||
}
|
||||
|
||||
/* https://rwmj.wordpress.com/2011/01/09/how-are-linux-drives-named-beyond-drive-26-devsdz/ */
|
||||
static char *
|
||||
drive_name (size_t index, char *ret)
|
||||
{
|
||||
if (index > 26)
|
||||
ret = drive_name (index / 26, ret);
|
||||
index %= 26;
|
||||
*ret++ = 'a' + index;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* You had to call this function after launch in versions <= 1.0.70,
|
||||
* but it is now a no-op.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user