看板 DFBSD_submit 關於我們 聯絡資訊
Improved version - aligns better with caller's M_*WAIT* semantics. Final version hopefully - looking for feedback :) ... Andrew. --- vm_contig.c.old 2004-11-10 15:19:51.000000000 -0500 +++ vm_contig.c 2005-02-21 15:55:48.000000000 -0500 @@ -179,7 +179,22 @@ } /* - * vm_contig_pg_alloc: + * vm_contig_pg_flush: + * + * Attempt to flush (count) pages from the given page queue. + * + * Return TRUE on success + */ +static int +vm_contig_pg_flush( int queue, int count ) { + for ( ; count > 0 ; count-- ) { + if (! vm_contig_pg_clean( queue ) ) + break; + } + return (count > 0); +} +/* + * vm_contig_int_pg_alloc: * * Allocate contiguous pages from the VM. This function does not * map the allocated pages into the kernel map, otherwise it is @@ -189,13 +204,14 @@ * statistics and for allocations of less than a page. * */ -int -vm_contig_pg_alloc( +static int +vm_contig_int_pg_alloc( unsigned long size, vm_paddr_t low, vm_paddr_t high, unsigned long alignment, - unsigned long boundary) + unsigned long boundary, + unsigned int mflags ) { int i, start, pass; vm_offset_t phys; @@ -212,8 +228,10 @@ panic("vm_contig_pg_alloc: boundary must be a power of 2"); start = 0; - for (pass = 0; pass <= 1; pass++) { - crit_enter(); + + crit_enter(); + + for (pass = 0; pass <= 2; pass++) { again: /* * Find first page in array that is free, within range, aligned, and @@ -244,13 +262,40 @@ if ((i == vmstats.v_page_count) || ((VM_PAGE_TO_PHYS(&pga[i]) + size) > high)) { -again1: - if (vm_contig_pg_clean(PQ_INACTIVE)) - goto again1; - if (vm_contig_pg_clean(PQ_ACTIVE)) - goto again1; + /* + * Best effort flush of all inactive pages. + * This is quite quick, for now stall all + * callers, even if they've specified M_NOWAIT. + */ + if ( !vm_contig_pg_flush( PQ_INACTIVE, + vmstats.v_inactive_count ) ) { + crit_exit(); /* give interrupts a chance */ + crit_enter(); + } + + /* + * Best effort flush of active pages. + * + * This is very, very slow. + * Only do this if the caller has agreed to M_WAITOK. + * + * If enough pages are flushed, we may succeed on + * next (final) pass, if not the caller, contigmalloc(), + * will fail in the index < 0 case. + */ + if ( pass > 0 && (mflags & M_WAITOK) ) { + vm_contig_pg_flush( PQ_ACTIVE, + vmstats.v_active_count); + } + + crit_exit(); /* give interrupts a chance */ - crit_exit(); + /* + * We're already too high in the address space + * to succeed, reset to 0 for the next iteration. + */ + start = 0; + crit_enter(); continue; /* next pass */ } start = i; @@ -311,6 +356,30 @@ return (-1); } + +/* + * vm_contig_pg_alloc: + * + * Allocate contiguous pages from the VM. This function does not + * map the allocated pages into the kernel map, otherwise it is + * impossible to make large allocations (i.e. >2G). + * + * Malloc()'s data structures have been used for collection of + * statistics and for allocations of less than a page. + * + */ +int +vm_contig_pg_alloc( + unsigned long size, + vm_paddr_t low, + vm_paddr_t high, + unsigned long alignment, + unsigned long boundary) +{ + return vm_contig_int_pg_alloc(size, low, high, + alignment, boundary, M_WAITOK); +} + /* * vm_contig_pg_free: * @@ -423,7 +492,7 @@ int index; void *rv; - index = vm_contig_pg_alloc(size, low, high, alignment, boundary); + index = vm_contig_int_pg_alloc(size, low, high, alignment, boundary, flags); if (index < 0) { printf("contigmalloc_map: failed in index < 0 case!"); return NULL;