add uvmexp.swpgonly and use it to detect out-of-swap conditions.

This commit is contained in:
chs 1999-03-26 17:34:15 +00:00
parent 92045bbba9
commit d97d75d81b
10 changed files with 159 additions and 86 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm.h,v 1.14 1999/03/25 18:48:49 mrg Exp $ */ /* $NetBSD: uvm.h,v 1.15 1999/03/26 17:34:15 chs Exp $ */
/* /*
* *
@ -92,6 +92,7 @@ struct uvm {
int page_nhash; /* number of buckets */ int page_nhash; /* number of buckets */
int page_hashmask; /* hash mask */ int page_hashmask; /* hash mask */
simple_lock_data_t hashlock; /* lock on page_hash array */ simple_lock_data_t hashlock; /* lock on page_hash array */
/* anon stuff */ /* anon stuff */
struct vm_anon *afree; /* anon free list */ struct vm_anon *afree; /* anon free list */
simple_lock_data_t afreelock; /* lock on anon free list */ simple_lock_data_t afreelock; /* lock on anon free list */
@ -107,6 +108,9 @@ struct uvm {
vaddr_t pager_sva; /* start of pager VA area */ vaddr_t pager_sva; /* start of pager VA area */
vaddr_t pager_eva; /* end of pager VA area */ vaddr_t pager_eva; /* end of pager VA area */
/* swap-related items */
simple_lock_data_t swap_data_lock;
/* kernel object: to support anonymous pageable kernel memory */ /* kernel object: to support anonymous pageable kernel memory */
struct uvm_object *kernel_object; struct uvm_object *kernel_object;
}; };

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_anon.c,v 1.1 1999/01/24 23:53:15 chuck Exp $ */ /* $NetBSD: uvm_anon.c,v 1.2 1999/03/26 17:34:15 chs Exp $ */
/* /*
* *
@ -205,7 +205,6 @@ uvm_anfree(anon)
if ((pg->flags & PG_BUSY) != 0) { if ((pg->flags & PG_BUSY) != 0) {
/* tell them to dump it when done */ /* tell them to dump it when done */
pg->flags |= PG_RELEASED; pg->flags |= PG_RELEASED;
simple_unlock(&anon->an_lock);
UVMHIST_LOG(maphist, UVMHIST_LOG(maphist,
" anon 0x%x, page 0x%x: BUSY (released!)", " anon 0x%x, page 0x%x: BUSY (released!)",
anon, pg, 0, 0); anon, pg, 0, 0);
@ -223,19 +222,9 @@ uvm_anfree(anon)
} }
/* /*
* are we using any backing store resources? if so, free them. * free any swap resources.
*/ */
if (anon->an_swslot) { uvm_anon_dropswap(anon);
/*
* on backing store: no I/O in progress. sole amap reference
* is ours and we've got it locked down. thus we can free,
* and be done.
*/
UVMHIST_LOG(maphist," freeing anon 0x%x, paged to swslot 0x%x",
anon, anon->an_swslot, 0, 0);
uvm_swap_free(anon->an_swslot, 1);
anon->an_swslot = 0;
}
/* /*
* now that we've stripped the data areas from the anon, free the anon * now that we've stripped the data areas from the anon, free the anon
@ -249,6 +238,33 @@ uvm_anfree(anon)
UVMHIST_LOG(maphist,"<- done!",0,0,0,0); UVMHIST_LOG(maphist,"<- done!",0,0,0,0);
} }
/*
* uvm_anon_dropswap: release any swap resources from this anon.
*
* => anon must be locked or have a reference count of 0.
*/
void
uvm_anon_dropswap(anon)
struct vm_anon *anon;
{
UVMHIST_FUNC("uvm_anon_dropswap"); UVMHIST_CALLED(maphist);
if (anon->an_swslot == 0) {
return;
}
UVMHIST_LOG(maphist,"freeing swap for anon %p, paged to swslot 0x%x",
anon, anon->an_swslot, 0, 0);
uvm_swap_free(anon->an_swslot, 1);
anon->an_swslot = 0;
if (anon->u.an_page == NULL) {
/* this page is no longer only in swap. */
simple_lock(&uvm.swap_data_lock);
uvmexp.swpgonly--;
simple_unlock(&uvm.swap_data_lock);
}
}
/* /*
* uvm_anon_lockloanpg: given a locked anon, lock its resident page * uvm_anon_lockloanpg: given a locked anon, lock its resident page
* *

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_anon.h,v 1.9 1999/01/24 23:53:15 chuck Exp $ */ /* $NetBSD: uvm_anon.h,v 1.10 1999/03/26 17:34:15 chs Exp $ */
/* /*
* *
@ -101,5 +101,6 @@ void uvm_anfree __P((struct vm_anon *));
void uvm_anon_init __P((void)); void uvm_anon_init __P((void));
void uvm_anon_add __P((int)); void uvm_anon_add __P((int));
struct vm_page *uvm_anon_lockloanpg __P((struct vm_anon *)); struct vm_page *uvm_anon_lockloanpg __P((struct vm_anon *));
void uvm_anon_dropswap __P((struct vm_anon *));
#endif /* _UVM_UVM_ANON_H_ */ #endif /* _UVM_UVM_ANON_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_aobj.c,v 1.17 1999/03/25 18:48:49 mrg Exp $ */ /* $NetBSD: uvm_aobj.c,v 1.18 1999/03/26 17:34:15 chs Exp $ */
/* /*
* Copyright (c) 1998 Chuck Silvers, Charles D. Cranor and * Copyright (c) 1998 Chuck Silvers, Charles D. Cranor and
@ -423,8 +423,17 @@ uao_free(aobj)
{ {
int slot = elt->slots[j]; int slot = elt->slots[j];
if (slot) if (slot) {
uvm_swap_free(slot, 1); uvm_swap_free(slot, 1);
/*
* this page is no longer
* only in swap.
*/
simple_lock(&uvm.swap_data_lock);
uvmexp.swpgonly--;
simple_unlock(&uvm.swap_data_lock);
}
} }
next = elt->list.le_next; next = elt->list.le_next;
@ -443,8 +452,14 @@ uao_free(aobj)
{ {
int slot = aobj->u_swslots[i]; int slot = aobj->u_swslots[i];
if (slot) if (slot) {
uvm_swap_free(slot, 1); uvm_swap_free(slot, 1);
/* this page is no longer only in swap. */
simple_lock(&uvm.swap_data_lock);
uvmexp.swpgonly--;
simple_unlock(&uvm.swap_data_lock);
}
} }
FREE(aobj->u_swslots, M_UVMAOBJ); FREE(aobj->u_swslots, M_UVMAOBJ);
} }
@ -661,7 +676,6 @@ uao_detach(uobj)
busybody = FALSE; busybody = FALSE;
for (pg = uobj->memq.tqh_first ; pg != NULL ; pg = pg->listq.tqe_next) { for (pg = uobj->memq.tqh_first ; pg != NULL ; pg = pg->listq.tqe_next) {
int swslot;
if (pg->flags & PG_BUSY) { if (pg->flags & PG_BUSY) {
pg->flags |= PG_RELEASED; pg->flags |= PG_RELEASED;
@ -669,16 +683,9 @@ uao_detach(uobj)
continue; continue;
} }
/* zap the mappings, free the swap slot, free the page */ /* zap the mappings, free the swap slot, free the page */
pmap_page_protect(PMAP_PGARG(pg), VM_PROT_NONE); pmap_page_protect(PMAP_PGARG(pg), VM_PROT_NONE);
uao_dropswap(&aobj->u_obj, pg->offset >> PAGE_SHIFT);
swslot = uao_set_swslot(&aobj->u_obj,
pg->offset >> PAGE_SHIFT, 0);
if (swslot) {
uvm_swap_free(swslot, 1);
}
uvm_lock_pageq(); uvm_lock_pageq();
uvm_pagefree(pg); uvm_pagefree(pg);
uvm_unlock_pageq(); uvm_unlock_pageq();
@ -1037,7 +1044,6 @@ static boolean_t uao_releasepg(pg, nextpgp)
struct vm_page **nextpgp; /* OUT */ struct vm_page **nextpgp; /* OUT */
{ {
struct uvm_aobj *aobj = (struct uvm_aobj *) pg->uobject; struct uvm_aobj *aobj = (struct uvm_aobj *) pg->uobject;
int slot;
#ifdef DIAGNOSTIC #ifdef DIAGNOSTIC
if ((pg->flags & PG_RELEASED) == 0) if ((pg->flags & PG_RELEASED) == 0)
@ -1048,9 +1054,7 @@ static boolean_t uao_releasepg(pg, nextpgp)
* dispose of the page [caller handles PG_WANTED] and swap slot. * dispose of the page [caller handles PG_WANTED] and swap slot.
*/ */
pmap_page_protect(PMAP_PGARG(pg), VM_PROT_NONE); pmap_page_protect(PMAP_PGARG(pg), VM_PROT_NONE);
slot = uao_set_swslot(&aobj->u_obj, pg->offset >> PAGE_SHIFT, 0); uao_dropswap(&aobj->u_obj, pg->offset >> PAGE_SHIFT);
if (slot)
uvm_swap_free(slot, 1);
uvm_lock_pageq(); uvm_lock_pageq();
if (nextpgp) if (nextpgp)
*nextpgp = pg->pageq.tqe_next; /* next page for daemon */ *nextpgp = pg->pageq.tqe_next; /* next page for daemon */
@ -1087,3 +1091,22 @@ static boolean_t uao_releasepg(pg, nextpgp)
return FALSE; return FALSE;
} }
/*
* uao_dropswap: release any swap resources from this aobj page.
*
* => aobj must be locked or have a reference count of 0.
*/
void
uao_dropswap(uobj, pageidx)
struct uvm_object *uobj;
int pageidx;
{
int slot;
slot = uao_set_swslot(uobj, pageidx, 0);
if (slot) {
uvm_swap_free(slot, 1);
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_aobj.h,v 1.7 1999/03/25 18:48:50 mrg Exp $ */ /* $NetBSD: uvm_aobj.h,v 1.8 1999/03/26 17:34:15 chs Exp $ */
/* /*
* Copyright (c) 1998 Chuck Silvers, Charles D. Cranor and * Copyright (c) 1998 Chuck Silvers, Charles D. Cranor and
@ -63,6 +63,7 @@
*/ */
int uao_set_swslot __P((struct uvm_object *, int, int)); int uao_set_swslot __P((struct uvm_object *, int, int));
void uao_dropswap __P((struct uvm_object *, int));
/* /*
* globals * globals

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_extern.h,v 1.22 1999/03/25 18:48:50 mrg Exp $ */ /* $NetBSD: uvm_extern.h,v 1.23 1999/03/26 17:34:15 chs Exp $ */
/* /*
* *
@ -177,6 +177,7 @@ struct uvmexp {
int nswapdev; /* number of configured swap devices in system */ int nswapdev; /* number of configured swap devices in system */
int swpages; /* number of PAGE_SIZE'ed swap pages */ int swpages; /* number of PAGE_SIZE'ed swap pages */
int swpginuse; /* number of swap pages in use */ int swpginuse; /* number of swap pages in use */
int swpgonly; /* number of swap pages in use, not also in RAM */
int nswget; /* number of times fault calls uvm_swap_get() */ int nswget; /* number of times fault calls uvm_swap_get() */
int nanon; /* number total of anon's in system */ int nanon; /* number total of anon's in system */
int nfreeanon; /* number of free anon's */ int nfreeanon; /* number of free anon's */

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_fault.c,v 1.21 1999/03/25 18:48:50 mrg Exp $ */ /* $NetBSD: uvm_fault.c,v 1.22 1999/03/26 17:34:16 chs Exp $ */
/* /*
* *
@ -1146,13 +1146,18 @@ ReFault:
if (anon) if (anon)
uvm_anfree(anon); uvm_anfree(anon);
uvmfault_unlockall(&ufi, amap, uobj, oanon); uvmfault_unlockall(&ufi, amap, uobj, oanon);
if (anon == NULL) { #ifdef DIAGNOSTIC
if (uvmexp.swpgonly > uvmexp.swpages) {
panic("uvmexp.swpgonly botch");
}
#endif
if (anon == NULL || uvmexp.swpgonly == uvmexp.swpages) {
UVMHIST_LOG(maphist, UVMHIST_LOG(maphist,
"<- failed. out of VM",0,0,0,0); "<- failed. out of VM",0,0,0,0);
uvmexp.fltnoanon++; uvmexp.fltnoanon++;
/* XXX: OUT OF VM, ??? */
return (KERN_RESOURCE_SHORTAGE); return (KERN_RESOURCE_SHORTAGE);
} }
uvmexp.fltnoram++; uvmexp.fltnoram++;
uvm_wait("flt_noram3"); /* out of RAM, wait for more */ uvm_wait("flt_noram3"); /* out of RAM, wait for more */
goto ReFault; goto ReFault;
@ -1207,6 +1212,7 @@ ReFault:
if (fault_type == VM_FAULT_WIRE) { if (fault_type == VM_FAULT_WIRE) {
uvm_pagewire(pg); uvm_pagewire(pg);
uvm_anon_dropswap(anon);
} else { } else {
/* activate it */ /* activate it */
uvm_pageactivate(pg); uvm_pageactivate(pg);
@ -1538,13 +1544,18 @@ Case2:
/* unlock and fail ... */ /* unlock and fail ... */
uvmfault_unlockall(&ufi, amap, uobj, NULL); uvmfault_unlockall(&ufi, amap, uobj, NULL);
if (anon == NULL) { #ifdef DIAGNOSTIC
if (uvmexp.swpgonly > uvmexp.swpages) {
panic("uvmexp.swpgonly botch");
}
#endif
if (anon == NULL || uvmexp.swpgonly == uvmexp.swpages) {
UVMHIST_LOG(maphist, " promote: out of VM", UVMHIST_LOG(maphist, " promote: out of VM",
0,0,0,0); 0,0,0,0);
uvmexp.fltnoanon++; uvmexp.fltnoanon++;
/* XXX: out of VM */
return (KERN_RESOURCE_SHORTAGE); return (KERN_RESOURCE_SHORTAGE);
} }
UVMHIST_LOG(maphist, " out of RAM, waiting for more", UVMHIST_LOG(maphist, " out of RAM, waiting for more",
0,0,0,0); 0,0,0,0);
uvm_anfree(anon); uvm_anfree(anon);
@ -1625,6 +1636,9 @@ Case2:
if (fault_type == VM_FAULT_WIRE) { if (fault_type == VM_FAULT_WIRE) {
uvm_pagewire(pg); uvm_pagewire(pg);
if (pg->pqflags & PQ_AOBJ) {
uao_dropswap(uobj, pg->offset >> PAGE_SHIFT);
}
} else { } else {
/* activate it */ /* activate it */

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_km.c,v 1.20 1999/03/25 18:48:52 mrg Exp $ */ /* $NetBSD: uvm_km.c,v 1.21 1999/03/26 17:34:16 chs Exp $ */
/* /*
* Copyright (c) 1997 Charles D. Cranor and Washington University. * Copyright (c) 1997 Charles D. Cranor and Washington University.
@ -575,12 +575,7 @@ uvm_km_pgremove(uobj, start, end)
* if this kernel object is an aobj, free the swap slot. * if this kernel object is an aobj, free the swap slot.
*/ */
if (is_aobj) { if (is_aobj) {
int slot = uao_set_swslot(uobj, uao_dropswap(uobj, curoff >> PAGE_SHIFT);
curoff >> PAGE_SHIFT,
0);
if (slot)
uvm_swap_free(slot, 1);
} }
uvm_lock_pageq(); uvm_lock_pageq();
@ -615,11 +610,7 @@ loop_by_list:
* if this kernel object is an aobj, free the swap slot. * if this kernel object is an aobj, free the swap slot.
*/ */
if (is_aobj) { if (is_aobj) {
int slot = uao_set_swslot(uobj, uao_dropswap(uobj, pp->offset >> PAGE_SHIFT);
pp->offset >> PAGE_SHIFT, 0);
if (slot)
uvm_swap_free(slot, 1);
} }
uvm_lock_pageq(); uvm_lock_pageq();

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_stat.c,v 1.11 1999/03/25 18:48:56 mrg Exp $ */ /* $NetBSD: uvm_stat.c,v 1.12 1999/03/26 17:34:16 chs Exp $ */
/* /*
* *
@ -244,6 +244,8 @@ uvm_dump()
uvmexp.pdpending, uvmexp.nswget); uvmexp.pdpending, uvmexp.nswget);
printf(" nswapdev=%d, nanon=%d, nfreeanon=%d\n", uvmexp.nswapdev, printf(" nswapdev=%d, nanon=%d, nfreeanon=%d\n", uvmexp.nswapdev,
uvmexp.nanon, uvmexp.nfreeanon); uvmexp.nanon, uvmexp.nfreeanon);
printf(" swpages=%d, swpginuse=%d, swpgonly=%d paging=%d\n",
uvmexp.swpages, uvmexp.swpginuse, uvmexp.swpgonly, uvmexp.paging);
printf(" kernel pointers:\n"); printf(" kernel pointers:\n");
printf(" objs(kern/kmem/mb)=%p/%p/%p\n", uvm.kernel_object, printf(" objs(kern/kmem/mb)=%p/%p/%p\n", uvm.kernel_object,

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_swap.c,v 1.25 1999/03/18 01:45:29 chs Exp $ */ /* $NetBSD: uvm_swap.c,v 1.26 1999/03/26 17:34:16 chs Exp $ */
/* /*
* Copyright (c) 1995, 1996, 1997 Matthew R. Green * Copyright (c) 1995, 1996, 1997 Matthew R. Green
@ -88,7 +88,7 @@
* - swap_syscall_lock (sleep lock): this lock serializes the swapctl * - swap_syscall_lock (sleep lock): this lock serializes the swapctl
* system call and prevents the swap priority list from changing * system call and prevents the swap priority list from changing
* while we are in the middle of a system call (e.g. SWAP_STATS). * while we are in the middle of a system call (e.g. SWAP_STATS).
* - swap_data_lock (simple_lock): this lock protects all swap data * - uvm.swap_data_lock (simple_lock): this lock protects all swap data
* structures including the priority list, the swapdev structures, * structures including the priority list, the swapdev structures,
* and the swapmap extent. * and the swapmap extent.
* - swap_buf_lock (simple_lock): this lock protects the free swapbuf * - swap_buf_lock (simple_lock): this lock protects the free swapbuf
@ -238,7 +238,6 @@ static struct swap_priority swap_priority;
/* locks */ /* locks */
lock_data_t swap_syscall_lock; lock_data_t swap_syscall_lock;
static simple_lock_data_t swap_data_lock;
/* /*
* prototypes * prototypes
@ -287,7 +286,7 @@ uvm_swap_init()
LIST_INIT(&swap_priority); LIST_INIT(&swap_priority);
uvmexp.nswapdev = 0; uvmexp.nswapdev = 0;
lockinit(&swap_syscall_lock, PVM, "swapsys", 0, 0); lockinit(&swap_syscall_lock, PVM, "swapsys", 0, 0);
simple_lock_init(&swap_data_lock); simple_lock_init(&uvm.swap_data_lock);
if (bdevvp(swapdev, &swapdev_vp)) if (bdevvp(swapdev, &swapdev_vp))
panic("uvm_swap_init: can't get vnode for swap device"); panic("uvm_swap_init: can't get vnode for swap device");
@ -341,7 +340,7 @@ uvm_swap_init()
/* /*
* swaplist_insert: insert swap device "sdp" into the global list * swaplist_insert: insert swap device "sdp" into the global list
* *
* => caller must hold both swap_syscall_lock and swap_data_lock * => caller must hold both swap_syscall_lock and uvm.swap_data_lock
* => caller must provide a newly malloc'd swappri structure (we will * => caller must provide a newly malloc'd swappri structure (we will
* FREE it if we don't need it... this it to prevent malloc blocking * FREE it if we don't need it... this it to prevent malloc blocking
* here while adding swap) * here while adding swap)
@ -401,7 +400,7 @@ swaplist_insert(sdp, newspp, priority)
* swaplist_find: find and optionally remove a swap device from the * swaplist_find: find and optionally remove a swap device from the
* global list. * global list.
* *
* => caller must hold both swap_syscall_lock and swap_data_lock * => caller must hold both swap_syscall_lock and uvm.swap_data_lock
* => we return the swapdev we found (and removed) * => we return the swapdev we found (and removed)
*/ */
static struct swapdev * static struct swapdev *
@ -437,7 +436,7 @@ swaplist_find(vp, remove)
* swaplist_trim: scan priority list for empty priority entries and kill * swaplist_trim: scan priority list for empty priority entries and kill
* them. * them.
* *
* => caller must hold both swap_syscall_lock and swap_data_lock * => caller must hold both swap_syscall_lock and uvm.swap_data_lock
*/ */
static void static void
swaplist_trim() swaplist_trim()
@ -457,7 +456,7 @@ swaplist_trim()
* swapdrum_add: add a "swapdev"'s blocks into /dev/drum's area. * swapdrum_add: add a "swapdev"'s blocks into /dev/drum's area.
* *
* => caller must hold swap_syscall_lock * => caller must hold swap_syscall_lock
* => swap_data_lock should be unlocked (we may sleep) * => uvm.swap_data_lock should be unlocked (we may sleep)
*/ */
static void static void
swapdrum_add(sdp, npages) swapdrum_add(sdp, npages)
@ -479,7 +478,7 @@ swapdrum_add(sdp, npages)
* to the "swapdev" that maps that section of the drum. * to the "swapdev" that maps that section of the drum.
* *
* => each swapdev takes one big contig chunk of the drum * => each swapdev takes one big contig chunk of the drum
* => caller must hold swap_data_lock * => caller must hold uvm.swap_data_lock
*/ */
static struct swapdev * static struct swapdev *
swapdrum_getsdp(pgno) swapdrum_getsdp(pgno)
@ -553,7 +552,7 @@ sys_swapctl(p, v, retval)
* *
* note that the swap_priority list can't change as long * note that the swap_priority list can't change as long
* as we are holding the swap_syscall_lock. we don't want * as we are holding the swap_syscall_lock. we don't want
* to grab the swap_data_lock because we may fault&sleep during * to grab the uvm.swap_data_lock because we may fault&sleep during
* copyout() and we don't want to be holding that lock then! * copyout() and we don't want to be holding that lock then!
*/ */
if (SCARG(uap, cmd) == SWAP_STATS if (SCARG(uap, cmd) == SWAP_STATS
@ -675,14 +674,14 @@ sys_swapctl(p, v, retval)
priority = SCARG(uap, misc); priority = SCARG(uap, misc);
spp = (struct swappri *) spp = (struct swappri *)
malloc(sizeof *spp, M_VMSWAP, M_WAITOK); malloc(sizeof *spp, M_VMSWAP, M_WAITOK);
simple_lock(&swap_data_lock); simple_lock(&uvm.swap_data_lock);
if ((sdp = swaplist_find(vp, 1)) == NULL) { if ((sdp = swaplist_find(vp, 1)) == NULL) {
error = ENOENT; error = ENOENT;
} else { } else {
swaplist_insert(sdp, spp, priority); swaplist_insert(sdp, spp, priority);
swaplist_trim(); swaplist_trim();
} }
simple_unlock(&swap_data_lock); simple_unlock(&uvm.swap_data_lock);
if (error) if (error)
free(spp, M_VMSWAP); free(spp, M_VMSWAP);
break; break;
@ -695,10 +694,10 @@ sys_swapctl(p, v, retval)
* it. * it.
*/ */
priority = SCARG(uap, misc); priority = SCARG(uap, misc);
simple_lock(&swap_data_lock); simple_lock(&uvm.swap_data_lock);
if ((sdp = swaplist_find(vp, 0)) != NULL) { if ((sdp = swaplist_find(vp, 0)) != NULL) {
error = EBUSY; error = EBUSY;
simple_unlock(&swap_data_lock); simple_unlock(&uvm.swap_data_lock);
break; break;
} }
sdp = (struct swapdev *) sdp = (struct swapdev *)
@ -717,7 +716,7 @@ sys_swapctl(p, v, retval)
sdp->swd_cred = crdup(p->p_ucred); sdp->swd_cred = crdup(p->p_ucred);
#endif #endif
swaplist_insert(sdp, spp, priority); swaplist_insert(sdp, spp, priority);
simple_unlock(&swap_data_lock); simple_unlock(&uvm.swap_data_lock);
sdp->swd_pathlen = len; sdp->swd_pathlen = len;
sdp->swd_path = malloc(sdp->swd_pathlen, M_VMSWAP, M_WAITOK); sdp->swd_path = malloc(sdp->swd_pathlen, M_VMSWAP, M_WAITOK);
@ -730,10 +729,10 @@ sys_swapctl(p, v, retval)
* if swap_on is a success, it will clear the SWF_FAKE flag * if swap_on is a success, it will clear the SWF_FAKE flag
*/ */
if ((error = swap_on(p, sdp)) != 0) { if ((error = swap_on(p, sdp)) != 0) {
simple_lock(&swap_data_lock); simple_lock(&uvm.swap_data_lock);
(void) swaplist_find(vp, 1); /* kill fake entry */ (void) swaplist_find(vp, 1); /* kill fake entry */
swaplist_trim(); swaplist_trim();
simple_unlock(&swap_data_lock); simple_unlock(&uvm.swap_data_lock);
#ifdef SWAP_TO_FILES #ifdef SWAP_TO_FILES
if (vp->v_type == VREG) if (vp->v_type == VREG)
crfree(sdp->swd_cred); crfree(sdp->swd_cred);
@ -756,9 +755,9 @@ sys_swapctl(p, v, retval)
/* /*
* find the entry of interest and ensure it is enabled. * find the entry of interest and ensure it is enabled.
*/ */
simple_lock(&swap_data_lock); simple_lock(&uvm.swap_data_lock);
if ((sdp = swaplist_find(vp, 0)) == NULL) { if ((sdp = swaplist_find(vp, 0)) == NULL) {
simple_unlock(&swap_data_lock); simple_unlock(&uvm.swap_data_lock);
error = ENXIO; error = ENXIO;
break; break;
} }
@ -767,7 +766,7 @@ sys_swapctl(p, v, retval)
* can't stop swapping from it (again). * can't stop swapping from it (again).
*/ */
if ((sdp->swd_flags & (SWF_INUSE|SWF_ENABLE)) == 0) { if ((sdp->swd_flags & (SWF_INUSE|SWF_ENABLE)) == 0) {
simple_unlock(&swap_data_lock); simple_unlock(&uvm.swap_data_lock);
error = EBUSY; error = EBUSY;
break; break;
} }
@ -783,7 +782,7 @@ sys_swapctl(p, v, retval)
error = ENXIO; error = ENXIO;
break; break;
} }
simple_unlock(&swap_data_lock); simple_unlock(&uvm.swap_data_lock);
free((caddr_t)sdp, M_VMSWAP); free((caddr_t)sdp, M_VMSWAP);
#else #else
error = EINVAL; error = EINVAL;
@ -814,7 +813,7 @@ out:
* *
* => we avoid the start of the disk (to protect disk labels) * => we avoid the start of the disk (to protect disk labels)
* => we also avoid the miniroot, if we are swapping to root. * => we also avoid the miniroot, if we are swapping to root.
* => caller should leave swap_data_lock unlocked, we may lock it * => caller should leave uvm.swap_data_lock unlocked, we may lock it
* if needed. * if needed.
*/ */
static int static int
@ -957,10 +956,12 @@ swap_on(p, sdp)
if (extent_alloc_region(sdp->swd_ex, 0, addr, EX_WAITOK)) if (extent_alloc_region(sdp->swd_ex, 0, addr, EX_WAITOK))
panic("disklabel region"); panic("disklabel region");
sdp->swd_npginuse += addr; sdp->swd_npginuse += addr;
simple_lock(&uvm.swap_data_lock);
uvmexp.swpginuse += addr; uvmexp.swpginuse += addr;
uvmexp.swpgonly += addr;
simple_unlock(&uvm.swap_data_lock);
} }
/* /*
* if the vnode we are swapping to is the root vnode * if the vnode we are swapping to is the root vnode
* (i.e. we are swapping to the miniroot) then we want * (i.e. we are swapping to the miniroot) then we want
@ -983,8 +984,11 @@ swap_on(p, sdp)
rootpages, EX_WAITOK)) rootpages, EX_WAITOK))
panic("swap_on: unable to preserve miniroot"); panic("swap_on: unable to preserve miniroot");
simple_lock(&uvm.swap_data_lock);
sdp->swd_npginuse += (rootpages - addr); sdp->swd_npginuse += (rootpages - addr);
uvmexp.swpginuse += (rootpages - addr); uvmexp.swpginuse += (rootpages - addr);
uvmexp.swpgonly += (rootpages - addr);
simple_unlock(&uvm.swap_data_lock);
printf("Preserved %d pages of miniroot ", rootpages); printf("Preserved %d pages of miniroot ", rootpages);
printf("leaving %d pages of swap\n", size - rootpages); printf("leaving %d pages of swap\n", size - rootpages);
@ -993,12 +997,12 @@ swap_on(p, sdp)
/* /*
* now add the new swapdev to the drum and enable. * now add the new swapdev to the drum and enable.
*/ */
simple_lock(&swap_data_lock); simple_lock(&uvm.swap_data_lock);
swapdrum_add(sdp, npages); swapdrum_add(sdp, npages);
sdp->swd_npages = npages; sdp->swd_npages = npages;
sdp->swd_flags &= ~SWF_FAKE; /* going live */ sdp->swd_flags &= ~SWF_FAKE; /* going live */
sdp->swd_flags |= (SWF_INUSE|SWF_ENABLE); sdp->swd_flags |= (SWF_INUSE|SWF_ENABLE);
simple_unlock(&swap_data_lock); simple_unlock(&uvm.swap_data_lock);
uvmexp.swpages += npages; uvmexp.swpages += npages;
/* /*
@ -1160,9 +1164,9 @@ swstrategy(bp)
* in it (i.e. the blocks we are doing I/O on). * in it (i.e. the blocks we are doing I/O on).
*/ */
pageno = dbtob(bp->b_blkno) >> PAGE_SHIFT; pageno = dbtob(bp->b_blkno) >> PAGE_SHIFT;
simple_lock(&swap_data_lock); simple_lock(&uvm.swap_data_lock);
sdp = swapdrum_getsdp(pageno); sdp = swapdrum_getsdp(pageno);
simple_unlock(&swap_data_lock); simple_unlock(&uvm.swap_data_lock);
if (sdp == NULL) { if (sdp == NULL) {
bp->b_error = EINVAL; bp->b_error = EINVAL;
bp->b_flags |= B_ERROR; bp->b_flags |= B_ERROR;
@ -1553,7 +1557,7 @@ sw_reg_iodone(bp)
* allocate in a priority we "rotate" the circle queue. * allocate in a priority we "rotate" the circle queue.
* => space can be freed with uvm_swap_free * => space can be freed with uvm_swap_free
* => we return the page slot number in /dev/drum (0 == invalid slot) * => we return the page slot number in /dev/drum (0 == invalid slot)
* => we lock swap_data_lock * => we lock uvm.swap_data_lock
* => XXXMRG: "LESSOK" INTERFACE NEEDED TO EXTENT SYSTEM * => XXXMRG: "LESSOK" INTERFACE NEEDED TO EXTENT SYSTEM
*/ */
int int
@ -1575,7 +1579,7 @@ uvm_swap_alloc(nslots, lessok)
/* /*
* lock data lock, convert slots into blocks, and enter loop * lock data lock, convert slots into blocks, and enter loop
*/ */
simple_lock(&swap_data_lock); simple_lock(&uvm.swap_data_lock);
ReTry: /* XXXMRG */ ReTry: /* XXXMRG */
for (spp = swap_priority.lh_first; spp != NULL; for (spp = swap_priority.lh_first; spp != NULL;
@ -1601,7 +1605,7 @@ ReTry: /* XXXMRG */
CIRCLEQ_INSERT_TAIL(&spp->spi_swapdev, sdp, swd_next); CIRCLEQ_INSERT_TAIL(&spp->spi_swapdev, sdp, swd_next);
sdp->swd_npginuse += *nslots; sdp->swd_npginuse += *nslots;
uvmexp.swpginuse += *nslots; uvmexp.swpginuse += *nslots;
simple_unlock(&swap_data_lock); simple_unlock(&uvm.swap_data_lock);
/* done! return drum slot number */ /* done! return drum slot number */
UVMHIST_LOG(pdhist, UVMHIST_LOG(pdhist,
"success! returning %d slots starting at %d", "success! returning %d slots starting at %d",
@ -1629,7 +1633,7 @@ panic("uvm_swap_alloc: allocating unmapped swap block!");
} }
/* XXXMRG: END HACK */ /* XXXMRG: END HACK */
simple_unlock(&swap_data_lock); simple_unlock(&uvm.swap_data_lock);
return 0; /* failed */ return 0; /* failed */
} }
@ -1637,7 +1641,7 @@ panic("uvm_swap_alloc: allocating unmapped swap block!");
* uvm_swap_free: free swap slots * uvm_swap_free: free swap slots
* *
* => this can be all or part of an allocation made by uvm_swap_alloc * => this can be all or part of an allocation made by uvm_swap_alloc
* => we lock swap_data_lock * => we lock uvm.swap_data_lock
*/ */
void void
uvm_swap_free(startslot, nslots) uvm_swap_free(startslot, nslots)
@ -1654,7 +1658,7 @@ uvm_swap_free(startslot, nslots)
* in the extent, and return. must hold pri lock to do * in the extent, and return. must hold pri lock to do
* lookup and access the extent. * lookup and access the extent.
*/ */
simple_lock(&swap_data_lock); simple_lock(&uvm.swap_data_lock);
sdp = swapdrum_getsdp(startslot); sdp = swapdrum_getsdp(startslot);
#ifdef DIAGNOSTIC #ifdef DIAGNOSTIC
@ -1677,7 +1681,7 @@ uvm_swap_free(startslot, nslots)
if (sdp->swd_npginuse < 0) if (sdp->swd_npginuse < 0)
panic("uvm_swap_free: inuse < 0"); panic("uvm_swap_free: inuse < 0");
#endif #endif
simple_unlock(&swap_data_lock); simple_unlock(&uvm.swap_data_lock);
} }
/* /*
@ -1724,9 +1728,25 @@ uvm_swap_get(page, swslot, flags)
printf("uvm_swap_get: ASYNC get requested?\n"); printf("uvm_swap_get: ASYNC get requested?\n");
#endif #endif
/*
* this page is (about to be) no longer only in swap.
*/
simple_lock(&uvm.swap_data_lock);
uvmexp.swpgonly--;
simple_unlock(&uvm.swap_data_lock);
result = uvm_swap_io(&page, swslot, 1, B_READ | result = uvm_swap_io(&page, swslot, 1, B_READ |
((flags & PGO_SYNCIO) ? 0 : B_ASYNC)); ((flags & PGO_SYNCIO) ? 0 : B_ASYNC));
if (result != VM_PAGER_OK && result != VM_PAGER_PEND) {
/*
* oops, the read failed so it really is still only in swap.
*/
simple_lock(&uvm.swap_data_lock);
uvmexp.swpgonly++;
simple_unlock(&uvm.swap_data_lock);
}
return (result); return (result);
} }