xref: /csrg-svn/sys/vm/vm_swap.c (revision 16695)
1*16695Smckusick /*	vm_swap.c	6.2	84/07/08	*/
21404Sbill 
31404Sbill #include "../h/param.h"
41404Sbill #include "../h/systm.h"
51404Sbill #include "../h/buf.h"
61404Sbill #include "../h/conf.h"
71404Sbill #include "../h/dir.h"
81404Sbill #include "../h/user.h"
91404Sbill #include "../h/inode.h"
101404Sbill #include "../h/map.h"
117828Sroot #include "../h/uio.h"
129010Sroot #include "../h/file.h"
131404Sbill 
141404Sbill struct	buf rswbuf;
151404Sbill /*
161404Sbill  * Indirect driver for multi-controller paging.
171404Sbill  */
181404Sbill swstrategy(bp)
191404Sbill 	register struct buf *bp;
201404Sbill {
211404Sbill 	int sz, off, seg;
221404Sbill 	dev_t dev;
231404Sbill 
247435Sroot #ifdef GENERIC
257435Sroot 	/*
267435Sroot 	 * A mini-root gets copied into the front of the swap
277435Sroot 	 * and we run over top of the swap area just long
287435Sroot 	 * enough for us to do a mkfs and restor of the real
297435Sroot 	 * root (sure beats rewriting standalone restor).
307435Sroot 	 */
3111051Ssam #define	MINIROOTSIZE	4096
327435Sroot 	if (rootdev == dumpdev)
337435Sroot 		bp->b_blkno += MINIROOTSIZE;
347435Sroot #endif
359010Sroot 	sz = howmany(bp->b_bcount, DEV_BSIZE);
3612490Ssam 	if (bp->b_blkno+sz > nswap) {
371404Sbill 		bp->b_flags |= B_ERROR;
381404Sbill 		iodone(bp);
391404Sbill 		return;
401404Sbill 	}
4112490Ssam 	if (nswdev > 1) {
4212490Ssam 		off = bp->b_blkno % dmmax;
4312490Ssam 		if (off+sz > dmmax) {
4412490Ssam 			bp->b_flags |= B_ERROR;
4512490Ssam 			iodone(bp);
4612490Ssam 			return;
4712490Ssam 		}
4812490Ssam 		seg = bp->b_blkno / dmmax;
4912490Ssam 		dev = swdevt[seg % nswdev].sw_dev;
5012490Ssam 		seg /= nswdev;
5112490Ssam 		bp->b_blkno = seg*dmmax + off;
5212490Ssam 	} else
5312490Ssam 		dev = swdevt[0].sw_dev;
541404Sbill 	bp->b_dev = dev;
551404Sbill 	if (dev == 0)
561404Sbill 		panic("swstrategy");
571404Sbill 	(*bdevsw[major(dev)].d_strategy)(bp);
581404Sbill }
591404Sbill 
607828Sroot swread(dev, uio)
617828Sroot 	dev_t dev;
627828Sroot 	struct uio *uio;
631404Sbill {
641404Sbill 
658819Sroot 	return (physio(swstrategy, &rswbuf, dev, B_READ, minphys, uio));
661404Sbill }
671404Sbill 
687828Sroot swwrite(dev, uio)
697828Sroot 	dev_t dev;
707828Sroot 	struct uio *uio;
711404Sbill {
721404Sbill 
738819Sroot 	return (physio(swstrategy, &rswbuf, dev, B_WRITE, minphys, uio));
741404Sbill }
751404Sbill 
761404Sbill /*
771404Sbill  * System call swapon(name) enables swapping on device name,
781404Sbill  * which must be in the swdevsw.  Return EBUSY
791404Sbill  * if already swapping on this device.
801404Sbill  */
8112359Ssam swapon()
821404Sbill {
8312359Ssam 	struct a {
8412359Ssam 		char	*name;
85*16695Smckusick 	} *uap = (struct a *)u.u_ap;
861404Sbill 	register struct inode *ip;
871404Sbill 	dev_t dev;
881404Sbill 	register struct swdevt *sp;
89*16695Smckusick 	register struct nameidata *ndp = &u.u_nd;
901404Sbill 
91*16695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
92*16695Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
93*16695Smckusick 	ndp->ni_dirp = uap->name;
94*16695Smckusick 	ip = namei(ndp);
951404Sbill 	if (ip == NULL)
961404Sbill 		return;
971404Sbill 	if ((ip->i_mode&IFMT) != IFBLK) {
981404Sbill 		u.u_error = ENOTBLK;
991404Sbill 		iput(ip);
1001404Sbill 		return;
1011404Sbill 	}
1027278Swnj 	dev = (dev_t)ip->i_rdev;
1031404Sbill 	iput(ip);
1041404Sbill 	if (major(dev) >= nblkdev) {
1051404Sbill 		u.u_error = ENXIO;
1061404Sbill 		return;
1071404Sbill 	}
1081404Sbill 	/*
1091404Sbill 	 * Search starting at second table entry,
1101404Sbill 	 * since first (primary swap area) is freed at boot.
1111404Sbill 	 */
1121404Sbill 	for (sp = &swdevt[1]; sp->sw_dev; sp++)
1131404Sbill 		if (sp->sw_dev == dev) {
1141404Sbill 			if (sp->sw_freed) {
1151404Sbill 				u.u_error = EBUSY;
1161404Sbill 				return;
1171404Sbill 			}
1181404Sbill 			swfree(sp - swdevt);
1191404Sbill 			return;
1201404Sbill 		}
1211404Sbill 	u.u_error = ENODEV;
1221404Sbill }
1231404Sbill 
1241404Sbill /*
1251404Sbill  * Swfree(index) frees the index'th portion of the swap map.
1261404Sbill  * Each of the nswdev devices provides 1/nswdev'th of the swap
12712490Ssam  * space, which is laid out with blocks of dmmax pages circularly
1281404Sbill  * among the devices.
1291404Sbill  */
1301404Sbill swfree(index)
1311404Sbill 	int index;
1321404Sbill {
1331404Sbill 	register swblk_t vsbase;
1348772Sroot 	register long blk;
1358961Sroot 	dev_t dev;
13612490Ssam 	register swblk_t dvbase;
13712490Ssam 	register int nblks;
1381404Sbill 
1398961Sroot 	dev = swdevt[index].sw_dev;
1408961Sroot 	(*bdevsw[major(dev)].d_open)(dev, FREAD|FWRITE);
1411404Sbill 	swdevt[index].sw_freed = 1;
14212490Ssam 	nblks = swdevt[index].sw_nblks;
14312490Ssam 	for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
14412490Ssam 		blk = nblks - dvbase;
14512490Ssam 		if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
14612490Ssam 			panic("swfree");
14712490Ssam 		if (blk > dmmax)
14812490Ssam 			blk = dmmax;
1491404Sbill 		if (vsbase == 0) {
1501404Sbill 			/*
1511404Sbill 			 * Can't free a block starting at 0 in the swapmap
1522788Swnj 			 * but need some space for argmap so use 1/2 this
1531404Sbill 			 * hunk which needs special treatment anyways.
1541404Sbill 			 */
1551404Sbill 			argdev = swdevt[0].sw_dev;
1568961Sroot 			rminit(argmap, (long)(blk/2-ctod(CLSIZE)),
1578961Sroot 			    (long)ctod(CLSIZE), "argmap", ARGMAPSIZE);
1582788Swnj 			/*
1592788Swnj 			 * First of all chunks... initialize the swapmap
1602788Swnj 			 * the second half of the hunk.
1612788Swnj 			 */
1628794Sroot 			rminit(swapmap, (long)blk/2, (long)blk/2,
1638794Sroot 			    "swap", nswapmap);
1641404Sbill 		} else
1652788Swnj 			rmfree(swapmap, blk, vsbase);
1661404Sbill 	}
1671404Sbill }
168