diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -668,6 +668,9 @@ vm_paddr_t high, u_long alignment, vm_paddr_t boundary); bool vm_page_reclaim_contig_domain(int domain, int req, u_long npages, vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary); +bool vm_page_reclaim_contig_domain_ext(int domain, int req, u_long npages, + vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary, + int num_runs); void vm_page_reference(vm_page_t m); #define VPR_TRYFREE 0x01 #define VPR_NOREUSE 0x02 diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -2995,9 +2995,7 @@ #define NRUNS 16 -CTASSERT(powerof2(NRUNS)); - -#define RUN_INDEX(count) ((count) & (NRUNS - 1)) +#define RUN_INDEX(count, nruns) ((count) % (nruns)) #define MIN_RECLAIM 8 @@ -3025,19 +3023,42 @@ * must be a power of two. */ bool -vm_page_reclaim_contig_domain(int domain, int req, u_long npages, - vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary) +vm_page_reclaim_contig_domain_ext(int domain, int req, u_long npages, + vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary, + int num_runs) { struct vm_domain *vmd; vm_paddr_t curr_low; - vm_page_t m_run, m_runs[NRUNS]; + vm_page_t m_run, _m_runs[NRUNS], *m_runs; u_long count, minalign, reclaimed; - int error, i, options, req_class; + int error, i, min_reclaim, options, req_class, runsize; + bool ret; KASSERT(npages > 0, ("npages is 0")); KASSERT(powerof2(alignment), ("alignment is not a power of 2")); KASSERT(powerof2(boundary), ("boundary is not a power of 2")); + ret = false; + /* + * If the caller wants to reclaim multiple runs, try to allocate + * space to store the runs. If that fails, fall back to the old + * behavior of just reclaiming MIN_RECLAIM pages. + */ + if (num_runs > 1) + m_runs = malloc(num_runs * sizeof(*m_runs), M_TEMP, M_NOWAIT); + else + m_runs = NULL; + + if (m_runs == NULL) { + m_runs = _m_runs; + runsize = NRUNS; + min_reclaim = MIN_RECLAIM; + } else { + runsize = num_runs; + min_reclaim = num_runs * npages; + } + + /* * The caller will attempt an allocation after some runs have been * reclaimed and added to the vm_phys buddy lists. Due to limitations @@ -3085,7 +3106,7 @@ if (m_run == NULL) break; curr_low = VM_PAGE_TO_PHYS(m_run) + ptoa(npages); - m_runs[RUN_INDEX(count)] = m_run; + m_runs[RUN_INDEX(count, runsize)] = m_run; count++; } @@ -3097,15 +3118,17 @@ * from one scan to the next as restrictions are relaxed. */ reclaimed = 0; - for (i = 0; count > 0 && i < NRUNS; i++) { + for (i = 0; count > 0 && i < runsize; i++) { count--; - m_run = m_runs[RUN_INDEX(count)]; + m_run = m_runs[RUN_INDEX(count, runsize)]; error = vm_page_reclaim_run(req_class, domain, npages, m_run, high); if (error == 0) { reclaimed += npages; - if (reclaimed >= MIN_RECLAIM) - return (true); + if (reclaimed >= min_reclaim) { + ret = true; + goto done; + } } } @@ -3117,11 +3140,24 @@ options = VPSC_NOSUPER; else if (options == VPSC_NOSUPER) options = VPSC_ANY; - else if (options == VPSC_ANY) - return (reclaimed != 0); + else if (options == VPSC_ANY) { + ret = reclaimed != 0; + goto done; + } } +done: + if (m_runs != _m_runs) + free(m_runs, M_TEMP); + return (ret); } +bool +vm_page_reclaim_contig_domain(int domain, int req, u_long npages, + vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary) +{ + return (vm_page_reclaim_contig_domain_ext(domain, req, npages, low, high, + alignment, boundary, 1)); +} bool vm_page_reclaim_contig(int req, u_long npages, vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary)