memory backend file unnecessarily requires write permission while it is only mapped privately
Host environment
- Operating system: linux
- OS/kernel version: kernel 5.15
- Architecture: x86
- QEMU flavor: qemu-system-x86_64
- QEMU version: 8.0.2
- QEMU command line:
./qemu-system-x86_64 -machine memory-backend=pc.ram -object memory-backend-file,id=pc.ram,size=40M,mem-path=path/to/pc.ram[,readonly=on] -nodefaults
Emulated/Virtualized environment
- Operating system: unrelated
- OS/kernel version: unrelated
- Architecture: unrelated
Description of problem
One day I wanted to boot the machine with physical memory initialized with a file, in a copy-on-write style. That is why I tried out -mem-path
and -object memory-backend-file
. Actually -mem-path
already works if not considering that qemu dislikes the backing file being readonly and requires it to be writeable even when only private mappings are used here.
I sadly found out that when using memory-backend-file, and when share=off
, if readonly=on
, then file is open
ed with O_RDONLY
and mmap prot is PROT_READ
; if readonly=off
, then the file is open
ed with O_RDWR
and mmap prot is PROT_READ|PROT_WRITE
. I want O_RDONLY
and PROT_READ|PROT_WRITE
but I cannot find it anywhere.
In my opinion, expected behavior should be that if share=off
, the file can already be opened with O_RDONLY
no matter what prot the mmap is. That is how linux MAP_PRIVATE
works - basically copy on write. When I only need copy on write for the content of file, why do I require write permission for it?
Now I cannot find a setup that opens the file with fd=open(*, O_RDONLY)
and mmap it with mmap(*, *, PROT_READ|PROT_WRITE, MAP_PRIVATE|*, fd, *)
.
Tell me if I misunderstood linux (for example certain file behave differently if one open with O_RDONLY and this behavior is necessary) or qemu or other posix systems where copy-on-write does not work like this.
Proposed patch
Basically this works for me mostly:
diff -ru qemu-8.0.2/softmmu/physmem.c qemu-8.0.2-b/softmmu/physmem.c
--- qemu-8.0.2/softmmu/physmem.c 2023-05-31 01:02:04.000000000 +0000
+++ qemu-8.0.2-b/softmmu/physmem.c 2023-05-31 01:02:05.000000000 +0000
@@ -1935,7 +1935,8 @@
bool created;
RAMBlock *block;
- fd = file_ram_open(mem_path, memory_region_name(mr), readonly, &created,
+ fd = file_ram_open(mem_path, memory_region_name(mr),
+ readonly || !(ram_flags & RAM_SHARED), &created,
errp);
if (fd < 0) {
return NULL;
Though this patch seems temporary and not official (it does not have comment telling why; it does not check the macros to see whether the target is linux; also a testcase of readonly memory may be required to be inserted into testsuite; if this does not work under different architecture or it does not work under some hugetlb setup or similar, this might be implemented with additional flags specified in command line; etc)