xref: /csrg-svn/sys/vm/vm_swap.c (revision 37729)
123460Smckusick /*
2*37729Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3*37729Smckusick  * All rights reserved.
423460Smckusick  *
5*37729Smckusick  * Redistribution and use in source and binary forms are permitted
6*37729Smckusick  * provided that the above copyright notice and this paragraph are
7*37729Smckusick  * duplicated in all such forms and that any documentation,
8*37729Smckusick  * advertising materials, and other materials related to such
9*37729Smckusick  * distribution and use acknowledge that the software was developed
10*37729Smckusick  * by the University of California, Berkeley.  The name of the
11*37729Smckusick  * University may not be used to endorse or promote products derived
12*37729Smckusick  * from this software without specific prior written permission.
13*37729Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*37729Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*37729Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*37729Smckusick  *
17*37729Smckusick  *	@(#)vm_swap.c	7.5 (Berkeley) 05/09/89
1823460Smckusick  */
191404Sbill 
2017107Sbloom #include "param.h"
2117107Sbloom #include "systm.h"
2217107Sbloom #include "buf.h"
2317107Sbloom #include "conf.h"
2417107Sbloom #include "user.h"
25*37729Smckusick #include "vnode.h"
2617107Sbloom #include "map.h"
2717107Sbloom #include "file.h"
281404Sbill 
291404Sbill /*
301404Sbill  * Indirect driver for multi-controller paging.
311404Sbill  */
321404Sbill swstrategy(bp)
331404Sbill 	register struct buf *bp;
341404Sbill {
3530750Skarels 	int sz, off, seg, index;
3630750Skarels 	register struct swdevt *sp;
371404Sbill 
387435Sroot #ifdef GENERIC
397435Sroot 	/*
407435Sroot 	 * A mini-root gets copied into the front of the swap
417435Sroot 	 * and we run over top of the swap area just long
427435Sroot 	 * enough for us to do a mkfs and restor of the real
437435Sroot 	 * root (sure beats rewriting standalone restor).
447435Sroot 	 */
4511051Ssam #define	MINIROOTSIZE	4096
467435Sroot 	if (rootdev == dumpdev)
477435Sroot 		bp->b_blkno += MINIROOTSIZE;
487435Sroot #endif
499010Sroot 	sz = howmany(bp->b_bcount, DEV_BSIZE);
5012490Ssam 	if (bp->b_blkno+sz > nswap) {
511404Sbill 		bp->b_flags |= B_ERROR;
5230750Skarels 		biodone(bp);
531404Sbill 		return;
541404Sbill 	}
5512490Ssam 	if (nswdev > 1) {
5612490Ssam 		off = bp->b_blkno % dmmax;
5712490Ssam 		if (off+sz > dmmax) {
5812490Ssam 			bp->b_flags |= B_ERROR;
5930750Skarels 			biodone(bp);
6012490Ssam 			return;
6112490Ssam 		}
6212490Ssam 		seg = bp->b_blkno / dmmax;
6330750Skarels 		index = seg % nswdev;
6412490Ssam 		seg /= nswdev;
6512490Ssam 		bp->b_blkno = seg*dmmax + off;
6612490Ssam 	} else
6730750Skarels 		index = 0;
6830750Skarels 	sp = &swdevt[index];
6930750Skarels 	bp->b_dev = sp->sw_dev;
7030750Skarels 	if (bp->b_dev == 0)
711404Sbill 		panic("swstrategy");
72*37729Smckusick 	if (bp->b_vp)
73*37729Smckusick 		brelvp(bp);
74*37729Smckusick 	sp->sw_vp->v_count++;
75*37729Smckusick 	bp->b_vp = sp->sw_vp;
76*37729Smckusick 	VOP_STRATEGY(bp);
771404Sbill }
781404Sbill 
791404Sbill /*
801404Sbill  * System call swapon(name) enables swapping on device name,
811404Sbill  * which must be in the swdevsw.  Return EBUSY
821404Sbill  * if already swapping on this device.
831404Sbill  */
8412359Ssam swapon()
851404Sbill {
8612359Ssam 	struct a {
8712359Ssam 		char	*name;
8816695Smckusick 	} *uap = (struct a *)u.u_ap;
89*37729Smckusick 	register struct vnode *vp;
901404Sbill 	dev_t dev;
911404Sbill 	register struct swdevt *sp;
9216695Smckusick 	register struct nameidata *ndp = &u.u_nd;
931404Sbill 
9437552Smckusick 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
9521017Smckusick 		return;
9616695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
9716695Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
9816695Smckusick 	ndp->ni_dirp = uap->name;
99*37729Smckusick 	if (u.u_error = namei(ndp))
1001404Sbill 		return;
101*37729Smckusick 	vp = ndp->ni_vp;
102*37729Smckusick 	if (vp->v_type != VBLK) {
103*37729Smckusick 		vrele(vp);
1041404Sbill 		u.u_error = ENOTBLK;
1051404Sbill 		return;
1061404Sbill 	}
107*37729Smckusick 	dev = (dev_t)vp->v_rdev;
1081404Sbill 	if (major(dev) >= nblkdev) {
109*37729Smckusick 		vrele(vp);
1101404Sbill 		u.u_error = ENXIO;
1111404Sbill 		return;
1121404Sbill 	}
11317879Sbloom 	for (sp = &swdevt[0]; sp->sw_dev; sp++)
1141404Sbill 		if (sp->sw_dev == dev) {
1151404Sbill 			if (sp->sw_freed) {
116*37729Smckusick 				vrele(vp);
1171404Sbill 				u.u_error = EBUSY;
1181404Sbill 				return;
1191404Sbill 			}
120*37729Smckusick 			sp->sw_vp = vp;
121*37729Smckusick 			if (u.u_error = swfree(sp - swdevt)) {
122*37729Smckusick 				vrele(vp);
123*37729Smckusick 				return;
124*37729Smckusick 			}
1251404Sbill 			return;
1261404Sbill 		}
127*37729Smckusick 	vrele(vp);
12817879Sbloom 	u.u_error = EINVAL;
1291404Sbill }
1301404Sbill 
1311404Sbill /*
1321404Sbill  * Swfree(index) frees the index'th portion of the swap map.
1331404Sbill  * Each of the nswdev devices provides 1/nswdev'th of the swap
13412490Ssam  * space, which is laid out with blocks of dmmax pages circularly
1351404Sbill  * among the devices.
1361404Sbill  */
1371404Sbill swfree(index)
1381404Sbill 	int index;
1391404Sbill {
14030750Skarels 	register struct swdevt *sp;
1411404Sbill 	register swblk_t vsbase;
1428772Sroot 	register long blk;
143*37729Smckusick 	struct vnode *vp;
14412490Ssam 	register swblk_t dvbase;
14512490Ssam 	register int nblks;
14630750Skarels 	int error;
1471404Sbill 
14830750Skarels 	sp = &swdevt[index];
149*37729Smckusick 	vp = sp->sw_vp;
150*37729Smckusick 	if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred))
15130750Skarels 		return (error);
15230750Skarels 	sp->sw_freed = 1;
15330750Skarels 	nblks = sp->sw_nblks;
15412490Ssam 	for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
15512490Ssam 		blk = nblks - dvbase;
15612490Ssam 		if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
15712490Ssam 			panic("swfree");
15812490Ssam 		if (blk > dmmax)
15912490Ssam 			blk = dmmax;
1601404Sbill 		if (vsbase == 0) {
1611404Sbill 			/*
1621404Sbill 			 * Can't free a block starting at 0 in the swapmap
1632788Swnj 			 * but need some space for argmap so use 1/2 this
1641404Sbill 			 * hunk which needs special treatment anyways.
1651404Sbill 			 */
16630750Skarels 			argdev = sp->sw_dev;
167*37729Smckusick 			if (argdev_vp)
168*37729Smckusick 				vrele(argdev_vp);
169*37729Smckusick 			vp->v_count++;
170*37729Smckusick 			argdev_vp = vp;
1718961Sroot 			rminit(argmap, (long)(blk/2-ctod(CLSIZE)),
1728961Sroot 			    (long)ctod(CLSIZE), "argmap", ARGMAPSIZE);
1732788Swnj 			/*
1742788Swnj 			 * First of all chunks... initialize the swapmap
1752788Swnj 			 * the second half of the hunk.
1762788Swnj 			 */
177*37729Smckusick 			rminit(swapmap, (long)(blk/2), (long)(blk/2),
1788794Sroot 			    "swap", nswapmap);
17930750Skarels 		} else if (dvbase == 0) {
18030750Skarels 			/*
18130750Skarels 			 * Don't use the first cluster of the device
18230750Skarels 			 * in case it starts with a label or boot block.
18330750Skarels 			 */
18430750Skarels 			rmfree(swapmap, blk - ctod(CLSIZE),
18530750Skarels 			    vsbase + ctod(CLSIZE));
1861404Sbill 		} else
1872788Swnj 			rmfree(swapmap, blk, vsbase);
1881404Sbill 	}
18930750Skarels 	return (0);
1901404Sbill }
191