3BSD/usr/src/sys/sys/vmdrum.c
/* vmdrum.c 2.1 1/5/80 */
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/proc.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/buf.h"
#include "../h/text.h"
#include "../h/map.h"
#include "../h/pte.h"
#include "../h/vm.h"
#include "../h/cmap.h"
/*
* Expand the swap area for both the data and stack segments.
* If space is not available for both, retract and return 0.
*/
swpexpand(ds, ss, dmp, smp)
size_t ds, ss;
register struct dmap *dmp, *smp;
{
register struct dmap *tmp;
register int ts;
size_t ods;
/*
* If dmap isn't growing, do smap first.
* This avoids anomalies if smap will try to grow and
* fail, which otherwise would shrink ds without expanding
* ss, a rather curious side effect!
*/
if (dmp->dm_alloc > ds) {
tmp = dmp; ts = ds;
dmp = smp; ds = ss;
smp = tmp; ss = ts;
}
ods = dmp->dm_size;
if (vsexpand(ds, dmp) == 0)
return (0);
if (vsexpand(ss, smp) == 0) {
VOID vsexpand(ods, dmp);
return (0);
}
return (1);
}
/*
* Expand or contract the virtual swap segment mapped
* by the argument diskmap so as to just allow the given size.
*
* FOR NOW CANT RELEASE UNLESS SHRINKING TO ZERO, SINCE PAGEOUTS MAY
* BE IN PROGRESS... TYPICALLY NEVER SHRINK ANYWAYS, SO DOESNT MATTER MUCH
*/
vsexpand(vssize, dmp)
register size_t vssize;
register struct dmap *dmp;
{
register int blk = DMMIN;
register int vsbase = 0;
register swblk_t *ip = dmp->dm_map;
size_t oldsize = dmp->dm_size;
if (vssize >= dmp->dm_size && vssize <= dmp->dm_alloc) {
dmp->dm_size = vssize;
return (1);
}
while (vsbase < dmp->dm_alloc || vsbase < vssize) {
if (vsbase >= dmp->dm_alloc) {
*ip = malloc(swapmap, ctod(blk));
if (*ip == 0) {
dmp->dm_size = vsbase;
if (vsexpand(oldsize, dmp) == 0)
panic("vsexpand");
return (0);
}
dmp->dm_alloc += blk;
} else if (vssize == 0) {
/* } else if (vsbase >= vssize) { */
mfree(swapmap, ctod(blk), *ip);
*ip = 0;
dmp->dm_alloc -= blk;
}
vsbase += blk;
if (blk < DMMAX)
blk *= 2;
ip++;
if (ip - dmp->dm_map > NDMAP)
panic("vmdrum NDMAP");
}
dmp->dm_size = vssize;
return (1);
}
/*
* Swap a segment of virtual memory to disk,
* by locating the contiguous dirty pte's
* and calling vschunk with each chunk.
*/
vsswap(p, pte, type, vsbase, vscount, dmp)
struct proc *p;
register struct pte *pte;
int type;
register int vsbase, vscount;
struct dmap *dmp;
{
register int size = 0;
if (vscount % CLSIZE)
panic("vsswap");
for (;;) {
if (vscount == 0 || !dirtycl(pte)) {
if (size) {
vschunk(p, vsbase, size, type, dmp);
vsbase += size;
size = 0;
}
if (vscount == 0)
return;
vsbase += CLSIZE;
if (pte->pg_fod == 0 && pte->pg_pfnum)
if (type == MTEXT)
p->p_textp->x_rssize -= vmemfree(pte, CLSIZE);
else
p->p_rssize -= vmemfree(pte, CLSIZE);
} else {
size += CLSIZE;
mwait(pte->pg_pfnum);
if (anycl(pte, pg_m))
zapcl(pte, pg_vreadm) = 1;
}
vscount -= CLSIZE;
if (type == MSTACK)
pte -= CLSIZE;
else
pte += CLSIZE;
}
}
vschunk(p, base, size, type, dmp)
register struct proc *p;
register int base, size;
int type;
struct dmap *dmp;
{
register struct pte *pte;
struct dblock db;
unsigned v;
if (type == MTEXT) {
swap(p, p->p_textp->x_daddr+base, ptob(tptov(p, base)),
ctob(size), B_WRITE, 0, swapdev);
p->p_textp->x_rssize -= vmemfree(tptopte(p, base), size);
return;
}
do {
vstodb(base, size, dmp, &db, type == MSTACK);
v = type==MSTACK ? sptov(p, base+db.db_size-1) : dptov(p, base);
swap(p, db.db_base, ptob(v), ctob(db.db_size), B_WRITE, 0, swapdev);
pte = type==MSTACK ? sptopte(p, base+db.db_size-1) : dptopte(p, base);
p->p_rssize -= vmemfree(pte, db.db_size);
base += db.db_size;
size -= db.db_size;
} while (size != 0);
}
/*
* Given a base/size pair in virtual swap area,
* return a physical base/size pair which is the
* (largest) initial, physically contiguous block.
*/
vstodb(vsbase, vssize, dmp, dbp, rev)
register int vsbase, vssize;
struct dmap *dmp;
register struct dblock *dbp;
{
register int blk = DMMIN;
register swblk_t *ip = dmp->dm_map;
if (vsbase < 0 || vssize < 0 || vsbase + vssize > dmp->dm_size)
panic("vstodb");
while (vsbase >= blk) {
vsbase -= blk;
if (blk < DMMAX)
blk *= 2;
ip++;
}
if (*ip + blk > nswap)
panic("vstodb *ip");
dbp->db_size = imin(vssize, blk - vsbase);
dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
}
/*
* Convert a virtual page number
* to its corresponding disk block number.
* Used in pagein/pageout to initiate single page transfers.
*/
swblk_t
vtod(p, v, dmap, smap)
register struct proc *p;
unsigned v;
struct dmap *dmap, *smap;
{
struct dblock db;
if (isatsv(p, v))
return (p->p_textp->x_daddr + vtotp(p, v));
if (isassv(p, v))
vstodb(vtosp(p, v), 1, smap, &db, 1);
else
vstodb(vtodp(p, v), 1, dmap, &db, 0);
return (db.db_base);
}