xref: /csrg-svn/sys/vm/vm_swap.c (revision 44462)
123460Smckusick /*
237729Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337729Smckusick  * All rights reserved.
423460Smckusick  *
5*44462Sbostic  * %sccs.include.redist.c%
637729Smckusick  *
7*44462Sbostic  *	@(#)vm_swap.c	7.14 (Berkeley) 06/28/90
823460Smckusick  */
91404Sbill 
1017107Sbloom #include "param.h"
1117107Sbloom #include "systm.h"
1217107Sbloom #include "buf.h"
1317107Sbloom #include "conf.h"
1444409Skarels #include "user.h"
1537729Smckusick #include "vnode.h"
1640652Smckusick #include "specdev.h"
1717107Sbloom #include "map.h"
1817107Sbloom #include "file.h"
191404Sbill 
201404Sbill /*
211404Sbill  * Indirect driver for multi-controller paging.
221404Sbill  */
231404Sbill swstrategy(bp)
241404Sbill 	register struct buf *bp;
251404Sbill {
2630750Skarels 	int sz, off, seg, index;
2730750Skarels 	register struct swdevt *sp;
2839894Smckusick 	struct vnode *vp;
291404Sbill 
307435Sroot #ifdef GENERIC
317435Sroot 	/*
327435Sroot 	 * A mini-root gets copied into the front of the swap
337435Sroot 	 * and we run over top of the swap area just long
347435Sroot 	 * enough for us to do a mkfs and restor of the real
357435Sroot 	 * root (sure beats rewriting standalone restor).
367435Sroot 	 */
3711051Ssam #define	MINIROOTSIZE	4096
387435Sroot 	if (rootdev == dumpdev)
397435Sroot 		bp->b_blkno += MINIROOTSIZE;
407435Sroot #endif
419010Sroot 	sz = howmany(bp->b_bcount, DEV_BSIZE);
4212490Ssam 	if (bp->b_blkno+sz > nswap) {
431404Sbill 		bp->b_flags |= B_ERROR;
4430750Skarels 		biodone(bp);
451404Sbill 		return;
461404Sbill 	}
4712490Ssam 	if (nswdev > 1) {
4812490Ssam 		off = bp->b_blkno % dmmax;
4912490Ssam 		if (off+sz > dmmax) {
5012490Ssam 			bp->b_flags |= B_ERROR;
5130750Skarels 			biodone(bp);
5212490Ssam 			return;
5312490Ssam 		}
5412490Ssam 		seg = bp->b_blkno / dmmax;
5530750Skarels 		index = seg % nswdev;
5612490Ssam 		seg /= nswdev;
5712490Ssam 		bp->b_blkno = seg*dmmax + off;
5812490Ssam 	} else
5930750Skarels 		index = 0;
6030750Skarels 	sp = &swdevt[index];
6139894Smckusick 	if ((bp->b_dev = sp->sw_dev) == 0)
621404Sbill 		panic("swstrategy");
6339304Smckusick 	if (sp->sw_vp == NULL) {
6439304Smckusick 		bp->b_error |= B_ERROR;
6539304Smckusick 		biodone(bp);
6639304Smckusick 		return;
6739304Smckusick 	}
6839806Smckusick 	VHOLD(sp->sw_vp);
6939880Smckusick 	if ((bp->b_flags & B_READ) == 0) {
7039894Smckusick 		if (vp = bp->b_vp) {
7139894Smckusick 			vp->v_numoutput--;
7239894Smckusick 			if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {
7339894Smckusick 				vp->v_flag &= ~VBWAIT;
7439894Smckusick 				wakeup((caddr_t)&vp->v_numoutput);
7539894Smckusick 			}
7639880Smckusick 		}
7739880Smckusick 		sp->sw_vp->v_numoutput++;
7839880Smckusick 	}
7939894Smckusick 	if (bp->b_vp != NULL)
8039894Smckusick 		brelvp(bp);
8137729Smckusick 	bp->b_vp = sp->sw_vp;
8237729Smckusick 	VOP_STRATEGY(bp);
831404Sbill }
841404Sbill 
851404Sbill /*
861404Sbill  * System call swapon(name) enables swapping on device name,
871404Sbill  * which must be in the swdevsw.  Return EBUSY
881404Sbill  * if already swapping on this device.
891404Sbill  */
9043376Smckusick /* ARGSUSED */
9143376Smckusick swapon(p, uap, retval)
9243376Smckusick 	struct proc *p;
9343376Smckusick 	struct args {
9443376Smckusick 		char	*name;
9543376Smckusick 	} *uap;
9643376Smckusick 	int *retval;
971404Sbill {
9837729Smckusick 	register struct vnode *vp;
991404Sbill 	register struct swdevt *sp;
10016695Smckusick 	register struct nameidata *ndp = &u.u_nd;
10143376Smckusick 	dev_t dev;
10243376Smckusick 	int error;
1031404Sbill 
10443376Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
10544409Skarels 		return (error);
10616695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
10716695Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
10816695Smckusick 	ndp->ni_dirp = uap->name;
10943376Smckusick 	if (error = namei(ndp))
11044409Skarels 		return (error);
11137729Smckusick 	vp = ndp->ni_vp;
11237729Smckusick 	if (vp->v_type != VBLK) {
11337729Smckusick 		vrele(vp);
11444409Skarels 		return (ENOTBLK);
1151404Sbill 	}
11637729Smckusick 	dev = (dev_t)vp->v_rdev;
1171404Sbill 	if (major(dev) >= nblkdev) {
11837729Smckusick 		vrele(vp);
11944409Skarels 		return (ENXIO);
1201404Sbill 	}
12117879Sbloom 	for (sp = &swdevt[0]; sp->sw_dev; sp++)
1221404Sbill 		if (sp->sw_dev == dev) {
1231404Sbill 			if (sp->sw_freed) {
12437729Smckusick 				vrele(vp);
12544409Skarels 				return (EBUSY);
1261404Sbill 			}
12737729Smckusick 			sp->sw_vp = vp;
12843376Smckusick 			if (error = swfree(sp - swdevt)) {
12937729Smckusick 				vrele(vp);
13044409Skarels 				return (error);
13137729Smckusick 			}
13244409Skarels 			return (0);
1331404Sbill 		}
13437729Smckusick 	vrele(vp);
13544409Skarels 	return (EINVAL);
1361404Sbill }
1371404Sbill 
1381404Sbill /*
1391404Sbill  * Swfree(index) frees the index'th portion of the swap map.
1401404Sbill  * Each of the nswdev devices provides 1/nswdev'th of the swap
14112490Ssam  * space, which is laid out with blocks of dmmax pages circularly
1421404Sbill  * among the devices.
1431404Sbill  */
1441404Sbill swfree(index)
1451404Sbill 	int index;
1461404Sbill {
14730750Skarels 	register struct swdevt *sp;
1481404Sbill 	register swblk_t vsbase;
1498772Sroot 	register long blk;
15037729Smckusick 	struct vnode *vp;
15112490Ssam 	register swblk_t dvbase;
15212490Ssam 	register int nblks;
15330750Skarels 	int error;
1541404Sbill 
15530750Skarels 	sp = &swdevt[index];
15637729Smckusick 	vp = sp->sw_vp;
15737729Smckusick 	if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred))
15830750Skarels 		return (error);
15930750Skarels 	sp->sw_freed = 1;
16030750Skarels 	nblks = sp->sw_nblks;
16112490Ssam 	for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
16212490Ssam 		blk = nblks - dvbase;
16312490Ssam 		if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
16412490Ssam 			panic("swfree");
16512490Ssam 		if (blk > dmmax)
16612490Ssam 			blk = dmmax;
1671404Sbill 		if (vsbase == 0) {
1681404Sbill 			/*
1691404Sbill 			 * Can't free a block starting at 0 in the swapmap
1702788Swnj 			 * but need some space for argmap so use 1/2 this
1711404Sbill 			 * hunk which needs special treatment anyways.
1721404Sbill 			 */
17330750Skarels 			argdev = sp->sw_dev;
17437729Smckusick 			if (argdev_vp)
17537729Smckusick 				vrele(argdev_vp);
17638349Smckusick 			VREF(vp);
17737729Smckusick 			argdev_vp = vp;
1788961Sroot 			rminit(argmap, (long)(blk/2-ctod(CLSIZE)),
1798961Sroot 			    (long)ctod(CLSIZE), "argmap", ARGMAPSIZE);
1802788Swnj 			/*
1812788Swnj 			 * First of all chunks... initialize the swapmap
1822788Swnj 			 * the second half of the hunk.
1832788Swnj 			 */
18437729Smckusick 			rminit(swapmap, (long)(blk/2), (long)(blk/2),
1858794Sroot 			    "swap", nswapmap);
18630750Skarels 		} else if (dvbase == 0) {
18730750Skarels 			/*
18830750Skarels 			 * Don't use the first cluster of the device
18930750Skarels 			 * in case it starts with a label or boot block.
19030750Skarels 			 */
19130750Skarels 			rmfree(swapmap, blk - ctod(CLSIZE),
19230750Skarels 			    vsbase + ctod(CLSIZE));
1931404Sbill 		} else
1942788Swnj 			rmfree(swapmap, blk, vsbase);
1951404Sbill 	}
19630750Skarels 	return (0);
1971404Sbill }
198