Commit 33240c54 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Reimplement map_fixed_area() to avoid recursion and callbacks.

parent 4cdc2f75
...@@ -1463,42 +1463,6 @@ static void remove_reserved_area( void *addr, size_t size ) ...@@ -1463,42 +1463,6 @@ static void remove_reserved_area( void *addr, size_t size )
} }
struct area_boundary
{
void *base;
size_t size;
void *boundary;
};
/***********************************************************************
* get_area_boundary_callback
*
* Get lowest boundary address between reserved area and non-reserved area
* in the specified region. If no boundaries are found, result is NULL.
* virtual_mutex must be held by caller.
*/
static int get_area_boundary_callback( void *start, SIZE_T size, void *arg )
{
struct area_boundary *area = arg;
void *end = (char *)start + size;
area->boundary = NULL;
if (area->base >= end) return 0;
if ((char *)start >= (char *)area->base + area->size) return 1;
if (area->base >= start)
{
if ((char *)area->base + area->size > (char *)end)
{
area->boundary = end;
return 1;
}
return 0;
}
area->boundary = start;
return 1;
}
/*********************************************************************** /***********************************************************************
* unmap_area * unmap_area
* *
...@@ -1918,52 +1882,48 @@ static int alloc_reserved_area_callback( void *start, SIZE_T size, void *arg ) ...@@ -1918,52 +1882,48 @@ static int alloc_reserved_area_callback( void *start, SIZE_T size, void *arg )
/*********************************************************************** /***********************************************************************
* map_fixed_area * map_fixed_area
* *
* mmap the fixed memory area. * Map a memory area at a fixed address.
* virtual_mutex must be held by caller. * virtual_mutex must be held by caller.
*/ */
static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot ) static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot )
{ {
void *ptr; int unix_prot = get_unix_prot(vprot);
struct reserved_area *area;
NTSTATUS status;
char *start = base, *end = (char *)base + size;
switch (mmap_is_in_reserved_area( base, size )) if (find_view_range( base, size )) return STATUS_CONFLICTING_ADDRESSES;
{
case -1: /* partially in a reserved area */ LIST_FOR_EACH_ENTRY( area, &reserved_areas, struct reserved_area, entry )
{ {
NTSTATUS status; char *area_start = area->base;
struct area_boundary area; char *area_end = area_start + area->size;
size_t lower_size;
area.base = base; if (area_start >= end) break;
area.size = size; if (area_end <= start) continue;
mmap_enum_reserved_areas( get_area_boundary_callback, &area, 0 ); if (area_start > start)
assert( area.boundary );
lower_size = (char *)area.boundary - (char *)base;
status = map_fixed_area( base, lower_size, vprot );
if (status == STATUS_SUCCESS)
{ {
status = map_fixed_area( area.boundary, size - lower_size, vprot); if (anon_mmap_tryfixed( start, area_start - start, unix_prot, 0 ) == MAP_FAILED) goto failed;
if (status != STATUS_SUCCESS) unmap_area( base, lower_size ); start = area_start;
} }
return status; if (area_end >= end)
}
case 0: /* not in a reserved area, do a normal allocation */
if ((ptr = anon_mmap_tryfixed( base, size, get_unix_prot(vprot), 0 )) == MAP_FAILED)
{ {
if (errno == ENOMEM) return STATUS_NO_MEMORY; if (anon_mmap_fixed( start, end - start, unix_prot, 0 ) == MAP_FAILED) goto failed;
if (errno == EEXIST) return STATUS_CONFLICTING_ADDRESSES; return STATUS_SUCCESS;
return STATUS_INVALID_PARAMETER;
} }
break; if (anon_mmap_fixed( start, area_end - start, unix_prot, 0 ) == MAP_FAILED) goto failed;
start = area_end;
default:
case 1: /* in a reserved area, make sure the address is available */
if (find_view_range( base, size )) return STATUS_CONFLICTING_ADDRESSES;
/* replace the reserved area by our mapping */
if ((ptr = anon_mmap_fixed( base, size, get_unix_prot(vprot), 0 )) != base)
return STATUS_INVALID_PARAMETER;
break;
} }
if (is_beyond_limit( ptr, size, working_set_limit )) working_set_limit = address_space_limit;
if (anon_mmap_tryfixed( start, end - start, unix_prot, 0 ) == MAP_FAILED) goto failed;
return STATUS_SUCCESS; return STATUS_SUCCESS;
failed:
if (errno == ENOMEM) status = STATUS_NO_MEMORY;
else if (errno == EEXIST) status = STATUS_CONFLICTING_ADDRESSES;
else status = STATUS_INVALID_PARAMETER;
unmap_area( base, start - (char *)base );
return status;
} }
/*********************************************************************** /***********************************************************************
...@@ -1998,12 +1958,10 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, ...@@ -1998,12 +1958,10 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
if (base) if (base)
{ {
if (is_beyond_limit( base, size, address_space_limit )) if (is_beyond_limit( base, size, address_space_limit )) return STATUS_WORKING_SET_LIMIT_RANGE;
return STATUS_WORKING_SET_LIMIT_RANGE; if (limit && is_beyond_limit( base, size, (void *)limit )) return STATUS_CONFLICTING_ADDRESSES;
if (limit && is_beyond_limit( base, size, (void *)limit )) if ((status = map_fixed_area( base, size, vprot ))) return status;
return STATUS_CONFLICTING_ADDRESSES; if (is_beyond_limit( base, size, working_set_limit )) working_set_limit = address_space_limit;
status = map_fixed_area( base, size, vprot );
if (status != STATUS_SUCCESS) return status;
ptr = base; ptr = base;
} }
else else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment