@@ -123,54 +123,22 @@ static void shmem_release_pages(char *rel_area)
}
/**
- * Structure to hold the reservation and aligned address information
- * This helps prevent race conditions by keeping the original reservation
- * active until it can be atomically replaced with the real mapping.
- */
-struct addr_mapping {
- void *reservation; /* The original memory reservation */
- void *aligned_addr; /* The aligned address for actual use */
- size_t size; /* Size of the reservation */
-};
-
-/**
- * Find a suitable virtual address area of the requested size and alignment
+ * Find a suitable virtual address area of the requested size
*
- * This function obtains a hint from the OS about where a good place to map
- * memory might be, creates a temporary reservation to hold the space, and
- * calculates an aligned address within that reservation.
+ * This function creates a temporary reservation with PROT_NONE to hold
+ * the address space. This reservation prevents other threads from taking
+ * the address range until we can atomically replace it with our real mapping.
*
- * IMPORTANT: The caller must eventually unmap the reservation when done
- * or replace it with MAP_FIXED to prevent memory leaks.
+ * IMPORTANT: The caller must eventually replace this reservation with MAP_FIXED
+ * or munmap it to prevent memory leaks.
*
- * @param mapping Pointer to addr_mapping struct that will receive the results
* @param size Size of the memory area needed
- * @param alignment Alignment requirement (typically huge page size)
- * @return 0 on success, -1 on failure
+ * @return Reserved memory area or NULL on failure
*/
-static int find_suitable_area(struct addr_mapping *mapping, size_t size, size_t alignment)
+static void *find_suitable_area(size_t size)
{
- void *addr;
- uintptr_t aligned_addr;
-
- if (!mapping)
- return -1;
-
- /* First create a reservation with PROT_NONE to hold the address space */
- addr = mmap(NULL, size, PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (addr == MAP_FAILED)
- return -1;
-
- /* Calculate an aligned address within this reservation */
- aligned_addr = ((uintptr_t)addr + alignment - 1) & ~(alignment - 1);
-
- /* Store both the reservation and the aligned address */
- mapping->reservation = addr;
- mapping->aligned_addr = (void *)aligned_addr;
- mapping->size = size;
-
- return 0;
+ /* Create a reservation with PROT_NONE to hold the address space */
+ return mmap(NULL, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
}
static int shmem_allocate_area(void **alloc_area, bool is_src)
@@ -179,13 +147,12 @@ static int shmem_allocate_area(void **alloc_area, bool is_src)
size_t bytes = nr_pages * page_size, hpage_size = read_pmd_pagesize();
unsigned long offset = is_src ? 0 : bytes;
int mem_fd = uffd_mem_fd_create(bytes * 2, false);
- struct addr_mapping addr_map = {0};
- struct addr_mapping alias_map = {0};
- int ret;
+ void *reserved_area = NULL;
+ void *reserved_alias = NULL;
- /* Get a suitable address space with reservation */
- ret = find_suitable_area(&addr_map, bytes, hpage_size);
- if (ret < 0) {
+ /* Get a suitable address reservation */
+ reserved_area = find_suitable_area(bytes);
+ if (reserved_area == MAP_FAILED) {
/* Couldn't get a reservation, but we can still try without hints */
*alloc_area = mmap(NULL, bytes, PROT_READ | PROT_WRITE,
MAP_SHARED, mem_fd, offset);
@@ -195,21 +162,22 @@ static int shmem_allocate_area(void **alloc_area, bool is_src)
return -errno;
}
} else {
- void *target_addr = addr_map.aligned_addr;
+ void *target_addr = reserved_area;
/* If this is dst area, add offset to prevent overlap with src area */
if (!is_src) {
+ /* Unmap the original reservation since we're using a different address */
+ munmap(reserved_area, bytes);
+
/* Calculate new address with the same spacing as original code */
/* src map + alias + interleaved hpages */
- uintptr_t new_addr = (uintptr_t)target_addr +
- 2 * (bytes + hpage_size);
-
- /* Unmap the original reservation since we're using a different address */
- munmap(addr_map.reservation, addr_map.size);
+ target_addr = (char *)reserved_area + 2 * (bytes + hpage_size);
/* Create a new reservation at the offset location */
- ret = find_suitable_area(&addr_map, bytes, hpage_size);
- if (ret < 0) {
+ reserved_area = mmap(target_addr, bytes, PROT_NONE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+ if (reserved_area == MAP_FAILED) {
/* Fallback to non-fixed mapping if we can't reserve space */
*alloc_area = mmap(NULL, bytes, PROT_READ | PROT_WRITE,
MAP_SHARED, mem_fd, offset);
@@ -220,7 +188,7 @@ static int shmem_allocate_area(void **alloc_area, bool is_src)
}
} else {
/* Use our new reservation */
- target_addr = addr_map.aligned_addr;
+ target_addr = reserved_area;
}
}
@@ -233,14 +201,11 @@ static int shmem_allocate_area(void **alloc_area, bool is_src)
*alloc_area = mmap(target_addr, bytes, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, mem_fd, offset);
- /* Check if the mapping succeeded at our target address */
- if (*alloc_area == MAP_FAILED || *alloc_area != target_addr) {
+ if (*alloc_area == MAP_FAILED) {
/* If fixed mapping failed, clean up and try anywhere */
- if (*alloc_area != MAP_FAILED)
- munmap(*alloc_area, bytes);
-
- /* Clean up the reservation if it's still around */
- munmap(addr_map.reservation, addr_map.size);
+ /* Explicitly munmap the reservation since our map failed */
+ if (reserved_area != MAP_FAILED)
+ munmap(reserved_area, bytes);
/* Fall back to letting the kernel choose an address */
*alloc_area = mmap(NULL, bytes, PROT_READ | PROT_WRITE,
@@ -254,12 +219,12 @@ static int shmem_allocate_area(void **alloc_area, bool is_src)
}
/* Calculate a good spot for the alias mapping with space to prevent merging */
- ret = find_suitable_area(&alias_map, bytes, hpage_size);
- if (ret < 0) {
+ void *p_alias = (char *)((uintptr_t)*alloc_area + bytes + hpage_size);
+
+ /* Reserve space for alias mapping */
+ reserved_alias = find_suitable_area(bytes);
+ if (reserved_alias == MAP_FAILED) {
/* Fallback to using an offset from the first mapping */
- void *p_alias = (char *)((uintptr_t)*alloc_area + bytes + hpage_size);
-
- /* No reservation, map directly */
area_alias = mmap(p_alias, bytes, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, mem_fd, offset);
@@ -270,14 +235,14 @@ static int shmem_allocate_area(void **alloc_area, bool is_src)
}
} else {
/* Use our reservation for the alias mapping */
- area_alias = mmap(alias_map.aligned_addr, bytes, PROT_READ | PROT_WRITE,
+ area_alias = mmap(reserved_alias, bytes, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, mem_fd, offset);
- /* Whether it succeeded or failed, we need to clean up the reservation */
- if (area_alias != alias_map.aligned_addr)
- munmap(alias_map.reservation, alias_map.size);
-
+ /* If mapping failed, try without specific address */
if (area_alias == MAP_FAILED) {
+ /* Clean up the reservation since it didn't get replaced */
+ munmap(reserved_alias, bytes);
+
/* If fixed mapping failed, try anywhere */
area_alias = mmap(NULL, bytes, PROT_READ | PROT_WRITE,
MAP_SHARED, mem_fd, offset);