V10/lsys/io/sw.c
/*
* indirect driver for swapping
*/
#include "sys/param.h"
#include "sys/systm.h"
#include "sys/buf.h"
#include "sys/conf.h"
#include "sys/user.h"
#include "sys/inode.h"
#include "sys/map.h"
struct buf rswbuf;
extern struct map swapmap[];
extern int swmapcnt;
extern struct map argmap[];
extern int argcnt;
int swopen(), swstrategy(), swread(), swwrite();
struct bdevsw swbdev = bdinit(swopen, nulldev, swstrategy, 0);
struct cdevsw swcdev = cdinit(swopen, nulldev, swread, swwrite, nodev);
/*
* presumably called for the first time on boot
*/
swopen(dev, flag)
dev_t dev;
int flag;
{
static int opened;
if (opened)
return;
opened++;
swfree(0);
}
swstrategy(bp)
register struct buf *bp;
{
register clicks_t sz;
register daddr_t off;
register int seg;
dev_t dev;
sz = btoc(bp->b_bcount);
off = bp->b_blkno % dmmax;
seg = bp->b_blkno / dmmax;
dev = swdevt[seg % nswdevt].sw_dev;
if (bdevsw[major(dev)] == 0)
panic("swstrategy");
bp->b_blkno = seg / nswdevt;
bp->b_blkno *= dmmax;
bp->b_blkno += off;
bp->b_dev = dev;
if (bp->b_blkno+sz > swdevt[seg % nswdevt].sw_size
|| off+sz > dmmax) {
bp->b_flags |= B_ERROR;
iodone(bp);
return;
}
(*bdevsw[major(dev)]->d_strategy)(bp);
}
swread(dev)
{
physio(swstrategy, &rswbuf, dev, B_READ, minphys);
}
swwrite(dev)
{
physio(swstrategy, &rswbuf, dev, B_WRITE, minphys);
}
/*
* System call swapon(name) enables swapping on device name,
* which must be in the swdevsw. Return EBUSY
* if already swapping on this device.
* silly; this should just be an ioctl.
*
* -- assume swapping on a regular filesystem,
* so directly calling thought bdevsw is what we want.
* some day this will be unfortunate.
*/
vswapon()
{
struct a {
char *fname;
};
register struct inode *ip;
dev_t dev;
register int i;
ip = namei(((struct a *)u.u_ap)->fname, SEGUDATA, &nilargnamei, 1);
if (ip == NULL)
return;
if ((ip->i_mode&IFMT) != IFBLK || ip->i_fstyp != 0) {
u.u_error = EINVAL;
iput(ip);
return;
}
dev = (dev_t)ip->i_un.i_rdev;
iput(ip);
for (i = 0; i < nswdevt; i++) {
if (swdevt[i].sw_dev != dev)
continue;
if (swdevt[i].sw_freed) {
u.u_error = EBUSY;
return;
}
swfree(i);
return;
}
u.u_error = ENODEV;
}
/*
* Swfree(index) frees the index'th portion of the swap map.
* Each of the nswdevt devices provides 1/nswdev'th of the swap
* space, which is laid out with blocks of dmmax pages circularly
* among the devices.
* rmalloc starts at 1, so give the first dmmax/2 pages of the first device
* to the arg device.
* quietly opens the device, with no trace in inode table
* subsequently really opening and closing the device may cause trouble?
*/
swfree(index)
register int index;
{
register swblk_t bno;
register int nblk;
register int xsize;
extern int argcnt, swmapcnt;
bdevopen(swdevt[index].sw_dev);
if (u.u_error)
return;
xsize = swdevt[index].sw_size * nswdevt;
xsize += index * dmmax;
xsize -= (nswdevt - 1) * (swdevt[index].sw_size % dmmax);
for (bno = dmmax * index; bno < xsize; bno += dmmax * nswdevt) {
nblk = xsize - bno;
if (nblk > dmmax)
nblk = dmmax;
if (bno)
rmfree(swapmap, nblk, (int)bno);
else {
argdev = swdevt[0].sw_dev;
rminit(argmap, argcnt, nblk/2-CLSIZE, CLSIZE);
rminit(swapmap, swmapcnt, nblk/2, nblk/2);
}
}
swdevt[index].sw_freed = 1;
}