summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--backends/hostmem-file.c23
-rw-r--r--include/qemu/osdep.h13
-rw-r--r--util/oslib-posix.c53
-rw-r--r--util/oslib-win32.c5
4 files changed, 94 insertions, 0 deletions
diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c
index ce54788048..37ac6445d2 100644
--- a/backends/hostmem-file.c
+++ b/backends/hostmem-file.c
@@ -56,6 +56,29 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
error_setg(errp, "mem-path property not set");
return;
}
+
+ /*
+ * Verify pmem file size since starting a guest with an incorrect size
+ * leads to confusing failures inside the guest.
+ */
+ if (fb->is_pmem) {
+ Error *local_err = NULL;
+ uint64_t size;
+
+ size = qemu_get_pmem_size(fb->mem_path, &local_err);
+ if (!size) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ if (backend->size > size) {
+ error_setg(errp, "size property %" PRIu64 " is larger than "
+ "pmem file \"%s\" size %" PRIu64, backend->size,
+ fb->mem_path, size);
+ return;
+ }
+ }
+
backend->force_prealloc = mem_prealloc;
name = host_memory_backend_get_name(backend);
memory_region_init_ram_from_file(&backend->mr, OBJECT(backend),
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 840af09cb0..303d315c5d 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -571,6 +571,19 @@ void os_mem_prealloc(int fd, char *area, size_t sz, int smp_cpus,
Error **errp);
/**
+ * qemu_get_pmem_size:
+ * @filename: path to a pmem file
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Determine the size of a persistent memory file. Besides supporting files on
+ * DAX file systems, this function also supports Linux devdax character
+ * devices.
+ *
+ * Returns: the size or 0 on failure
+ */
+uint64_t qemu_get_pmem_size(const char *filename, Error **errp);
+
+/**
* qemu_get_pid_name:
* @pid: pid of a process
*
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index 37c5854b9c..10d90d1783 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -500,6 +500,59 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
}
}
+uint64_t qemu_get_pmem_size(const char *filename, Error **errp)
+{
+ struct stat st;
+
+ if (stat(filename, &st) < 0) {
+ error_setg(errp, "unable to stat pmem file \"%s\"", filename);
+ return 0;
+ }
+
+#if defined(__linux__)
+ /* Special handling for devdax character devices */
+ if (S_ISCHR(st.st_mode)) {
+ char *subsystem_path = NULL;
+ char *subsystem = NULL;
+ char *size_path = NULL;
+ char *size_str = NULL;
+ uint64_t ret = 0;
+
+ subsystem_path = g_strdup_printf("/sys/dev/char/%d:%d/subsystem",
+ major(st.st_rdev), minor(st.st_rdev));
+ subsystem = g_file_read_link(subsystem_path, NULL);
+ if (!subsystem) {
+ error_setg(errp, "unable to read subsystem for pmem file \"%s\"",
+ filename);
+ goto devdax_err;
+ }
+
+ if (!g_str_has_suffix(subsystem, "/dax")) {
+ error_setg(errp, "pmem file \"%s\" is not a dax device", filename);
+ goto devdax_err;
+ }
+
+ size_path = g_strdup_printf("/sys/dev/char/%d:%d/size",
+ major(st.st_rdev), minor(st.st_rdev));
+ if (!g_file_get_contents(size_path, &size_str, NULL, NULL)) {
+ error_setg(errp, "unable to read size for pmem file \"%s\"",
+ size_path);
+ goto devdax_err;
+ }
+
+ ret = g_ascii_strtoull(size_str, NULL, 0);
+
+devdax_err:
+ g_free(size_str);
+ g_free(size_path);
+ g_free(subsystem);
+ g_free(subsystem_path);
+ return ret;
+ }
+#endif /* defined(__linux__) */
+
+ return st.st_size;
+}
char *qemu_get_pid_name(pid_t pid)
{
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index b4c17f5dfa..bd633afab6 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -560,6 +560,11 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
}
}
+uint64_t qemu_get_pmem_size(const char *filename, Error **errp)
+{
+ error_setg(errp, "pmem support not available");
+ return 0;
+}
char *qemu_get_pid_name(pid_t pid)
{