diff options
-rw-r--r-- | sys/vm/swap_pager.c | 245 | ||||
-rw-r--r-- | sys/vm/swap_pager.h | 3 | ||||
-rw-r--r-- | sys/vm/vm_fault.c | 16 | ||||
-rw-r--r-- | sys/vm/vm_glue.c | 8 | ||||
-rw-r--r-- | sys/vm/vm_kern.c | 14 | ||||
-rw-r--r-- | sys/vm/vm_map.c | 29 | ||||
-rw-r--r-- | sys/vm/vm_object.c | 278 | ||||
-rw-r--r-- | sys/vm/vm_object.h | 21 | ||||
-rw-r--r-- | sys/vm/vm_page.c | 34 | ||||
-rw-r--r-- | sys/vm/vm_pageout.c | 12 |
10 files changed, 373 insertions, 287 deletions
diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c index da751f3..491abf2 100644 --- a/sys/vm/swap_pager.c +++ b/sys/vm/swap_pager.c @@ -39,7 +39,7 @@ * from: Utah $Hdr: swap_pager.c 1.4 91/04/30$ * * @(#)swap_pager.c 8.9 (Berkeley) 3/21/94 - * $Id: swap_pager.c,v 1.23 1995/01/10 07:32:43 davidg Exp $ + * $Id: swap_pager.c,v 1.24 1995/01/24 10:12:12 davidg Exp $ */ /* @@ -115,6 +115,7 @@ struct pagerlst swap_pager_list; /* list of "named" anon regions */ struct pagerlst swap_pager_un_list; /* list of "unnamed" anon pagers */ #define SWAP_FREE_NEEDED 0x1 /* need a swap block */ +#define SWAP_FREE_NEEDED_BY_PAGEOUT 0x2 int swap_pager_needflags; struct rlist *swapfrag; @@ -146,7 +147,7 @@ static inline void swapsizecheck() { if (vm_swap_size < 128 * btodb(PAGE_SIZE)) { - if (swap_pager_full) + if (swap_pager_full == 0) printf("swap_pager: out of space\n"); swap_pager_full = 1; } else if (vm_swap_size > 192 * btodb(PAGE_SIZE)) @@ -200,14 +201,6 @@ swap_pager_alloc(handle, size, prot, offset) swp_clean_t spc; struct buf *bp; -#if 0 - int desiredpendingio; - - desiredpendingio = cnt.v_page_count / 200 + 2; - if (desiredpendingio < npendingio) - npendingio = desiredpendingio; -#endif - /* * kva's are allocated here so that we dont need to keep doing * kmem_alloc pageables at runtime @@ -217,7 +210,7 @@ swap_pager_alloc(handle, size, prot, offset) if (!spc->spc_kva) { break; } - spc->spc_bp = malloc(sizeof(*bp), M_TEMP, M_NOWAIT); + spc->spc_bp = malloc(sizeof(*bp), M_TEMP, M_KERNEL); if (!spc->spc_bp) { kmem_free_wakeup(pager_map, spc->spc_kva, PAGE_SIZE); break; @@ -249,7 +242,7 @@ swap_pager_alloc(handle, size, prot, offset) * Pager doesn't exist, allocate swap management resources and * initialize. */ - waitok = handle ? M_WAITOK : M_NOWAIT; + waitok = handle ? M_WAITOK : M_KERNEL; pager = (vm_pager_t) malloc(sizeof *pager, M_VMPAGER, waitok); if (pager == NULL) return (NULL); @@ -277,6 +270,7 @@ swap_pager_alloc(handle, size, prot, offset) } swp->sw_poip = 0; + swp->sw_allocsize = 0; if (handle) { vm_object_t object; @@ -308,7 +302,7 @@ swap_pager_alloc(handle, size, prot, offset) * if the block has been written */ -static int * +inline static int * swap_pager_diskaddr(swp, offset, valid) sw_pager_t swp; vm_offset_t offset; @@ -320,7 +314,8 @@ swap_pager_diskaddr(swp, offset, valid) if (valid) *valid = 0; ix = offset / (SWB_NPAGES * PAGE_SIZE); - if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) { + if ((swp->sw_blocks == NULL) || (ix >= swp->sw_nblocks) || + (offset >= swp->sw_osize)) { return (FALSE); } swb = &swp->sw_blocks[ix]; @@ -361,7 +356,7 @@ swap_pager_setvalid(swp, offset, valid) * minimization policy. */ int -swap_pager_getswapspace(unsigned amount, unsigned *rtval) +swap_pager_getswapspace(sw_pager_t swp, unsigned amount, unsigned *rtval) { vm_swap_size -= amount; if (!rlist_alloc(&swaplist, amount, rtval)) { @@ -369,6 +364,7 @@ swap_pager_getswapspace(unsigned amount, unsigned *rtval) return 0; } else { swapsizecheck(); + swp->sw_allocsize += amount; return 1; } } @@ -378,10 +374,11 @@ swap_pager_getswapspace(unsigned amount, unsigned *rtval) * minimization policy. */ void -swap_pager_freeswapspace(unsigned from, unsigned to) +swap_pager_freeswapspace(sw_pager_t swp, unsigned from, unsigned to) { rlist_free(&swaplist, from, to); vm_swap_size += (to - from) + 1; + swp->sw_allocsize -= (to - from) + 1; swapsizecheck(); } /* @@ -402,7 +399,7 @@ _swap_pager_freespace(swp, start, size) int *addr = swap_pager_diskaddr(swp, i, &valid); if (addr && *addr != SWB_EMPTY) { - swap_pager_freeswapspace(*addr, *addr + btodb(PAGE_SIZE) - 1); + swap_pager_freeswapspace(swp, *addr, *addr + btodb(PAGE_SIZE) - 1); if (valid) { swap_pager_setvalid(swp, i, 0); } @@ -421,6 +418,56 @@ swap_pager_freespace(pager, start, size) _swap_pager_freespace((sw_pager_t) pager->pg_data, start, size); } +static void +swap_pager_free_swap(swp) + sw_pager_t swp; +{ + register int i, j; + register sw_blk_t bp; + int first_block=0, block_count=0; + int s; + /* + * Free left over swap blocks + */ + s = splbio(); + for (i = 0, bp = swp->sw_blocks; i < swp->sw_nblocks; i++, bp++) { + for (j = 0; j < SWB_NPAGES; j++) { + if (bp->swb_block[j] != SWB_EMPTY) { + /* + * initially the length of the run is zero + */ + if( block_count == 0) { + first_block = bp->swb_block[j]; + block_count = btodb(PAGE_SIZE); + bp->swb_block[j] = SWB_EMPTY; + /* + * if the new block can be included into the current run + */ + } else if( bp->swb_block[j] == first_block + block_count) { + block_count += btodb(PAGE_SIZE); + bp->swb_block[j] = SWB_EMPTY; + /* + * terminate the previous run, and start a new one + */ + } else { + swap_pager_freeswapspace(swp, first_block, + (unsigned) first_block + block_count - 1); + first_block = bp->swb_block[j]; + block_count = btodb(PAGE_SIZE); + bp->swb_block[j] = SWB_EMPTY; + } + } + } + } + + if( block_count) { + swap_pager_freeswapspace(swp, first_block, + (unsigned) first_block + block_count - 1); + } + splx(s); +} + + /* * swap_pager_reclaim frees up over-allocated space from all pagers * this eliminates internal fragmentation due to allocation of space @@ -432,7 +479,7 @@ swap_pager_freespace(pager, start, size) /* * Maximum number of blocks (pages) to reclaim per pass */ -#define MAXRECLAIM 256 +#define MAXRECLAIM 128 void swap_pager_reclaim() @@ -442,7 +489,10 @@ swap_pager_reclaim() int i, j, k; int s; int reclaimcount; - static int reclaims[MAXRECLAIM]; + static struct { + int address; + sw_pager_t pager; + } reclaims[MAXRECLAIM]; static int in_reclaim; /* @@ -476,7 +526,8 @@ swap_pager_reclaim() for (j = 0; j < SWB_NPAGES; j++) { if (swb->swb_block[j] != SWB_EMPTY && (swb->swb_valid & (1 << j)) == 0) { - reclaims[reclaimcount++] = swb->swb_block[j]; + reclaims[reclaimcount].address = swb->swb_block[j]; + reclaims[reclaimcount++].pager = swp; swb->swb_block[j] = SWB_EMPTY; if (reclaimcount >= MAXRECLAIM) goto rfinished; @@ -493,10 +544,8 @@ rfinished: * free the blocks that have been added to the reclaim list */ for (i = 0; i < reclaimcount; i++) { - swap_pager_freeswapspace(reclaims[i], reclaims[i] + btodb(PAGE_SIZE) - 1); - wakeup((caddr_t) &in_reclaim); + swap_pager_freeswapspace(reclaims[i].pager, reclaims[i].address, reclaims[i].address + btodb(PAGE_SIZE) - 1); } - splx(s); in_reclaim = 0; wakeup((caddr_t) &in_reclaim); @@ -518,6 +567,7 @@ swap_pager_copy(srcpager, srcoffset, dstpager, dstoffset, offset) { sw_pager_t srcswp, dstswp; vm_offset_t i; + int origsize; int s; if (vm_swap_size) @@ -527,6 +577,7 @@ swap_pager_copy(srcpager, srcoffset, dstpager, dstoffset, offset) return; srcswp = (sw_pager_t) srcpager->pg_data; + origsize = srcswp->sw_allocsize; dstswp = (sw_pager_t) dstpager->pg_data; /* @@ -552,25 +603,12 @@ swap_pager_copy(srcpager, srcoffset, dstpager, dstoffset, offset) s = splbio(); /* - * clear source block before destination object - * (release allocated space) - */ - for (i = 0; i < offset + srcoffset; i += PAGE_SIZE) { - int valid; - int *addr = swap_pager_diskaddr(srcswp, i, &valid); - - if (addr && *addr != SWB_EMPTY) { - swap_pager_freeswapspace(*addr, *addr + btodb(PAGE_SIZE) - 1); - *addr = SWB_EMPTY; - } - } - /* * transfer source to destination */ for (i = 0; i < dstswp->sw_osize; i += PAGE_SIZE) { int srcvalid, dstvalid; int *srcaddrp = swap_pager_diskaddr(srcswp, i + offset + srcoffset, - &srcvalid); + &srcvalid); int *dstaddrp; /* @@ -583,19 +621,23 @@ swap_pager_copy(srcpager, srcoffset, dstpager, dstoffset, offset) * dest. */ if (srcvalid) { - dstaddrp = swap_pager_diskaddr(dstswp, i + dstoffset, &dstvalid); + dstaddrp = swap_pager_diskaddr(dstswp, i + dstoffset, + &dstvalid); /* * if the dest already has a valid block, * deallocate the source block without * copying. */ if (!dstvalid && dstaddrp && *dstaddrp != SWB_EMPTY) { - swap_pager_freeswapspace(*dstaddrp, *dstaddrp + btodb(PAGE_SIZE) - 1); + swap_pager_freeswapspace(dstswp, *dstaddrp, + *dstaddrp + btodb(PAGE_SIZE) - 1); *dstaddrp = SWB_EMPTY; } if (dstaddrp && *dstaddrp == SWB_EMPTY) { *dstaddrp = *srcaddrp; *srcaddrp = SWB_EMPTY; + dstswp->sw_allocsize += btodb(PAGE_SIZE); + srcswp->sw_allocsize -= btodb(PAGE_SIZE); swap_pager_setvalid(dstswp, i + dstoffset, 1); } } @@ -604,27 +646,21 @@ swap_pager_copy(srcpager, srcoffset, dstpager, dstoffset, offset) * deallocate the space. */ if (*srcaddrp != SWB_EMPTY) { - swap_pager_freeswapspace(*srcaddrp, *srcaddrp + btodb(PAGE_SIZE) - 1); + swap_pager_freeswapspace(srcswp, *srcaddrp, + *srcaddrp + btodb(PAGE_SIZE) - 1); *srcaddrp = SWB_EMPTY; } } } + splx(s); /* - * deallocate the rest of the source object + * Free left over swap blocks */ - for (i = dstswp->sw_osize + offset + srcoffset; i < srcswp->sw_osize; i += PAGE_SIZE) { - int valid; - int *srcaddrp = swap_pager_diskaddr(srcswp, i, &valid); - - if (srcaddrp && *srcaddrp != SWB_EMPTY) { - swap_pager_freeswapspace(*srcaddrp, *srcaddrp + btodb(PAGE_SIZE) - 1); - *srcaddrp = SWB_EMPTY; - } - } - - splx(s); + swap_pager_free_swap(srcswp); + if( srcswp->sw_allocsize) + printf("swap_pager_copy: *warning* pager with %d blocks (orig: %d)\n", srcswp->sw_allocsize, origsize); free((caddr_t) srcswp->sw_blocks, M_VMPGDATA); srcswp->sw_blocks = 0; free((caddr_t) srcswp, M_VMPGDATA); @@ -634,13 +670,10 @@ swap_pager_copy(srcpager, srcoffset, dstpager, dstoffset, offset) return; } - void swap_pager_dealloc(pager) vm_pager_t pager; { - register int i, j; - register sw_blk_t bp; register sw_pager_t swp; int s; @@ -672,17 +705,10 @@ swap_pager_dealloc(pager) /* * Free left over swap blocks */ - s = splbio(); - for (i = 0, bp = swp->sw_blocks; i < swp->sw_nblocks; i++, bp++) { - for (j = 0; j < SWB_NPAGES; j++) - if (bp->swb_block[j] != SWB_EMPTY) { - swap_pager_freeswapspace((unsigned) bp->swb_block[j], - (unsigned) bp->swb_block[j] + btodb(PAGE_SIZE) - 1); - bp->swb_block[j] = SWB_EMPTY; - } - } - splx(s); + swap_pager_free_swap(swp); + if( swp->sw_allocsize) + printf("swap_pager_dealloc: *warning* freeing pager with %d blocks\n", swp->sw_allocsize); /* * Free swap management resources */ @@ -871,10 +897,6 @@ swap_pager_iodone1(bp) bp->b_flags |= B_DONE; bp->b_flags &= ~B_ASYNC; wakeup((caddr_t) bp); -/* - if ((bp->b_flags & B_READ) == 0) - vwakeup(bp); -*/ } @@ -997,7 +1019,7 @@ swap_pager_input(swp, m, count, reqpage) spc = NULL; /* we might not use an spc data structure */ - if (count == 1) { + if ((count == 1) && (swap_pager_free.tqh_first != NULL)) { /* * if a kva has not been allocated, we can only do a one page * transfer, so we free the other pages that might have been @@ -1021,6 +1043,8 @@ swap_pager_input(swp, m, count, reqpage) wakeup((caddr_t) &vm_pages_needed); while (swap_pager_free.tqh_first == NULL) { swap_pager_needflags |= SWAP_FREE_NEEDED; + if (curproc == pageproc) + swap_pager_needflags |= SWAP_FREE_NEEDED_BY_PAGEOUT; tsleep((caddr_t) &swap_pager_free, PVM, "swpfre", 0); if (curproc == pageproc) @@ -1119,9 +1143,11 @@ swap_pager_input(swp, m, count, reqpage) crfree(bp->b_wcred); TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); if (swap_pager_needflags & SWAP_FREE_NEEDED) { - swap_pager_needflags &= ~SWAP_FREE_NEEDED; wakeup((caddr_t) &swap_pager_free); } + if( swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) + wakeup((caddr_t) &vm_pages_needed); + swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); } else { /* * release the physical I/O buffer @@ -1144,12 +1170,7 @@ swap_pager_input(swp, m, count, reqpage) * results, it is best to deactivate * the readahead pages. */ -/* - if (sequential || (i == reqpage - 1) || (i == reqpage + 1)) - vm_page_activate(m[i]); - else -*/ - vm_page_deactivate(m[i]); + vm_page_deactivate(m[i]); /* * just in case someone was asking for @@ -1258,12 +1279,12 @@ swap_pager_output(swp, m, count, flags, rtvals) * intent of this code is to allocate small chunks for * small objects) */ - if ((m[j]->offset == 0) && (ntoget * PAGE_SIZE > object->size)) { + if (ntoget * PAGE_SIZE > object->size) { ntoget = (object->size + (PAGE_SIZE - 1)) / PAGE_SIZE; } retrygetspace: if (!swap_pager_full && ntoget > 1 && - swap_pager_getswapspace(ntoget * btodb(PAGE_SIZE), &blk)) { + swap_pager_getswapspace(swp, ntoget * btodb(PAGE_SIZE), &blk)) { for (i = 0; i < ntoget; i++) { swb[j]->swb_block[i] = blk + btodb(PAGE_SIZE) * i; @@ -1271,7 +1292,7 @@ swap_pager_output(swp, m, count, flags, rtvals) } reqaddr[j] = swb[j]->swb_block[off]; - } else if (!swap_pager_getswapspace(btodb(PAGE_SIZE), + } else if (!swap_pager_getswapspace(swp, btodb(PAGE_SIZE), &swb[j]->swb_block[off])) { /* * if the allocation has failed, we try to @@ -1327,9 +1348,6 @@ swap_pager_output(swp, m, count, flags, rtvals) } /* - * */ - - /* * For synchronous writes, we clean up all completed async pageouts. */ if ((flags & B_ASYNC) == 0) { @@ -1338,45 +1356,28 @@ swap_pager_output(swp, m, count, flags, rtvals) kva = 0; /* - * we allocate a new kva for transfers > 1 page but for transfers == 1 - * page, the swap_pager_free list contains entries that have - * pre-allocated kva's (for efficiency). NOTE -- we do not use the - * physical buffer pool or the preallocated associated kva's because - * of the potential for deadlock. This is very subtile -- but - * deadlocks or resource contention must be avoided on pageouts -- or - * your system will sleep (forever) !!! - */ -/* - if ( count > 1) { - kva = kmem_alloc_pageable(pager_map, count*PAGE_SIZE); - if( !kva) { - for (i = 0; i < count; i++) { - if( swb[i]) - --swb[i]->swb_locked; - rtvals[i] = VM_PAGER_AGAIN; - } - return VM_PAGER_AGAIN; - } - } -*/ - - /* * get a swap pager clean data structure, block until we get it */ - if (swap_pager_free.tqh_first == NULL || swap_pager_free.tqh_first->spc_list.tqe_next == NULL || swap_pager_free.tqh_first->spc_list.tqe_next->spc_list.tqe_next == NULL) { + if (swap_pager_free.tqh_first == NULL || + swap_pager_free.tqh_first->spc_list.tqe_next == NULL || + swap_pager_free.tqh_first->spc_list.tqe_next->spc_list.tqe_next == NULL) { s = splbio(); if (curproc == pageproc) { (void) swap_pager_clean(); -/* +#if 0 splx(s); return VM_PAGER_AGAIN; -*/ +#endif } else wakeup((caddr_t) &vm_pages_needed); - while (swap_pager_free.tqh_first == NULL || swap_pager_free.tqh_first->spc_list.tqe_next == NULL || swap_pager_free.tqh_first->spc_list.tqe_next->spc_list.tqe_next == NULL) { - if (curproc == pageproc && - (cnt.v_free_count + cnt.v_cache_count) >= cnt.v_free_min) - wakeup((caddr_t) &cnt.v_free_count); + while (swap_pager_free.tqh_first == NULL || + swap_pager_free.tqh_first->spc_list.tqe_next == NULL || + swap_pager_free.tqh_first->spc_list.tqe_next->spc_list.tqe_next == NULL) { + if (curproc == pageproc) { + swap_pager_needflags |= SWAP_FREE_NEEDED_BY_PAGEOUT; + if((cnt.v_free_count + cnt.v_cache_count) > cnt.v_free_reserved) + wakeup((caddr_t) &cnt.v_free_count); + } swap_pager_needflags |= SWAP_FREE_NEEDED; tsleep((caddr_t) &swap_pager_free, @@ -1538,9 +1539,11 @@ swap_pager_output(swp, m, count, flags, rtvals) crfree(bp->b_wcred); TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); if (swap_pager_needflags & SWAP_FREE_NEEDED) { - swap_pager_needflags &= ~SWAP_FREE_NEEDED; wakeup((caddr_t) &swap_pager_free); } + if( swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) + wakeup((caddr_t) &vm_pages_needed); + swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); return (rv); } @@ -1584,9 +1587,11 @@ doclean: spc->spc_flags = 0; TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); if (swap_pager_needflags & SWAP_FREE_NEEDED) { - swap_pager_needflags &= ~SWAP_FREE_NEEDED; wakeup((caddr_t) &swap_pager_free); } + if( swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) + wakeup((caddr_t) &vm_pages_needed); + swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); ++cleandone; splx(s); } @@ -1656,10 +1661,6 @@ swap_pager_iodone(bp) (bp->b_flags & B_READ) ? "pagein" : "pageout", bp->b_error, (u_long) bp->b_blkno, bp->b_bcount); } -/* - if ((bp->b_flags & B_READ) == 0) - vwakeup(bp); -*/ if (bp->b_vp) pbrelvp(bp); @@ -1680,10 +1681,16 @@ swap_pager_iodone(bp) swap_pager_inuse.tqh_first == 0) { swap_pager_needflags &= ~SWAP_FREE_NEEDED; wakeup((caddr_t) &swap_pager_free); + } + + if( swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) { + swap_pager_needflags &= ~SWAP_FREE_NEEDED_BY_PAGEOUT; wakeup((caddr_t) &vm_pages_needed); } + if (vm_pageout_pages_needed) { wakeup((caddr_t) &vm_pageout_pages_needed); + vm_pageout_pages_needed = 0; } if ((swap_pager_inuse.tqh_first == NULL) || ((cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_min && diff --git a/sys/vm/swap_pager.h b/sys/vm/swap_pager.h index c1bc8c8..d14d0e1 100644 --- a/sys/vm/swap_pager.h +++ b/sys/vm/swap_pager.h @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * from: @(#)swap_pager.h 7.1 (Berkeley) 12/5/90 - * $Id: swap_pager.h,v 1.3 1994/10/09 01:52:06 phk Exp $ + * $Id: swap_pager.h,v 1.4 1995/01/09 16:05:37 davidg Exp $ */ /* @@ -69,6 +69,7 @@ typedef struct swblock *sw_blk_t; struct swpager { vm_size_t sw_osize; /* size of object we are backing (bytes) */ int sw_nblocks; /* number of blocks in list (sw_blk_t units) */ + int sw_allocsize; /* amount of space actually allocated */ sw_blk_t sw_blocks; /* pointer to list of swap blocks */ short sw_flags; /* flags */ short sw_poip; /* pageouts in progress */ diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c index 9483c6e..1e0b426 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -66,7 +66,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: vm_fault.c,v 1.16 1995/01/24 10:12:29 davidg Exp $ + * $Id: vm_fault.c,v 1.17 1995/01/26 01:40:04 davidg Exp $ */ /* @@ -376,10 +376,6 @@ readrest: * if moved. */ m = vm_page_lookup(object, offset); - if (!m) { - printf("vm_fault: error fetching offset: %lx (fc: %d, rq: %d)\n", - offset, faultcount, reqpage); - } m->valid = VM_PAGE_BITS_ALL; pmap_clear_modify(VM_PAGE_TO_PHYS(m)); hardfault++; @@ -857,7 +853,7 @@ RetryCopy: vm_page_activate(m); } - if (curproc && curproc->p_stats) { + if (curproc && (curproc->p_flag & P_INMEM) && curproc->p_stats) { if (hardfault) { curproc->p_stats->p_ru.ru_majflt++; } else { @@ -908,11 +904,11 @@ vm_fault_wire(map, start, end) for (va = start; va < end; va += PAGE_SIZE) { - if( curproc != pageproc && + while( curproc != pageproc && (cnt.v_free_count <= cnt.v_pageout_free_min)) VM_WAIT; - rv = vm_fault(map, va, VM_PROT_NONE, TRUE); + rv = vm_fault(map, va, VM_PROT_READ|VM_PROT_WRITE, TRUE); if (rv) { if (va != start) vm_fault_unwire(map, start, va); @@ -1156,8 +1152,8 @@ vm_fault_additional_pages(first_object, first_offset, m, rbehind, raheada, marra * try to do any readahead that we might have free pages for. */ rahead = raheada; - if ((rahead + rbehind) > ((cnt.v_free_count + cnt.v_cache_count) - cnt.v_free_reserved)) { - rahead = ((cnt.v_free_count + cnt.v_cache_count) - cnt.v_free_reserved) / 2; + if ((rahead + rbehind) > ((cnt.v_free_count + cnt.v_cache_count) - 2*cnt.v_free_reserved)) { + rahead = ((cnt.v_free_count + cnt.v_cache_count) - 2*cnt.v_free_reserved) / 2; rbehind = rahead; if (!rahead) wakeup((caddr_t) &vm_pages_needed); diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c index 6ec7a1b..65dab97 100644 --- a/sys/vm/vm_glue.c +++ b/sys/vm/vm_glue.c @@ -59,7 +59,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: vm_glue.c,v 1.12 1995/01/10 07:32:45 davidg Exp $ + * $Id: vm_glue.c,v 1.13 1995/01/24 10:12:39 davidg Exp $ */ #include <sys/param.h> @@ -450,11 +450,13 @@ retry: if ((p->p_priority & 0x7f) < PSOCK) continue; + vm_map_reference(&p->p_vmspace->vm_map); /* * do not swapout a process that is waiting for VM * datastructures there is a possible deadlock. */ if (!lock_try_write(&p->p_vmspace->vm_map.lock)) { + vm_map_deallocate(&p->p_vmspace->vm_map); continue; } vm_map_unlock(&p->p_vmspace->vm_map); @@ -462,11 +464,13 @@ retry: * If the process has been asleep for awhile and had * most of its pages taken away already, swap it out. */ - if (p->p_slptime > maxslp) { + if (p->p_slptime > 4) { swapout(p); + vm_map_deallocate(&p->p_vmspace->vm_map); didswap++; goto retry; } + vm_map_deallocate(&p->p_vmspace->vm_map); } } /* diff --git a/sys/vm/vm_kern.c b/sys/vm/vm_kern.c index a1ef102..6d3e7b2 100644 --- a/sys/vm/vm_kern.c +++ b/sys/vm/vm_kern.c @@ -61,7 +61,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: vm_kern.c,v 1.8 1995/01/09 16:05:43 davidg Exp $ + * $Id: vm_kern.c,v 1.9 1995/01/24 10:12:51 davidg Exp $ */ /* @@ -72,6 +72,7 @@ #include <sys/systm.h> #include <sys/kernel.h> #include <sys/proc.h> +#include <sys/malloc.h> #include <vm/vm.h> #include <vm/vm_page.h> @@ -277,10 +278,10 @@ kmem_suballoc(parent, min, max, size, pageable) * for wired maps are statically allocated. */ vm_offset_t -kmem_malloc(map, size, canwait) +kmem_malloc(map, size, waitflag) register vm_map_t map; register vm_size_t size; - boolean_t canwait; + boolean_t waitflag; { register vm_offset_t offset, i; vm_map_entry_t entry; @@ -306,7 +307,7 @@ kmem_malloc(map, size, canwait) panic("kmem_malloc: %s too small", map == kmem_map ? "kmem_map" : "mb_map"); #endif - if (canwait) + if (waitflag == M_WAITOK) panic("kmem_malloc: map too small"); return (0); } @@ -318,7 +319,7 @@ kmem_malloc(map, size, canwait) * If we can wait, just mark the range as wired (will fault pages as * necessary). */ - if (canwait) { + if (waitflag == M_WAITOK) { vm_map_unlock(map); (void) vm_map_pageable(map, (vm_offset_t) addr, addr + size, FALSE); @@ -331,7 +332,8 @@ kmem_malloc(map, size, canwait) */ vm_object_lock(kmem_object); for (i = 0; i < size; i += PAGE_SIZE) { - m = vm_page_alloc(kmem_object, offset + i, VM_ALLOC_INTERRUPT); + m = vm_page_alloc(kmem_object, offset + i, + (waitflag == M_NOWAIT) ? VM_ALLOC_INTERRUPT : VM_ALLOC_SYSTEM); /* * Ran out of space, free everything up and return. Don't need diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 5ba5895..941b0dc 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -61,7 +61,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: vm_map.c,v 1.11 1995/01/10 07:32:46 davidg Exp $ + * $Id: vm_map.c,v 1.12 1995/01/24 10:13:02 davidg Exp $ */ /* @@ -216,6 +216,9 @@ vmspace_free(vm) register struct vmspace *vm; { + if (vm->vm_refcnt == 0) + panic("vmspace_free: attempt to free already freed vmspace"); + if (--vm->vm_refcnt == 0) { /* * Lock the map, to wait out all other references to it. @@ -225,6 +228,10 @@ vmspace_free(vm) vm_map_lock(&vm->vm_map); (void) vm_map_delete(&vm->vm_map, vm->vm_map.min_offset, vm->vm_map.max_offset); + vm_map_unlock(&vm->vm_map); + while( vm->vm_map.ref_count != 1) + tsleep(&vm->vm_map.ref_count, PVM, "vmsfre", 0); + --vm->vm_map.ref_count; pmap_release(&vm->vm_pmap); FREE(vm, M_VMMAP); } @@ -448,10 +455,15 @@ vm_map_deallocate(map) return; simple_lock(&map->ref_lock); - c = --map->ref_count; + c = map->ref_count; simple_unlock(&map->ref_lock); - if (c > 0) { + if (c == 0) + panic("vm_map_deallocate: deallocating already freed map"); + + if (c != 1) { + --map->ref_count; + wakeup((caddr_t) &map->ref_count); return; } /* @@ -459,11 +471,14 @@ vm_map_deallocate(map) */ vm_map_lock(map); - (void) vm_map_delete(map, map->min_offset, map->max_offset); + --map->ref_count; + if( map->ref_count != 0) { + vm_map_unlock(map); + return; + } pmap_destroy(map->pmap); - FREE(map, M_VMMAP); } @@ -1039,8 +1054,10 @@ vm_map_protect(map, start, end, new_prot, set_max) current = entry; while ((current != &map->header) && (current->start < end)) { - if (current->is_sub_map) + if (current->is_sub_map) { + vm_map_unlock(map); return (KERN_INVALID_ARGUMENT); + } if ((new_prot & current->max_protection) != new_prot) { vm_map_unlock(map); return (KERN_PROTECTION_FAILURE); diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index bbdb707..9d059e2 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -61,7 +61,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: vm_object.c,v 1.19 1995/01/24 10:13:14 davidg Exp $ + * $Id: vm_object.c,v 1.20 1995/01/25 20:36:29 davidg Exp $ */ /* @@ -82,9 +82,9 @@ #include <vm/vm_pager.h> #include <vm/swap_pager.h> #include <vm/vnode_pager.h> +#include <vm/vm_kern.h> static void _vm_object_allocate(vm_size_t, vm_object_t); -static void vm_object_rcollapse(vm_object_t, vm_object_t); /* * Virtual memory objects maintain the actual data @@ -130,26 +130,23 @@ _vm_object_allocate(size, object) vm_size_t size; register vm_object_t object; { - bzero(object, sizeof *object); TAILQ_INIT(&object->memq); TAILQ_INIT(&object->reverse_shadow_head); - vm_object_lock_init(object); - object->ref_count = 1; - object->resident_page_count = 0; + object->size = size; + object->ref_count = 1; + vm_object_lock_init(object); object->flags = OBJ_INTERNAL; /* vm_allocate_with_pager will reset */ object->paging_in_progress = 0; - object->copy = NULL; - object->last_read = 0; - - /* - * Object starts out read-write, with no pager. - */ + object->resident_page_count = 0; object->pager = NULL; object->paging_offset = 0; object->shadow = NULL; object->shadow_offset = (vm_offset_t) 0; + object->copy = NULL; + + object->last_read = 0; simple_lock(&vm_object_list_lock); TAILQ_INSERT_TAIL(&vm_object_list, object, object_list); @@ -258,13 +255,40 @@ vm_object_deallocate(object) vm_object_lock(object); if (--(object->ref_count) != 0) { if (object->ref_count == 1) { - if (object->reverse_shadow_head.tqh_first) { - ++object->reverse_shadow_head.tqh_first->ref_count; - if (vm_object_lock_try(object->reverse_shadow_head.tqh_first)) { - vm_object_rcollapse(object->reverse_shadow_head.tqh_first, object); - vm_object_unlock(object->reverse_shadow_head.tqh_first); + vm_object_t robject; + robject = object->reverse_shadow_head.tqh_first; + if( robject) { + int s; + robject->ref_count += 2; + object->ref_count += 1; + + do { + s = splhigh(); + while( robject->paging_in_progress) { + tsleep(robject, PVM, "objde1", 0); + } + + while( object->paging_in_progress) { + tsleep(object, PVM, "objde2", 0); + } + splx(s); + + } while( object->paging_in_progress || robject->paging_in_progress); + + object->ref_count -= 1; + robject->ref_count -= 2; + if( robject->ref_count == 0) { + vm_object_unlock(object); + vm_object_cache_unlock(); + robject->ref_count += 1; + vm_object_deallocate(robject); + return; } - vm_object_deallocate(object->reverse_shadow_head.tqh_first); + vm_object_cache_unlock(); + vm_object_unlock(object); + vm_object_lock(robject); + vm_object_collapse(robject); + return; } } vm_object_unlock(object); @@ -801,7 +825,6 @@ vm_object_copy(src_object, src_offset, size, vm_object_collapse(src_object); if (src_object->pager == NULL || - src_object->pager->pg_type == PG_SWAP || (src_object->flags & OBJ_INTERNAL)) { /* @@ -1127,91 +1150,6 @@ vm_object_remove(pager) } } -static void -vm_object_rcollapse(object, sobject) - register vm_object_t object, sobject; -{ - register vm_object_t backing_object; - register vm_offset_t backing_offset, new_offset; - register vm_page_t p, pp; - register vm_size_t size; - int s; - - if (!object) - return; - backing_object = object->shadow; - if (backing_object != sobject) { - printf("backing obj != sobject!!!\n"); - return; - } - if (!backing_object) - return; - if ((backing_object->flags & OBJ_INTERNAL) == 0) - return; - if (backing_object->shadow != NULL && - backing_object->shadow->copy == backing_object) - return; - if (backing_object->ref_count != 1) - return; - - object->ref_count += 2; - backing_object->ref_count += 2; - - backing_offset = object->shadow_offset; - size = object->size; - -again: - s = splbio(); - /* XXX what about object->paging_in_progress? */ - while (backing_object->paging_in_progress) { - tsleep(backing_object, PVM, "rcolpp", 0); - } - splx(s); - - p = backing_object->memq.tqh_first; - while (p) { - vm_page_t next; - - next = p->listq.tqe_next; - - if ((p->flags & (PG_BUSY | PG_FICTITIOUS | PG_CACHE)) || - !p->valid || p->hold_count || p->wire_count || p->busy || p->bmapped) { - p = next; - continue; - } - pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE); - new_offset = (p->offset - backing_offset); - if (p->offset < backing_offset || - new_offset >= size) { - if (backing_object->pager) - swap_pager_freespace(backing_object->pager, - backing_object->paging_offset + p->offset, PAGE_SIZE); - vm_page_lock_queues(); - vm_page_free(p); - vm_page_unlock_queues(); - } else { - pp = vm_page_lookup(object, new_offset); - if (pp != NULL || - (object->pager && - vm_pager_has_page(object->pager, object->paging_offset + new_offset))) { - if (backing_object->pager) - swap_pager_freespace(backing_object->pager, - backing_object->paging_offset + p->offset, PAGE_SIZE); - vm_page_lock_queues(); - vm_page_free(p); - vm_page_unlock_queues(); - } else { - if (!backing_object->pager || - !vm_pager_has_page(backing_object->pager, backing_object->paging_offset + p->offset)) - vm_page_rename(p, object, new_offset); - } - } - p = next; - } - backing_object->ref_count -= 2; - object->ref_count -= 2; -} - /* * this version of collapse allows the operation to occur earlier and * when paging_in_progress is true for an object... This is not a complete @@ -1272,9 +1210,10 @@ vm_object_qcollapse(object) vm_page_free(p); vm_page_unlock_queues(); } else { - if (!backing_object->pager || - !vm_pager_has_page(backing_object->pager, backing_object->paging_offset + p->offset)) - vm_page_rename(p, object, new_offset); + if( backing_object->pager) + swap_pager_freespace(backing_object->pager, + backing_object->paging_offset + p->offset, PAGE_SIZE); + vm_page_rename(p, object, new_offset); } } p = next; @@ -1347,8 +1286,8 @@ vm_object_collapse(object) if ((backing_object->flags & OBJ_INTERNAL) == 0 || backing_object->paging_in_progress != 0) { - vm_object_unlock(backing_object); vm_object_qcollapse(object); + vm_object_unlock(backing_object); return; } /* @@ -1391,6 +1330,7 @@ vm_object_collapse(object) if (backing_object->ref_count == 1) { + backing_object->flags |= OBJ_DEAD; /* * We can collapse the backing object. * @@ -1784,6 +1724,128 @@ vm_object_page_lookup(object, offset) return m; } +int +_vm_object_in_map(map, object, entry) + vm_map_t map; + vm_object_t object; + vm_map_entry_t entry; +{ + vm_map_t tmpm; + vm_map_entry_t tmpe; + vm_object_t obj; + int entcount; + + if (map == 0) + return 0; + + if (entry == 0) { + tmpe = map->header.next; + entcount = map->nentries; + while (entcount-- && (tmpe != &map->header)) { + if( _vm_object_in_map(map, object, tmpe)) { + return 1; + } + tmpe = tmpe->next; + } + } else if (entry->is_sub_map || entry->is_a_map) { + tmpm = entry->object.share_map; + tmpe = tmpm->header.next; + entcount = tmpm->nentries; + while (entcount-- && tmpe != &tmpm->header) { + if( _vm_object_in_map(tmpm, object, tmpe)) { + return 1; + } + tmpe = tmpe->next; + } + } else if (obj = entry->object.vm_object) { + for(; obj; obj=obj->shadow) + if( obj == object) { + return 1; + } + } + return 0; +} + +int +vm_object_in_map( object) + vm_object_t object; +{ + struct proc *p; + for (p = (struct proc *) allproc; p != NULL; p = p->p_next) { + if( !p->p_vmspace /* || (p->p_flag & (P_SYSTEM|P_WEXIT)) */) + continue; +/* + if (p->p_stat != SRUN && p->p_stat != SSLEEP) { + continue; + } +*/ + if( _vm_object_in_map(&p->p_vmspace->vm_map, object, 0)) + return 1; + } + if( _vm_object_in_map( kernel_map, object, 0)) + return 1; + if( _vm_object_in_map( kmem_map, object, 0)) + return 1; + if( _vm_object_in_map( pager_map, object, 0)) + return 1; + if( _vm_object_in_map( buffer_map, object, 0)) + return 1; + if( _vm_object_in_map( io_map, object, 0)) + return 1; + if( _vm_object_in_map( phys_map, object, 0)) + return 1; + if( _vm_object_in_map( mb_map, object, 0)) + return 1; + if( _vm_object_in_map( u_map, object, 0)) + return 1; + return 0; +} + +void +vm_object_check() { + int i; + int maxhash = 0; + vm_object_t object; + vm_object_hash_entry_t entry; + + /* + * make sure that no internal objs are hashed + */ + for (i=0; i<VM_OBJECT_HASH_COUNT;i++) { + int lsize = 0; + for (entry = vm_object_hashtable[i].tqh_first; + entry != NULL; + entry = entry->hash_links.tqe_next) { + if( entry->object->flags & OBJ_INTERNAL) { + printf("vmochk: internal obj on hash: size: %d\n", entry->object->size); + } + ++lsize; + } + if( lsize > maxhash) + maxhash = lsize; + } + + printf("maximum object hash queue size: %d\n", maxhash); + + /* + * make sure that internal objs are in a map somewhere + * and none have zero ref counts. + */ + for (object = vm_object_list.tqh_first; + object != NULL; + object = object->object_list.tqe_next) { + if( object->flags & OBJ_INTERNAL) { + if( object->ref_count == 0) { + printf("vmochk: internal obj has zero ref count: %d\n", + object->size); + } + if( !vm_object_in_map(object)) { + printf("vmochk: internal obj is not in a map: ref: %d, size: %d, pager: 0x%x, shadow: 0x%x\n", object->ref_count, object->size, object->pager, object->shadow); + } + } + } +} + #define DEBUG #if defined(DEBUG) || defined(DDB) /* diff --git a/sys/vm/vm_object.h b/sys/vm/vm_object.h index 71bdd76..14a758b 100644 --- a/sys/vm/vm_object.h +++ b/sys/vm/vm_object.h @@ -61,7 +61,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: vm_object.h,v 1.4 1995/01/09 16:05:50 davidg Exp $ + * $Id: vm_object.h,v 1.5 1995/01/24 10:13:24 davidg Exp $ */ /* @@ -82,26 +82,25 @@ struct vm_object { struct pglist memq; /* Resident memory */ - TAILQ_ENTRY(vm_object) object_list; /* list of all objects */ - u_short flags; /* see below */ - u_short paging_in_progress; /* Paging (in or out) so don't collapse or destroy */ + TAILQ_HEAD(rslist, vm_object) reverse_shadow_head; /* objects that this is a shadow for */ + TAILQ_ENTRY(vm_object) object_list; /* list of all objects */ + TAILQ_ENTRY(vm_object) reverse_shadow_list; /* chain of objects that are shadowed */ + TAILQ_ENTRY(vm_object) cached_list; /* for persistence */ + vm_size_t size; /* Object size */ int ref_count; /* How many refs?? */ struct { int recursion; /* object locking */ struct proc *proc; /* process owned */ } lock; - vm_size_t size; /* Object size */ - int resident_page_count; - /* number of resident pages */ - struct vm_object *copy; /* Object that holds copies of my changed pages */ + u_short flags; /* see below */ + u_short paging_in_progress; /* Paging (in or out) so don't collapse or destroy */ + int resident_page_count; /* number of resident pages */ vm_pager_t pager; /* Where to get data */ vm_offset_t paging_offset; /* Offset into paging space */ struct vm_object *shadow; /* My shadow */ vm_offset_t shadow_offset; /* Offset in shadow */ + struct vm_object *copy; /* Object that holds copies of my changed pages */ vm_offset_t last_read; /* last read in object -- detect seq behavior */ - TAILQ_ENTRY(vm_object) cached_list; /* for persistence */ - TAILQ_ENTRY(vm_object) reverse_shadow_list; /* chain of objects that are shadowed */ - TAILQ_HEAD(rslist, vm_object) reverse_shadow_head; /* objects that this is a shadow for */ }; /* diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index 73906dd..cac0a63 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)vm_page.c 7.4 (Berkeley) 5/7/91 - * $Id: vm_page.c,v 1.16 1995/01/15 07:31:34 davidg Exp $ + * $Id: vm_page.c,v 1.17 1995/01/24 10:13:35 davidg Exp $ */ /* @@ -622,11 +622,11 @@ vm_page_alloc(object, offset, page_req) s = splhigh(); - if (object != kernel_object && + if (((cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_reserved) && + object != kernel_object && object != kmem_object && curproc != pageproc && - curproc != &proc0 && - (cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_reserved) { + curproc != &proc0) { simple_unlock(&vm_page_queue_free_lock); splx(s); return (NULL); @@ -641,10 +641,8 @@ vm_page_alloc(object, offset, page_req) wakeup((caddr_t) &vm_pages_needed); return NULL; } - if( cnt.v_free_count < cnt.v_pageout_free_min) - wakeup((caddr_t) &vm_pages_needed); } else { - if ((cnt.v_free_count < cnt.v_pageout_free_min) || + if ((cnt.v_free_count < cnt.v_free_reserved) || (mem = vm_page_queue_free.tqh_first) == 0) { mem = vm_page_queue_cache.tqh_first; if (mem) { @@ -653,14 +651,16 @@ vm_page_alloc(object, offset, page_req) cnt.v_cache_count--; goto gotpage; } + if( page_req == VM_ALLOC_SYSTEM) { mem = vm_page_queue_free.tqh_first; - if( !mem) { - simple_unlock(&vm_page_queue_free_lock); - splx(s); - wakeup((caddr_t) &vm_pages_needed); - return (NULL); - } + } + + if( !mem) { + simple_unlock(&vm_page_queue_free_lock); + splx(s); + wakeup((caddr_t) &vm_pages_needed); + return (NULL); } } } @@ -814,8 +814,10 @@ vm_page_free(mem) * if pageout daemon needs pages, then tell it that there are * some free. */ - if (vm_pageout_pages_needed) + if (vm_pageout_pages_needed) { wakeup((caddr_t) &vm_pageout_pages_needed); + vm_pageout_pages_needed = 0; + } /* * wakeup processes that are waiting on memory if we hit a @@ -954,8 +956,10 @@ vm_page_cache(m) wakeup((caddr_t) &cnt.v_free_count); wakeup((caddr_t) &proc0); } - if (vm_pageout_pages_needed) + if (vm_pageout_pages_needed) { wakeup((caddr_t) &vm_pageout_pages_needed); + vm_pageout_pages_needed = 0; + } splx(s); } diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c index 152fdcd..1cb1bd6 100644 --- a/sys/vm/vm_pageout.c +++ b/sys/vm/vm_pageout.c @@ -65,7 +65,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: vm_pageout.c,v 1.31 1995/01/24 10:13:58 davidg Exp $ + * $Id: vm_pageout.c,v 1.32 1995/01/28 02:02:25 davidg Exp $ */ /* @@ -642,11 +642,8 @@ rescan1: } else if (maxlaunder > 0) { int written; - TAILQ_REMOVE(&vm_page_queue_inactive, m, pageq); - TAILQ_INSERT_TAIL(&vm_page_queue_inactive, m, pageq); - object = m->object; - if (!vm_object_lock_try(object)) { + if ((object->flags & OBJ_DEAD) || !vm_object_lock_try(object)) { m = next; continue; } @@ -670,9 +667,6 @@ rescan1: if ((next->flags & PG_INACTIVE) == 0) { goto rescan1; } - } else { - TAILQ_REMOVE(&vm_page_queue_inactive, m, pageq); - TAILQ_INSERT_TAIL(&vm_page_queue_inactive, m, pageq); } m = next; } @@ -770,7 +764,7 @@ rescan1: * We try to maintain some *really* free pages, this allows interrupt * code to be guaranteed space. */ - while (cnt.v_free_count < cnt.v_free_min) { + while (cnt.v_free_count < cnt.v_free_reserved) { m = vm_page_queue_cache.tqh_first; if (!m) break; |