xref: /csrg-svn/sys/vm/vm_swap.c (revision 39304)
123460Smckusick /*
237729Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337729Smckusick  * All rights reserved.
423460Smckusick  *
537729Smckusick  * Redistribution and use in source and binary forms are permitted
637729Smckusick  * provided that the above copyright notice and this paragraph are
737729Smckusick  * duplicated in all such forms and that any documentation,
837729Smckusick  * advertising materials, and other materials related to such
937729Smckusick  * distribution and use acknowledge that the software was developed
1037729Smckusick  * by the University of California, Berkeley.  The name of the
1137729Smckusick  * University may not be used to endorse or promote products derived
1237729Smckusick  * from this software without specific prior written permission.
1337729Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1437729Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1537729Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1637729Smckusick  *
17*39304Smckusick  *	@(#)vm_swap.c	7.7 (Berkeley) 10/15/89
1823460Smckusick  */
191404Sbill 
2017107Sbloom #include "param.h"
2117107Sbloom #include "systm.h"
2217107Sbloom #include "buf.h"
2317107Sbloom #include "conf.h"
2417107Sbloom #include "user.h"
2537729Smckusick #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");
7237729Smckusick 	if (bp->b_vp)
7337729Smckusick 		brelvp(bp);
74*39304Smckusick 	if (sp->sw_vp == NULL) {
75*39304Smckusick 		bp->b_error |= B_ERROR;
76*39304Smckusick 		biodone(bp);
77*39304Smckusick 		return;
78*39304Smckusick 	}
7938349Smckusick 	VREF(sp->sw_vp);
8037729Smckusick 	bp->b_vp = sp->sw_vp;
8137729Smckusick 	VOP_STRATEGY(bp);
821404Sbill }
831404Sbill 
841404Sbill /*
851404Sbill  * System call swapon(name) enables swapping on device name,
861404Sbill  * which must be in the swdevsw.  Return EBUSY
871404Sbill  * if already swapping on this device.
881404Sbill  */
8912359Ssam swapon()
901404Sbill {
9112359Ssam 	struct a {
9212359Ssam 		char	*name;
9316695Smckusick 	} *uap = (struct a *)u.u_ap;
9437729Smckusick 	register struct vnode *vp;
951404Sbill 	dev_t dev;
961404Sbill 	register struct swdevt *sp;
9716695Smckusick 	register struct nameidata *ndp = &u.u_nd;
981404Sbill 
9937552Smckusick 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
10021017Smckusick 		return;
10116695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
10216695Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
10316695Smckusick 	ndp->ni_dirp = uap->name;
10437729Smckusick 	if (u.u_error = namei(ndp))
1051404Sbill 		return;
10637729Smckusick 	vp = ndp->ni_vp;
10737729Smckusick 	if (vp->v_type != VBLK) {
10837729Smckusick 		vrele(vp);
1091404Sbill 		u.u_error = ENOTBLK;
1101404Sbill 		return;
1111404Sbill 	}
11237729Smckusick 	dev = (dev_t)vp->v_rdev;
1131404Sbill 	if (major(dev) >= nblkdev) {
11437729Smckusick 		vrele(vp);
1151404Sbill 		u.u_error = ENXIO;
1161404Sbill 		return;
1171404Sbill 	}
11817879Sbloom 	for (sp = &swdevt[0]; sp->sw_dev; sp++)
1191404Sbill 		if (sp->sw_dev == dev) {
1201404Sbill 			if (sp->sw_freed) {
12137729Smckusick 				vrele(vp);
1221404Sbill 				u.u_error = EBUSY;
1231404Sbill 				return;
1241404Sbill 			}
12537729Smckusick 			sp->sw_vp = vp;
12637729Smckusick 			if (u.u_error = swfree(sp - swdevt)) {
12737729Smckusick 				vrele(vp);
12837729Smckusick 				return;
12937729Smckusick 			}
1301404Sbill 			return;
1311404Sbill 		}
13237729Smckusick 	vrele(vp);
13317879Sbloom 	u.u_error = EINVAL;
1341404Sbill }
1351404Sbill 
1361404Sbill /*
1371404Sbill  * Swfree(index) frees the index'th portion of the swap map.
1381404Sbill  * Each of the nswdev devices provides 1/nswdev'th of the swap
13912490Ssam  * space, which is laid out with blocks of dmmax pages circularly
1401404Sbill  * among the devices.
1411404Sbill  */
1421404Sbill swfree(index)
1431404Sbill 	int index;
1441404Sbill {
14530750Skarels 	register struct swdevt *sp;
1461404Sbill 	register swblk_t vsbase;
1478772Sroot 	register long blk;
14837729Smckusick 	struct vnode *vp;
14912490Ssam 	register swblk_t dvbase;
15012490Ssam 	register int nblks;
15130750Skarels 	int error;
1521404Sbill 
15330750Skarels 	sp = &swdevt[index];
15437729Smckusick 	vp = sp->sw_vp;
15537729Smckusick 	if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred))
15630750Skarels 		return (error);
15730750Skarels 	sp->sw_freed = 1;
15830750Skarels 	nblks = sp->sw_nblks;
15912490Ssam 	for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
16012490Ssam 		blk = nblks - dvbase;
16112490Ssam 		if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
16212490Ssam 			panic("swfree");
16312490Ssam 		if (blk > dmmax)
16412490Ssam 			blk = dmmax;
1651404Sbill 		if (vsbase == 0) {
1661404Sbill 			/*
1671404Sbill 			 * Can't free a block starting at 0 in the swapmap
1682788Swnj 			 * but need some space for argmap so use 1/2 this
1691404Sbill 			 * hunk which needs special treatment anyways.
1701404Sbill 			 */
17130750Skarels 			argdev = sp->sw_dev;
17237729Smckusick 			if (argdev_vp)
17337729Smckusick 				vrele(argdev_vp);
17438349Smckusick 			VREF(vp);
17537729Smckusick 			argdev_vp = vp;
1768961Sroot 			rminit(argmap, (long)(blk/2-ctod(CLSIZE)),
1778961Sroot 			    (long)ctod(CLSIZE), "argmap", ARGMAPSIZE);
1782788Swnj 			/*
1792788Swnj 			 * First of all chunks... initialize the swapmap
1802788Swnj 			 * the second half of the hunk.
1812788Swnj 			 */
18237729Smckusick 			rminit(swapmap, (long)(blk/2), (long)(blk/2),
1838794Sroot 			    "swap", nswapmap);
18430750Skarels 		} else if (dvbase == 0) {
18530750Skarels 			/*
18630750Skarels 			 * Don't use the first cluster of the device
18730750Skarels 			 * in case it starts with a label or boot block.
18830750Skarels 			 */
18930750Skarels 			rmfree(swapmap, blk - ctod(CLSIZE),
19030750Skarels 			    vsbase + ctod(CLSIZE));
1911404Sbill 		} else
1922788Swnj 			rmfree(swapmap, blk, vsbase);
1931404Sbill 	}
19430750Skarels 	return (0);
1951404Sbill }
196