> Date: Tue, 16 Jun 2015 14:28:22 +0000
> From: Visa Hankala <[email protected]>
>
> The uvm_pmr_get1page() function can fail even when there are suitable
> free pages available. If there is no hit in the list of single pages in
> a pmemrange, the function continues the lookup in the address tree.
> The function takes the root of a size-sorted tree as the starting point
> for the address tree search. Because the chosen root node is likely to
> cover only a part of the whole address tree, the tree lookup might be
> incomplete. This seems to be a mistake that was made while refactoring
> uvm_pmemrange.c between revisions 1.8 and 1.10.
>
> The patch below changes the logic to always use the address tree root.
> I have tested it on amd64, i386 and octeon.
>
> The issue appears to get masked easily in a running system because
> there tend to be enough pages in circulation. I happened to notice it
> while I was playing with an EdgeRouter Lite to get the full 512 MiB of
> RAM usable. After having removed the #if 0's, in file
> arch/octeon/octeon/machdep.c, that disable the second 256 MiB, the
> system kept on hanging during the early steps of the init process. An
> execve() call tried to allocate DMA'ble pages of memory, and this is
> where uvm_pmr_get1page() failed. Due to bad luck, there always were an
> address tree lookup that happened to process only the part of the tree
> that did not meet the address constraints. The process ended up waiting
> for the page daemon, and nothing was to happen since there were no
> other process to release a suitable page.
>
> With the patch, and the #if 0's removed, the EdgeRouter Lite has run
> stably with the full memory available and completed several make build
> cycles successfully.
You're definitely on to something. It certainly looks like your diff
fixes the bug. However, if there is no constraint, it would make
sense to pick a page from the size tree of the right type. Not sure
if that optimization would really matter though.
> Index: uvm/uvm_pmemrange.c
> ===================================================================
> RCS file: src/sys/uvm/uvm_pmemrange.c,v
> retrieving revision 1.44
> diff -u -p -r1.44 uvm_pmemrange.c
> --- uvm/uvm_pmemrange.c 13 Nov 2014 00:47:44 -0000 1.44
> +++ uvm/uvm_pmemrange.c 16 Jun 2015 10:36:53 -0000
> @@ -1708,11 +1708,8 @@ uvm_pmr_get1page(psize_t count, int memt
> found = TAILQ_NEXT(found, pageq);
>
> if (found == NULL) {
> - found = RB_ROOT(&pmr->size[memtype]);
> - /* Size tree gives pg[1] instead of pg[0] */
> + found = RB_ROOT(&pmr->addr);
> if (found != NULL) {
> - found--;
> -
> found = uvm_pmr_rootupdate(pmr, found,
> start, end, memtype);
> }
>
>