#include <string.h>
#include <fcntl.h>
#include <time.h>
+#include <sys/stat.h>
#include <sys/select.h>
+
#include <rpc/types.h>
#include <rpc/xdr.h>
guestfs_launch (guestfs_h *g)
{
static const char *dir_template = "/tmp/libguestfsXXXXXX";
- int r, i, len, pmore;
+ int r, i, len, pmore, memsize;
int wfd[2], rfd[2];
int tries;
const char *kernel_name = "vmlinuz." REPO "." host_cpu;
char *kernel = NULL, *initrd = NULL;
char unixsock[256];
struct sockaddr_un addr;
+ struct stat statbuf;
/* Configured? */
if (!g->cmdline) {
goto cleanup0;
}
+ /* Choose a suitable memory size (in MB). This is more art
+ * than science, but you can help by doing
+ * ./configure --enable-debug-command
+ * and then running:
+ * debug sh free
+ * debug mem ''
+ * and seeing how much free memory is left for particular
+ * configurations.
+ *
+ * It's also helpful to report both the compressed and uncompressed
+ * size of the initramfs (ls -lh initramfs*.img; du -sh initramfs).
+ *
+ * XXX KVM virtio balloon driver?
+ */
+ if (stat (initrd, &statbuf) != -1) {
+ /* Approximate size of the initramfs after it is decompressed
+ * in kernel memory. The compression factor is ~2.5-3.
+ */
+ memsize = 3 * statbuf.st_size / 1024 / 1024;
+
+ /* Approximate size used by the kernel. */
+ memsize += 10;
+
+ /* Want to give userspace some room, so: */
+ memsize += 128;
+
+#if SIZEOF_LONG == 8
+ /* On 64 bit, assume some overhead. */
+ memsize += 64;
+#endif
+ } else
+ memsize = 512;
+
+
/* Make the temporary directory containing the socket. */
if (!g->tmpdir) {
g->tmpdir = safe_strdup (g, dir_template);
if (r == 0) { /* Child (qemu). */
char vmchannel[256];
char append[256];
+ char memsize_str[256];
/* Set up the full command line. Do this in the subprocess so we
* don't need to worry about cleaning up.
VMCHANNEL_ADDR, VMCHANNEL_PORT,
g->verbose ? " guestfs_verbose=1" : "");
+ snprintf (memsize_str, sizeof memsize_str, "%d", memsize);
+
add_cmdline (g, "-m");
- add_cmdline (g, "384"); /* XXX Choose best size. */
+ add_cmdline (g, memsize_str);
#if 0
add_cmdline (g, "-no-kqemu"); /* Avoids a warning. */
#endif
guestfs__send_sync (guestfs_h *g, int proc_nr,
xdrproc_t xdrp, char *args)
{
- char buffer[GUESTFS_MESSAGE_MAX];
struct guestfs_message_header hdr;
XDR xdr;
unsigned len;
return -1;
}
+ /* This is probably an internal error. Or perhaps we should just
+ * free the buffer anyway?
+ */
+ if (g->msg_out != NULL) {
+ error (g, "guestfs__send_sync: msg_out should be NULL");
+ return -1;
+ }
+
+ /* We have to allocate this message buffer on the heap because
+ * it is quite large (although will be mostly unused). We
+ * can't allocate it on the stack because in some environments
+ * we have quite limited stack space available, notably when
+ * running in the JVM.
+ */
+ g->msg_out = safe_malloc (g, GUESTFS_MESSAGE_MAX + 4);
+ xdrmem_create (&xdr, g->msg_out + 4, GUESTFS_MESSAGE_MAX, XDR_ENCODE);
+
/* Serialize the header. */
hdr.prog = GUESTFS_PROGRAM;
hdr.vers = GUESTFS_PROTOCOL_VERSION;
hdr.serial = serial;
hdr.status = GUESTFS_STATUS_OK;
- xdrmem_create (&xdr, buffer, sizeof buffer, XDR_ENCODE);
if (!xdr_guestfs_message_header (&xdr, &hdr)) {
error (g, "xdr_guestfs_message_header failed");
- return -1;
+ goto cleanup1;
}
/* Serialize the args. If any, because some message types
if (xdrp) {
if (!(*xdrp) (&xdr, args)) {
error (g, "dispatch failed to marshal args");
- return -1;
+ goto cleanup1;
}
}
+ /* Get the actual length of the message, resize the buffer to match
+ * the actual length, and write the length word at the beginning.
+ */
len = xdr_getpos (&xdr);
xdr_destroy (&xdr);
- /* Allocate the outgoing message buffer. */
- g->msg_out = safe_malloc (g, len + 4);
-
+ g->msg_out = safe_realloc (g, g->msg_out, len + 4);
g->msg_out_size = len + 4;
g->msg_out_pos = 0;
xdrmem_create (&xdr, g->msg_out, 4, XDR_ENCODE);
xdr_uint32_t (&xdr, &len);
- memcpy (g->msg_out + 4, buffer, len);
-
if (guestfs__switch_to_sending (g) == -1)
goto cleanup1;