When uvm pivots are enabled, allocations with an address hint provided by the user program are handled by the uaddr_hint selector.
I'd like to remove the uaddr_hint selector. The uaddr_rnd selector already deals with hinted allocations correctly, so why not use it for hinted allocations in the pivot selector? This diff is a part of making pivots work. Getting rid of the hint selectors makes the code simpler. I'd to commit this part first, to make the actual pivot diffs smaller. ok? Some more details: If you have multiple selectors per address space that manage overlapping address ranges, some selectors have priority over others. E.g. only the brk selector is allowed to make allocations within the brk area. The rnd selector gets all these checks right, but the hint selector does not, which causes panics when you use pivots and try to do a hinted allocation within the brk area. So better use the code which is known to work for hinted allocations. Once pivots are enabled, maybe the parts of the rnd allocator that deal with hinted allocations can be factored out into a common function. Index: uvm/uvm_addr.c =================================================================== RCS file: /cvs/src/sys/uvm/uvm_addr.c,v retrieving revision 1.22 diff -u -p -r1.22 uvm_addr.c --- uvm/uvm_addr.c 16 Sep 2016 02:50:54 -0000 1.22 +++ uvm/uvm_addr.c 14 Jan 2017 05:53:17 -0000 @@ -46,17 +46,10 @@ /* Pool with uvm_addr_state structures. */ struct pool uaddr_pool; -struct pool uaddr_hint_pool; struct pool uaddr_bestfit_pool; struct pool uaddr_pivot_pool; struct pool uaddr_rnd_pool; -/* uvm_addr state for hint based selector. */ -struct uaddr_hint_state { - struct uvm_addr_state uaddr; - vsize_t max_dist; -}; - /* uvm_addr state for bestfit selector. */ struct uaddr_bestfit_state { struct uvm_addr_state ubf_uaddr; @@ -118,7 +111,6 @@ void uaddr_kremove(struct vm_map *, void uaddr_kbootstrapdestroy(struct uvm_addr_state *); void uaddr_destroy(struct uvm_addr_state *); -void uaddr_hint_destroy(struct uvm_addr_state *); void uaddr_kbootstrap_destroy(struct uvm_addr_state *); void uaddr_rnd_destroy(struct uvm_addr_state *); void uaddr_bestfit_destroy(struct uvm_addr_state *); @@ -138,10 +130,6 @@ int uaddr_rnd_select(struct vm_map *, struct uvm_addr_state *, struct vm_map_entry **, vaddr_t *, vsize_t, vaddr_t, vaddr_t, vm_prot_t, vaddr_t); -int uaddr_hint_select(struct vm_map *, - struct uvm_addr_state*, struct vm_map_entry **, - vaddr_t *, vsize_t, vaddr_t, vaddr_t, vm_prot_t, - vaddr_t); int uaddr_bestfit_select(struct vm_map *, struct uvm_addr_state*, struct vm_map_entry **, vaddr_t *, vsize_t, vaddr_t, vaddr_t, vm_prot_t, @@ -290,8 +278,6 @@ uvm_addr_init(void) { pool_init(&uaddr_pool, sizeof(struct uvm_addr_state), 0, IPL_VM, PR_WAITOK, "uaddr", NULL); - pool_init(&uaddr_hint_pool, sizeof(struct uaddr_hint_state), 0, - IPL_VM, PR_WAITOK, "uaddrhint", NULL); pool_init(&uaddr_bestfit_pool, sizeof(struct uaddr_bestfit_state), 0, IPL_VM, PR_WAITOK, "uaddrbest", NULL); pool_init(&uaddr_pivot_pool, sizeof(struct uaddr_pivot_state), 0, @@ -740,116 +726,6 @@ uaddr_rnd_print(struct uvm_addr_state *u #endif /* - * An allocator that selects an address within distance of the hint. - * - * If no hint is given, the allocator refuses to allocate. - */ -const struct uvm_addr_functions uaddr_hint_functions = { - .uaddr_select = &uaddr_hint_select, - .uaddr_destroy = &uaddr_hint_destroy, - .uaddr_name = "uaddr_hint" -}; - -/* - * Create uaddr_hint state. - */ -struct uvm_addr_state * -uaddr_hint_create(vaddr_t minaddr, vaddr_t maxaddr, vsize_t max_dist) -{ - struct uaddr_hint_state *ua_hint; - - KASSERT(uaddr_hint_pool.pr_size == sizeof(*ua_hint)); - - ua_hint = pool_get(&uaddr_hint_pool, PR_WAITOK); - ua_hint->uaddr.uaddr_minaddr = minaddr; - ua_hint->uaddr.uaddr_maxaddr = maxaddr; - ua_hint->uaddr.uaddr_functions = &uaddr_hint_functions; - ua_hint->max_dist = max_dist; - return &ua_hint->uaddr; -} - -/* - * Destroy uaddr_hint state. - */ -void -uaddr_hint_destroy(struct uvm_addr_state *uaddr) -{ - pool_put(&uaddr_hint_pool, uaddr); -} - -/* - * Hint selector. - * - * Attempts to find an address that is within max_dist of the hint. - */ -int -uaddr_hint_select(struct vm_map *map, struct uvm_addr_state *uaddr_param, - struct vm_map_entry **entry_out, vaddr_t *addr_out, - vsize_t sz, vaddr_t align, vaddr_t offset, - vm_prot_t prot, vaddr_t hint) -{ - struct uaddr_hint_state *uaddr = - (struct uaddr_hint_state *)uaddr_param; - vsize_t before_gap, after_gap; - vaddr_t low, high; - int dir; - - if (hint == 0) - return ENOMEM; - - /* Calculate upper and lower bound for selected address. */ - high = hint + uaddr->max_dist; - if (high < hint) /* overflow */ - high = map->max_offset; - high = MIN(high, uaddr->uaddr.uaddr_maxaddr); - if (high < sz) - return ENOMEM; /* Protect against underflow. */ - high -= sz; - - /* Calculate lower bound for selected address. */ - low = hint - uaddr->max_dist; - if (low > hint) /* underflow */ - low = map->min_offset; - low = MAX(low, uaddr->uaddr.uaddr_minaddr); - - /* Search strategy setup. */ - before_gap = PAGE_SIZE + - (arc4random_uniform(UADDR_HINT_MAXGAP) & ~(vaddr_t)PAGE_MASK); - after_gap = PAGE_SIZE + - (arc4random_uniform(UADDR_HINT_MAXGAP) & ~(vaddr_t)PAGE_MASK); - dir = (arc4random() & 0x01) ? 1 : -1; - - /* - * Try to search: - * - forward, with gap - * - backward, with gap - * - forward, without gap - * - backward, without gap - * (Where forward is in the direction specified by dir and - * backward is in the direction specified by -dir). - */ - if (uvm_addr_linsearch(map, uaddr_param, - entry_out, addr_out, hint, sz, align, offset, - dir, low, high, before_gap, after_gap) == 0) - return 0; - if (uvm_addr_linsearch(map, uaddr_param, - entry_out, addr_out, hint, sz, align, offset, - -dir, low, high, before_gap, after_gap) == 0) - return 0; - - if (uvm_addr_linsearch(map, uaddr_param, - entry_out, addr_out, hint, sz, align, offset, - dir, low, high, 0, 0) == 0) - return 0; - if (uvm_addr_linsearch(map, uaddr_param, - entry_out, addr_out, hint, sz, align, offset, - -dir, low, high, 0, 0) == 0) - return 0; - - return ENOMEM; -} - -/* * Kernel allocation bootstrap logic. */ const struct uvm_addr_functions uaddr_kernel_functions = { @@ -1242,9 +1118,16 @@ uaddr_pivot_select(struct vm_map *map, s vsize_t before_gap, after_gap; int err; - /* Hint must be handled by dedicated hint allocator. */ - if (hint != 0) - return EINVAL; + /* + * When we have a hint, use the rnd allocator that finds the + * area that is closest to the hint, if there is such an area. + */ + if (hint != 0) { + if (uaddr_rnd_select(map, uaddr_p, entry_out, addr_out, + sz, align, offset, prot, hint) == 0) + return 0; + return ENOMEM; + } /* * Select a random pivot and a random gap sizes around the allocation. Index: uvm/uvm_addr.h =================================================================== RCS file: /cvs/src/sys/uvm/uvm_addr.h,v retrieving revision 1.6 diff -u -p -r1.6 uvm_addr.h --- uvm/uvm_addr.h 16 Sep 2016 01:51:40 -0000 1.6 +++ uvm/uvm_addr.h 14 Jan 2017 05:53:17 -0000 @@ -90,7 +90,6 @@ int uvm_addr_invoke(struct vm_map *, struct uvm_addr_state *uaddr_lin_create(vaddr_t, vaddr_t); #endif struct uvm_addr_state *uaddr_rnd_create(vaddr_t, vaddr_t); -struct uvm_addr_state *uaddr_hint_create(vaddr_t, vaddr_t, vsize_t); #ifndef SMALL_KERNEL struct uvm_addr_state *uaddr_bestfit_create(vaddr_t, vaddr_t); struct uvm_addr_state *uaddr_pivot_create(vaddr_t, vaddr_t); Index: uvm/uvm_map.c =================================================================== RCS file: /cvs/src/sys/uvm/uvm_map.c,v retrieving revision 1.226 diff -u -p -r1.226 uvm_map.c --- uvm/uvm_map.c 7 Nov 2016 00:26:33 -0000 1.226 +++ uvm/uvm_map.c 14 Jan 2017 05:53:18 -0000 @@ -5291,9 +5291,6 @@ uvm_map_setup_md(struct vm_map *map) min = VMMAP_MIN_ADDR; #if 0 /* Cool stuff, not yet */ - /* Hinted allocations. */ - map->uaddr_any[1] = uaddr_hint_create(min, max, 1024 * 1024 * 1024); - /* Executable code is special. */ map->uaddr_exe = uaddr_rnd_create(min, I386_MAX_EXE_ADDR); /* Place normal allocations beyond executable mappings. */ @@ -5323,13 +5320,6 @@ uvm_map_setup_md(struct vm_map *map) min = VMMAP_MIN_ADDR; #if 0 /* Cool stuff, not yet */ - /* Hinted allocations above 4GB */ - map->uaddr_any[0] = - uaddr_hint_create(0x100000000ULL, max, 1024 * 1024 * 1024); - /* Hinted allocations below 4GB */ - map->uaddr_any[1] = uaddr_hint_create(min, 0x100000000ULL, - 1024 * 1024 * 1024); - /* Normal allocations, always above 4GB */ map->uaddr_any[3] = uaddr_pivot_create(MAX(min, 0x100000000ULL), max); #else /* Crappy stuff, for now */ map->uaddr_any[0] = uaddr_rnd_create(min, max); @@ -5356,9 +5346,6 @@ uvm_map_setup_md(struct vm_map *map) min = VMMAP_MIN_ADDR; #if 0 /* Cool stuff, not yet */ - /* Hinted allocations. */ - map->uaddr_any[1] = uaddr_hint_create(min, max, 1024 * 1024 * 1024); - /* Normal allocations. */ map->uaddr_any[3] = uaddr_pivot_create(min, max); #else /* Crappy stuff, for now */ map->uaddr_any[0] = uaddr_rnd_create(min, max);