xref: /csrg-svn/sys/vm/vm_swap.c (revision 48041)
123460Smckusick /*
237729Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337729Smckusick  * All rights reserved.
423460Smckusick  *
544462Sbostic  * %sccs.include.redist.c%
637729Smckusick  *
7*48041Smckusick  *	@(#)vm_swap.c	7.17 (Berkeley) 04/16/91
823460Smckusick  */
91404Sbill 
1017107Sbloom #include "param.h"
1117107Sbloom #include "systm.h"
1217107Sbloom #include "buf.h"
1317107Sbloom #include "conf.h"
1447976Skarels #include "proc.h"
1547976Skarels #include "namei.h"
1647976Skarels #include "dmap.h"		/* XXX */
1737729Smckusick #include "vnode.h"
1840652Smckusick #include "specdev.h"
1917107Sbloom #include "map.h"
2017107Sbloom #include "file.h"
211404Sbill 
221404Sbill /*
231404Sbill  * Indirect driver for multi-controller paging.
241404Sbill  */
2547976Skarels 
2647976Skarels /*
2747976Skarels  * Set up swap devices.
2847976Skarels  * Initialize linked list of free swap
2947976Skarels  * headers. These do not actually point
3047976Skarels  * to buffers, but rather to pages that
3147976Skarels  * are being swapped in and out.
3247976Skarels  */
3347976Skarels swapinit()
3447976Skarels {
3547976Skarels 	register int i;
3647976Skarels 	register struct buf *sp = swbuf;
3747976Skarels 	struct swdevt *swp;
3847976Skarels 	int error;
3947976Skarels 
4047976Skarels 	/*
4147976Skarels 	 * Count swap devices, and adjust total swap space available.
4247976Skarels 	 * Some of this space will not be available until a swapon()
4347976Skarels 	 * system is issued, usually when the system goes multi-user.
4447976Skarels 	 */
4547976Skarels 	nswdev = 0;
4647976Skarels 	nswap = 0;
4747976Skarels 	for (swp = swdevt; swp->sw_dev; swp++) {
4847976Skarels 		nswdev++;
4947976Skarels 		if (swp->sw_nblks > nswap)
5047976Skarels 			nswap = swp->sw_nblks;
5147976Skarels 	}
5247976Skarels 	if (nswdev == 0)
5347976Skarels 		panic("swapinit");
5447976Skarels 	if (nswdev > 1)
5547976Skarels 		nswap = ((nswap + dmmax - 1) / dmmax) * dmmax;
5647976Skarels 	nswap *= nswdev;
5747976Skarels 	if (bdevvp(swdevt[0].sw_dev, &swdevt[0].sw_vp))
5847976Skarels 		panic("swapvp");
5947976Skarels 	if (error = swfree(&proc0, 0)) {
6047976Skarels 		printf("swfree errno %d\n", error);	/* XXX */
6147976Skarels 		panic("swapinit swfree 0");
6247976Skarels 	}
6347976Skarels 
6447976Skarels 	/*
6547976Skarels 	 * Now set up swap buffer headers.
6647976Skarels 	 */
6747976Skarels 	bswlist.av_forw = sp;
6847976Skarels 	for (i = 0; i < nswbuf - 1; i++, sp++)
6947976Skarels 		sp->av_forw = sp + 1;
7047976Skarels 	sp->av_forw = NULL;
7147976Skarels }
7247976Skarels 
731404Sbill swstrategy(bp)
741404Sbill 	register struct buf *bp;
751404Sbill {
7630750Skarels 	int sz, off, seg, index;
7730750Skarels 	register struct swdevt *sp;
7839894Smckusick 	struct vnode *vp;
791404Sbill 
807435Sroot #ifdef GENERIC
817435Sroot 	/*
827435Sroot 	 * A mini-root gets copied into the front of the swap
837435Sroot 	 * and we run over top of the swap area just long
847435Sroot 	 * enough for us to do a mkfs and restor of the real
857435Sroot 	 * root (sure beats rewriting standalone restor).
867435Sroot 	 */
8711051Ssam #define	MINIROOTSIZE	4096
887435Sroot 	if (rootdev == dumpdev)
897435Sroot 		bp->b_blkno += MINIROOTSIZE;
907435Sroot #endif
919010Sroot 	sz = howmany(bp->b_bcount, DEV_BSIZE);
9247976Skarels 	if (bp->b_blkno + sz > nswap) {
931404Sbill 		bp->b_flags |= B_ERROR;
9430750Skarels 		biodone(bp);
951404Sbill 		return;
961404Sbill 	}
9712490Ssam 	if (nswdev > 1) {
9812490Ssam 		off = bp->b_blkno % dmmax;
9912490Ssam 		if (off+sz > dmmax) {
10012490Ssam 			bp->b_flags |= B_ERROR;
10130750Skarels 			biodone(bp);
10212490Ssam 			return;
10312490Ssam 		}
10412490Ssam 		seg = bp->b_blkno / dmmax;
10530750Skarels 		index = seg % nswdev;
10612490Ssam 		seg /= nswdev;
10712490Ssam 		bp->b_blkno = seg*dmmax + off;
10812490Ssam 	} else
10930750Skarels 		index = 0;
11030750Skarels 	sp = &swdevt[index];
11139894Smckusick 	if ((bp->b_dev = sp->sw_dev) == 0)
1121404Sbill 		panic("swstrategy");
11339304Smckusick 	if (sp->sw_vp == NULL) {
11439304Smckusick 		bp->b_error |= B_ERROR;
11539304Smckusick 		biodone(bp);
11639304Smckusick 		return;
11739304Smckusick 	}
11839806Smckusick 	VHOLD(sp->sw_vp);
11939880Smckusick 	if ((bp->b_flags & B_READ) == 0) {
12039894Smckusick 		if (vp = bp->b_vp) {
12139894Smckusick 			vp->v_numoutput--;
12239894Smckusick 			if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {
12339894Smckusick 				vp->v_flag &= ~VBWAIT;
12439894Smckusick 				wakeup((caddr_t)&vp->v_numoutput);
12539894Smckusick 			}
12639880Smckusick 		}
12739880Smckusick 		sp->sw_vp->v_numoutput++;
12839880Smckusick 	}
12939894Smckusick 	if (bp->b_vp != NULL)
13039894Smckusick 		brelvp(bp);
13137729Smckusick 	bp->b_vp = sp->sw_vp;
13237729Smckusick 	VOP_STRATEGY(bp);
1331404Sbill }
1341404Sbill 
1351404Sbill /*
1361404Sbill  * System call swapon(name) enables swapping on device name,
1371404Sbill  * which must be in the swdevsw.  Return EBUSY
1381404Sbill  * if already swapping on this device.
1391404Sbill  */
14043376Smckusick /* ARGSUSED */
14143376Smckusick swapon(p, uap, retval)
14243376Smckusick 	struct proc *p;
14343376Smckusick 	struct args {
14443376Smckusick 		char	*name;
14543376Smckusick 	} *uap;
14643376Smckusick 	int *retval;
1471404Sbill {
14837729Smckusick 	register struct vnode *vp;
1491404Sbill 	register struct swdevt *sp;
15047976Skarels 	register struct nameidata *ndp;
15143376Smckusick 	dev_t dev;
15243376Smckusick 	int error;
15347976Skarels 	struct nameidata nd;
1541404Sbill 
15547976Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
15644409Skarels 		return (error);
15747976Skarels 	ndp = &nd;
15816695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
15916695Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
16016695Smckusick 	ndp->ni_dirp = uap->name;
16147976Skarels 	if (error = namei(ndp, p))
16244409Skarels 		return (error);
16337729Smckusick 	vp = ndp->ni_vp;
16437729Smckusick 	if (vp->v_type != VBLK) {
16537729Smckusick 		vrele(vp);
16644409Skarels 		return (ENOTBLK);
1671404Sbill 	}
16837729Smckusick 	dev = (dev_t)vp->v_rdev;
1691404Sbill 	if (major(dev) >= nblkdev) {
17037729Smckusick 		vrele(vp);
17144409Skarels 		return (ENXIO);
1721404Sbill 	}
17317879Sbloom 	for (sp = &swdevt[0]; sp->sw_dev; sp++)
1741404Sbill 		if (sp->sw_dev == dev) {
1751404Sbill 			if (sp->sw_freed) {
17637729Smckusick 				vrele(vp);
17744409Skarels 				return (EBUSY);
1781404Sbill 			}
17937729Smckusick 			sp->sw_vp = vp;
18047976Skarels 			if (error = swfree(p, sp - swdevt)) {
18137729Smckusick 				vrele(vp);
18244409Skarels 				return (error);
18337729Smckusick 			}
18444409Skarels 			return (0);
1851404Sbill 		}
18637729Smckusick 	vrele(vp);
18744409Skarels 	return (EINVAL);
1881404Sbill }
1891404Sbill 
1901404Sbill /*
1911404Sbill  * Swfree(index) frees the index'th portion of the swap map.
1921404Sbill  * Each of the nswdev devices provides 1/nswdev'th of the swap
19312490Ssam  * space, which is laid out with blocks of dmmax pages circularly
1941404Sbill  * among the devices.
1951404Sbill  */
19647976Skarels swfree(p, index)
19747976Skarels 	struct proc *p;
1981404Sbill 	int index;
1991404Sbill {
20030750Skarels 	register struct swdevt *sp;
2011404Sbill 	register swblk_t vsbase;
2028772Sroot 	register long blk;
20337729Smckusick 	struct vnode *vp;
20412490Ssam 	register swblk_t dvbase;
20512490Ssam 	register int nblks;
20630750Skarels 	int error;
2071404Sbill 
20830750Skarels 	sp = &swdevt[index];
20937729Smckusick 	vp = sp->sw_vp;
210*48041Smckusick 	if (error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p))
21130750Skarels 		return (error);
21230750Skarels 	sp->sw_freed = 1;
21330750Skarels 	nblks = sp->sw_nblks;
21412490Ssam 	for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
21512490Ssam 		blk = nblks - dvbase;
21612490Ssam 		if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
21712490Ssam 			panic("swfree");
21812490Ssam 		if (blk > dmmax)
21912490Ssam 			blk = dmmax;
2201404Sbill 		if (vsbase == 0) {
2211404Sbill 			/*
2222788Swnj 			 * First of all chunks... initialize the swapmap
2232788Swnj 			 * the second half of the hunk.
2242788Swnj 			 */
22537729Smckusick 			rminit(swapmap, (long)(blk/2), (long)(blk/2),
2268794Sroot 			    "swap", nswapmap);
22730750Skarels 		} else if (dvbase == 0) {
22830750Skarels 			/*
22930750Skarels 			 * Don't use the first cluster of the device
23030750Skarels 			 * in case it starts with a label or boot block.
23130750Skarels 			 */
23230750Skarels 			rmfree(swapmap, blk - ctod(CLSIZE),
23330750Skarels 			    vsbase + ctod(CLSIZE));
2341404Sbill 		} else
2352788Swnj 			rmfree(swapmap, blk, vsbase);
2361404Sbill 	}
23730750Skarels 	return (0);
2381404Sbill }
239