Copy-on-write file mapping on windows
Asked Answered
A

2

5

I have 3 processes communicating over named pipes: server, writer, reader. The basic idea is that the writer can store huge (~GB) binary blobs on the server, and the reader(s) can retrieve it. But instead of sending data on the named pipe, memory mapping is used.

The server creates an unnamed file-backed mapping with CreateFileMapping with PAGE_READWRITE protection, then duplicates the handle into the writer. After the writer has done its job, the handle is duplicated into any number of interested readers.

The writer maps the handle with MapViewOfFile in FILE_MAP_WRITE mode.

The reader maps the handle with MapViewOfFile in FILE_MAP_READ|FILE_MAP_COPY mode.

On the reader I want copy-on-write semantics, so as long the mapping is only read it is shared between all reader instances. But if a reader wants to write into it (eg. in-place parsing or image processing), the impacts should be limited to the modifying process with the least number of copied pages possible.

The problem
When the reader tries to write into the mapping it dies with segmentation fault as if FILE_MAP_COPY was not considered. What's wrong with the above described method? According to MSDN this should work...

We have the same mechanism implemented on linux as well (with mmap and fd passing in AF_UNIX ancillary buffers) and it works as expected.

Antoinetteanton answered 6/3, 2019 at 8:41 Comment(4)
you must use FILE_MAP_COPY only instead FILE_MAP_READ|FILE_MAP_COPYKnowhow
The way I read it is, COPY is just a flag that can be combined with the access mode. Since you do intend to write to the address you should use WRITE and since you also want CoW you should ask for WRITE|COPY.Rubie
@Rubie - you mean use FILE_MAP_COPY|FILE_MAP_WRITE ? if you try this - can view that this combination of flags converted to PAGE_READWRITE. only single FILE_MAP_COPY converted to PAGE_WRITECOPY. as is. if want - test code pastebin.com/LkTj72CdKnowhow
@RbMm, using FILE_MAP_COPY indeed solved the issue. And yeah, the documentation page is misleading (bitwise-OR comment) on this flag.Antoinetteanton
K
11

problem here that MapViewOfFile bad designed or/and documented. this is shell (with restricted functionality) over ZwMapViewOfSection. the dwDesiredAccess parameter of MapViewOfFile converted to Win32Protect parameter of ZwMapViewOfSection.

the FILE_MAP_READ|FILE_MAP_COPY combination converted to PAGE_READONLY page protection, because this you and get page fault on write.

you need use FILE_MAP_COPY only flag - it converted to PAGE_WRITECOPY page protection and in this case all will be work.

the best solution of course direct use ZwMapViewOfSection with PAGE_WRITECOPY page protection

Knowhow answered 6/3, 2019 at 10:20 Comment(3)
Using the NT API when Win32 can be made to work is never the best solution IMHO.Rubie
@Rubie Isn't the point that the Win32 API cannot be made to do what is desired in this case?Sexdecillion
@DavidHeffernan - no, MapViewOfFile with single flag FILE_MAP_COPY do job correct and as desired. but for me unclear logic under flag conversion. the ZwMapViewOfSection have more clear designKnowhow
R
4

TL:DR: RbMm is correct, you must pass just FILE_MAP_COPY to MapViewOfFile to get copy-on-write behavior.

The current Microsoft documentation is incorrect, it incorrectly states that FILE_MAP_COPY can be OR'ed with FILE_MAP_<ALL_ACCESS|READ|WRITE>.

Looking at older versions of MSDN it correctly says that you must choose one of the access modes:

Type of access to the file view and, therefore, the protection of the pages mapped by the file. This parameter can be one of the following values.

  • FILE_MAP_WRITE
  • FILE_MAP_READ
  • FILE_MAP_ALL_ACCESS
  • FILE_MAP_COPY

No longer relevant but still surprising, on Windows 95/98/ME the copy-on-write behavior only applies to the file, writes are propagated to views in other processes!

Rubie answered 6/3, 2019 at 13:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.