On Tue, Apr 20, 2021 at 04:35:02AM +0100, Igor Druzhinin wrote: > When we're replacing the existing mapping there is possibility of a race > on memory map with other threads doing mmap operations - the address being > unmapped/re-mapped could be occupied by another thread in between. > > Linux mmap man page recommends keeping the existing mappings in place to > reserve the place and instead utilize the fact that the next mmap operation > with MAP_FIXED flag passed will implicitly destroy the existing mappings > behind the chosen address. This behavior is guaranteed by POSIX / BSD and > therefore is portable. > > Note that it wouldn't make the replacement atomic for parallel accesses to > the replaced region - those might still fail with SIGBUS due to > xenforeignmemory_map not being atomic. So we're still not expecting those. > > Tested-by: Anthony PERARD <anthony.per...@citrix.com> > Signed-off-by: Igor Druzhinin <igor.druzhi...@citrix.com>
Should we add a 'Fixes: 759235653de ...' or similar tag here? > --- > hw/i386/xen/xen-mapcache.c | 15 ++++++++++++++- > 1 file changed, 14 insertions(+), 1 deletion(-) > > diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c > index 5b120ed..e82b7dc 100644 > --- a/hw/i386/xen/xen-mapcache.c > +++ b/hw/i386/xen/xen-mapcache.c > @@ -171,7 +171,20 @@ static void xen_remap_bucket(MapCacheEntry *entry, > if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) { > ram_block_notify_remove(entry->vaddr_base, entry->size); > } > - if (munmap(entry->vaddr_base, entry->size) != 0) { > + > + /* > + * If an entry is being replaced by another mapping and we're using > + * MAP_FIXED flag for it - there is possibility of a race for vaddr > + * address with another thread doing an mmap call itself > + * (see man 2 mmap). To avoid that we skip explicit unmapping here > + * and allow the kernel to destroy the previous mappings by replacing > + * them in mmap call later. > + * > + * Non-identical replacements are not allowed therefore. > + */ > + assert(!vaddr || (entry->vaddr_base == vaddr && entry->size == > size)); > + > + if (!vaddr && munmap(entry->vaddr_base, entry->size) != 0) { Oh, so remappings of foreign addresses must always use the same virtual address space, I somehow assumed that you could remap an existing foreign map (or dummy mapping) into a different virtual address if you so wanted. Thanks, Roger.