Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

HVM-671 qemu cannot start due to a failing mlock()

  • Loading branch information...
commit 7bdfeb90593194a6d242831c9e085e8798c84702 1 parent 96f81f9
@bcantrill bcantrill authored
Showing with 67 additions and 1 deletion.
  1. +67 −1 exec.c
View
68 exec.c
@@ -2828,6 +2828,72 @@ static ram_addr_t last_ram_offset(void)
return last;
}
+#ifdef CONFIG_SOLARIS
+static int
+qemu_mlock(caddr_t base, ram_addr_t size)
+{
+ ram_addr_t ps = qemu_real_host_page_size, nbytes, locked = 0;
+ ram_addr_t remaining = size / ps;
+ ram_addr_t step = remaining;
+ timespec_t tv;
+ hrtime_t waiting = 0, threshold;
+
+ tv.tv_sec = 0;
+ tv.tv_nsec = NANOSEC / MILLISEC;
+ threshold = 10 * (hrtime_t)NANOSEC;
+
+ /*
+ * We cannot lock memory with a single call to mlock() because it
+ * won't result in sustained memory pressure: if there is a
+ * substantial amount of kernel memory in use electively (e.g., for
+ * the ARC) a single call to mlock() may fail where sustained memory
+ * pressure would succeed. We therefore start by trying to lock the
+ * entire region, adjusting our size down as we fail with EAGAIN; once
+ * we successfully lock a portion of the region, we advance to the
+ * unlocked portion of the region (if any remains) and increase the
+ * size. Note that this will continue to hoard memory until it locks
+ * what it needs -- it won't give up. To help debug situations in
+ * which one has mistakenly overprovisioned, we emit a message every
+ * ten seconds with no forward progress.
+ */
+ while (remaining) {
+ if (step > remaining)
+ step = remaining;
+
+ while (mlock(base, (nbytes = step * ps)) == -1) {
+ if (errno != EAGAIN)
+ return (-1);
+
+ if (waiting == 0)
+ waiting = gethrtime();
+
+ if (step > 1) {
+ step >>= 1;
+ continue;
+ }
+
+ (void) nanosleep(&tv, NULL);
+
+ if (gethrtime() - waiting > threshold) {
+ (void) fprintf(stderr, "qemu_mlock: have only "
+ "locked %ld of %ld bytes; still "
+ "trying...\n", locked, size);
+ waiting = 0;
+ }
+ }
+
+ waiting = 0;
+ base += nbytes;
+ locked += nbytes;
+ remaining -= step;
+
+ step <<= 1;
+ }
+
+ return (0);
+}
+#endif
+
ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
ram_addr_t size, void *host)
{
@@ -2883,7 +2949,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
* revisited if we implement mmu notifiers in the kernel.
* Note also that pages are touched in kvm_set_user_memory_region.
*/
- if (mlock(new_block->host, size) != 0) {
+ if (qemu_mlock(new_block->host, size) != 0) {
@rmustacc Owner

It already is, look at the surrounding part.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
fprintf(stderr, "qemu_ram_alloc: Could not lock %ld memory, errno = %d\n",
size, errno);
exit(1);
Please sign in to comment.
Something went wrong with that request. Please try again.