xref: /csrg-svn/sys/vm/vm_swap.c (revision 40652)
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*40652Smckusick  *	@(#)vm_swap.c	7.11 (Berkeley) 03/27/90
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"
26*40652Smckusick #include "specdev.h"
2717107Sbloom #include "map.h"
2817107Sbloom #include "file.h"
291404Sbill 
301404Sbill /*
311404Sbill  * Indirect driver for multi-controller paging.
321404Sbill  */
331404Sbill swstrategy(bp)
341404Sbill 	register struct buf *bp;
351404Sbill {
3630750Skarels 	int sz, off, seg, index;
3730750Skarels 	register struct swdevt *sp;
3839894Smckusick 	struct vnode *vp;
391404Sbill 
407435Sroot #ifdef GENERIC
417435Sroot 	/*
427435Sroot 	 * A mini-root gets copied into the front of the swap
437435Sroot 	 * and we run over top of the swap area just long
447435Sroot 	 * enough for us to do a mkfs and restor of the real
457435Sroot 	 * root (sure beats rewriting standalone restor).
467435Sroot 	 */
4711051Ssam #define	MINIROOTSIZE	4096
487435Sroot 	if (rootdev == dumpdev)
497435Sroot 		bp->b_blkno += MINIROOTSIZE;
507435Sroot #endif
519010Sroot 	sz = howmany(bp->b_bcount, DEV_BSIZE);
5212490Ssam 	if (bp->b_blkno+sz > nswap) {
531404Sbill 		bp->b_flags |= B_ERROR;
5430750Skarels 		biodone(bp);
551404Sbill 		return;
561404Sbill 	}
5712490Ssam 	if (nswdev > 1) {
5812490Ssam 		off = bp->b_blkno % dmmax;
5912490Ssam 		if (off+sz > dmmax) {
6012490Ssam 			bp->b_flags |= B_ERROR;
6130750Skarels 			biodone(bp);
6212490Ssam 			return;
6312490Ssam 		}
6412490Ssam 		seg = bp->b_blkno / dmmax;
6530750Skarels 		index = seg % nswdev;
6612490Ssam 		seg /= nswdev;
6712490Ssam 		bp->b_blkno = seg*dmmax + off;
6812490Ssam 	} else
6930750Skarels 		index = 0;
7030750Skarels 	sp = &swdevt[index];
7139894Smckusick 	if ((bp->b_dev = sp->sw_dev) == 0)
721404Sbill 		panic("swstrategy");
7339304Smckusick 	if (sp->sw_vp == NULL) {
7439304Smckusick 		bp->b_error |= B_ERROR;
7539304Smckusick 		biodone(bp);
7639304Smckusick 		return;
7739304Smckusick 	}
7839806Smckusick 	VHOLD(sp->sw_vp);
7939880Smckusick 	if ((bp->b_flags & B_READ) == 0) {
8039894Smckusick 		if (vp = bp->b_vp) {
8139894Smckusick 			vp->v_numoutput--;
8239894Smckusick 			if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {
8339894Smckusick 				vp->v_flag &= ~VBWAIT;
8439894Smckusick 				wakeup((caddr_t)&vp->v_numoutput);
8539894Smckusick 			}
8639880Smckusick 		}
8739880Smckusick 		sp->sw_vp->v_numoutput++;
8839880Smckusick 	}
8939894Smckusick 	if (bp->b_vp != NULL)
9039894Smckusick 		brelvp(bp);
9137729Smckusick 	bp->b_vp = sp->sw_vp;
9237729Smckusick 	VOP_STRATEGY(bp);
931404Sbill }
941404Sbill 
951404Sbill /*
961404Sbill  * System call swapon(name) enables swapping on device name,
971404Sbill  * which must be in the swdevsw.  Return EBUSY
981404Sbill  * if already swapping on this device.
991404Sbill  */
10012359Ssam swapon()
1011404Sbill {
10212359Ssam 	struct a {
10312359Ssam 		char	*name;
10416695Smckusick 	} *uap = (struct a *)u.u_ap;
10537729Smckusick 	register struct vnode *vp;
1061404Sbill 	dev_t dev;
1071404Sbill 	register struct swdevt *sp;
10816695Smckusick 	register struct nameidata *ndp = &u.u_nd;
1091404Sbill 
11037552Smckusick 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
11121017Smckusick 		return;
11216695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
11316695Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
11416695Smckusick 	ndp->ni_dirp = uap->name;
11537729Smckusick 	if (u.u_error = namei(ndp))
1161404Sbill 		return;
11737729Smckusick 	vp = ndp->ni_vp;
11837729Smckusick 	if (vp->v_type != VBLK) {
11937729Smckusick 		vrele(vp);
1201404Sbill 		u.u_error = ENOTBLK;
1211404Sbill 		return;
1221404Sbill 	}
12337729Smckusick 	dev = (dev_t)vp->v_rdev;
1241404Sbill 	if (major(dev) >= nblkdev) {
12537729Smckusick 		vrele(vp);
1261404Sbill 		u.u_error = ENXIO;
1271404Sbill 		return;
1281404Sbill 	}
12917879Sbloom 	for (sp = &swdevt[0]; sp->sw_dev; sp++)
1301404Sbill 		if (sp->sw_dev == dev) {
1311404Sbill 			if (sp->sw_freed) {
13237729Smckusick 				vrele(vp);
1331404Sbill 				u.u_error = EBUSY;
1341404Sbill 				return;
1351404Sbill 			}
13637729Smckusick 			sp->sw_vp = vp;
13737729Smckusick 			if (u.u_error = swfree(sp - swdevt)) {
13837729Smckusick 				vrele(vp);
13937729Smckusick 				return;
14037729Smckusick 			}
1411404Sbill 			return;
1421404Sbill 		}
14337729Smckusick 	vrele(vp);
14417879Sbloom 	u.u_error = EINVAL;
1451404Sbill }
1461404Sbill 
1471404Sbill /*
1481404Sbill  * Swfree(index) frees the index'th portion of the swap map.
1491404Sbill  * Each of the nswdev devices provides 1/nswdev'th of the swap
15012490Ssam  * space, which is laid out with blocks of dmmax pages circularly
1511404Sbill  * among the devices.
1521404Sbill  */
1531404Sbill swfree(index)
1541404Sbill 	int index;
1551404Sbill {
15630750Skarels 	register struct swdevt *sp;
1571404Sbill 	register swblk_t vsbase;
1588772Sroot 	register long blk;
15937729Smckusick 	struct vnode *vp;
16012490Ssam 	register swblk_t dvbase;
16112490Ssam 	register int nblks;
16230750Skarels 	int error;
1631404Sbill 
16430750Skarels 	sp = &swdevt[index];
16537729Smckusick 	vp = sp->sw_vp;
16637729Smckusick 	if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred))
16730750Skarels 		return (error);
16830750Skarels 	sp->sw_freed = 1;
16930750Skarels 	nblks = sp->sw_nblks;
17012490Ssam 	for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
17112490Ssam 		blk = nblks - dvbase;
17212490Ssam 		if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
17312490Ssam 			panic("swfree");
17412490Ssam 		if (blk > dmmax)
17512490Ssam 			blk = dmmax;
1761404Sbill 		if (vsbase == 0) {
1771404Sbill 			/*
1781404Sbill 			 * Can't free a block starting at 0 in the swapmap
1792788Swnj 			 * but need some space for argmap so use 1/2 this
1801404Sbill 			 * hunk which needs special treatment anyways.
1811404Sbill 			 */
18230750Skarels 			argdev = sp->sw_dev;
18337729Smckusick 			if (argdev_vp)
18437729Smckusick 				vrele(argdev_vp);
18538349Smckusick 			VREF(vp);
18637729Smckusick 			argdev_vp = vp;
1878961Sroot 			rminit(argmap, (long)(blk/2-ctod(CLSIZE)),
1888961Sroot 			    (long)ctod(CLSIZE), "argmap", ARGMAPSIZE);
1892788Swnj 			/*
1902788Swnj 			 * First of all chunks... initialize the swapmap
1912788Swnj 			 * the second half of the hunk.
1922788Swnj 			 */
19337729Smckusick 			rminit(swapmap, (long)(blk/2), (long)(blk/2),
1948794Sroot 			    "swap", nswapmap);
19530750Skarels 		} else if (dvbase == 0) {
19630750Skarels 			/*
19730750Skarels 			 * Don't use the first cluster of the device
19830750Skarels 			 * in case it starts with a label or boot block.
19930750Skarels 			 */
20030750Skarels 			rmfree(swapmap, blk - ctod(CLSIZE),
20130750Skarels 			    vsbase + ctod(CLSIZE));
2021404Sbill 		} else
2032788Swnj 			rmfree(swapmap, blk, vsbase);
2041404Sbill 	}
20530750Skarels 	return (0);
2061404Sbill }
207