xref: /csrg-svn/sys/vm/vm_swap.c (revision 52308)
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*52308Smckusick  *	@(#)vm_swap.c	7.19 (Berkeley) 02/03/92
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 
2649228Skarels int	nswap, nswdev;
2749228Skarels 
2847976Skarels /*
2947976Skarels  * Set up swap devices.
3047976Skarels  * Initialize linked list of free swap
3147976Skarels  * headers. These do not actually point
3247976Skarels  * to buffers, but rather to pages that
3347976Skarels  * are being swapped in and out.
3447976Skarels  */
3547976Skarels swapinit()
3647976Skarels {
3747976Skarels 	register int i;
3847976Skarels 	register struct buf *sp = swbuf;
3947976Skarels 	struct swdevt *swp;
4047976Skarels 	int error;
4147976Skarels 
4247976Skarels 	/*
4347976Skarels 	 * Count swap devices, and adjust total swap space available.
4447976Skarels 	 * Some of this space will not be available until a swapon()
4547976Skarels 	 * system is issued, usually when the system goes multi-user.
4647976Skarels 	 */
4747976Skarels 	nswdev = 0;
4847976Skarels 	nswap = 0;
4947976Skarels 	for (swp = swdevt; swp->sw_dev; swp++) {
5047976Skarels 		nswdev++;
5147976Skarels 		if (swp->sw_nblks > nswap)
5247976Skarels 			nswap = swp->sw_nblks;
5347976Skarels 	}
5447976Skarels 	if (nswdev == 0)
5547976Skarels 		panic("swapinit");
5647976Skarels 	if (nswdev > 1)
5747976Skarels 		nswap = ((nswap + dmmax - 1) / dmmax) * dmmax;
5847976Skarels 	nswap *= nswdev;
5947976Skarels 	if (bdevvp(swdevt[0].sw_dev, &swdevt[0].sw_vp))
6047976Skarels 		panic("swapvp");
6147976Skarels 	if (error = swfree(&proc0, 0)) {
6247976Skarels 		printf("swfree errno %d\n", error);	/* XXX */
6347976Skarels 		panic("swapinit swfree 0");
6447976Skarels 	}
6547976Skarels 
6647976Skarels 	/*
6747976Skarels 	 * Now set up swap buffer headers.
6847976Skarels 	 */
6947976Skarels 	bswlist.av_forw = sp;
7047976Skarels 	for (i = 0; i < nswbuf - 1; i++, sp++)
7147976Skarels 		sp->av_forw = sp + 1;
7247976Skarels 	sp->av_forw = NULL;
7347976Skarels }
7447976Skarels 
751404Sbill swstrategy(bp)
761404Sbill 	register struct buf *bp;
771404Sbill {
7830750Skarels 	int sz, off, seg, index;
7930750Skarels 	register struct swdevt *sp;
8039894Smckusick 	struct vnode *vp;
811404Sbill 
827435Sroot #ifdef GENERIC
837435Sroot 	/*
847435Sroot 	 * A mini-root gets copied into the front of the swap
857435Sroot 	 * and we run over top of the swap area just long
867435Sroot 	 * enough for us to do a mkfs and restor of the real
877435Sroot 	 * root (sure beats rewriting standalone restor).
887435Sroot 	 */
8911051Ssam #define	MINIROOTSIZE	4096
907435Sroot 	if (rootdev == dumpdev)
917435Sroot 		bp->b_blkno += MINIROOTSIZE;
927435Sroot #endif
939010Sroot 	sz = howmany(bp->b_bcount, DEV_BSIZE);
9447976Skarels 	if (bp->b_blkno + sz > nswap) {
951404Sbill 		bp->b_flags |= B_ERROR;
9630750Skarels 		biodone(bp);
971404Sbill 		return;
981404Sbill 	}
9912490Ssam 	if (nswdev > 1) {
10012490Ssam 		off = bp->b_blkno % dmmax;
10112490Ssam 		if (off+sz > dmmax) {
10212490Ssam 			bp->b_flags |= B_ERROR;
10330750Skarels 			biodone(bp);
10412490Ssam 			return;
10512490Ssam 		}
10612490Ssam 		seg = bp->b_blkno / dmmax;
10730750Skarels 		index = seg % nswdev;
10812490Ssam 		seg /= nswdev;
10912490Ssam 		bp->b_blkno = seg*dmmax + off;
11012490Ssam 	} else
11130750Skarels 		index = 0;
11230750Skarels 	sp = &swdevt[index];
11339894Smckusick 	if ((bp->b_dev = sp->sw_dev) == 0)
1141404Sbill 		panic("swstrategy");
11539304Smckusick 	if (sp->sw_vp == NULL) {
11639304Smckusick 		bp->b_error |= B_ERROR;
11739304Smckusick 		biodone(bp);
11839304Smckusick 		return;
11939304Smckusick 	}
12039806Smckusick 	VHOLD(sp->sw_vp);
12139880Smckusick 	if ((bp->b_flags & B_READ) == 0) {
12239894Smckusick 		if (vp = bp->b_vp) {
12339894Smckusick 			vp->v_numoutput--;
12439894Smckusick 			if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {
12539894Smckusick 				vp->v_flag &= ~VBWAIT;
12639894Smckusick 				wakeup((caddr_t)&vp->v_numoutput);
12739894Smckusick 			}
12839880Smckusick 		}
12939880Smckusick 		sp->sw_vp->v_numoutput++;
13039880Smckusick 	}
13139894Smckusick 	if (bp->b_vp != NULL)
13239894Smckusick 		brelvp(bp);
13337729Smckusick 	bp->b_vp = sp->sw_vp;
13437729Smckusick 	VOP_STRATEGY(bp);
1351404Sbill }
1361404Sbill 
1371404Sbill /*
1381404Sbill  * System call swapon(name) enables swapping on device name,
1391404Sbill  * which must be in the swdevsw.  Return EBUSY
1401404Sbill  * if already swapping on this device.
1411404Sbill  */
14243376Smckusick /* ARGSUSED */
14343376Smckusick swapon(p, uap, retval)
14443376Smckusick 	struct proc *p;
14543376Smckusick 	struct args {
14643376Smckusick 		char	*name;
14743376Smckusick 	} *uap;
14843376Smckusick 	int *retval;
1491404Sbill {
15037729Smckusick 	register struct vnode *vp;
1511404Sbill 	register struct swdevt *sp;
15243376Smckusick 	dev_t dev;
15343376Smckusick 	int error;
15447976Skarels 	struct nameidata nd;
1551404Sbill 
15647976Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
15744409Skarels 		return (error);
158*52308Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->name, p);
159*52308Smckusick 	if (error = namei(&nd))
16044409Skarels 		return (error);
161*52308Smckusick 	vp = nd.ni_vp;
16237729Smckusick 	if (vp->v_type != VBLK) {
16337729Smckusick 		vrele(vp);
16444409Skarels 		return (ENOTBLK);
1651404Sbill 	}
16637729Smckusick 	dev = (dev_t)vp->v_rdev;
1671404Sbill 	if (major(dev) >= nblkdev) {
16837729Smckusick 		vrele(vp);
16944409Skarels 		return (ENXIO);
1701404Sbill 	}
17117879Sbloom 	for (sp = &swdevt[0]; sp->sw_dev; sp++)
1721404Sbill 		if (sp->sw_dev == dev) {
1731404Sbill 			if (sp->sw_freed) {
17437729Smckusick 				vrele(vp);
17544409Skarels 				return (EBUSY);
1761404Sbill 			}
17737729Smckusick 			sp->sw_vp = vp;
17847976Skarels 			if (error = swfree(p, sp - swdevt)) {
17937729Smckusick 				vrele(vp);
18044409Skarels 				return (error);
18137729Smckusick 			}
18244409Skarels 			return (0);
1831404Sbill 		}
18437729Smckusick 	vrele(vp);
18544409Skarels 	return (EINVAL);
1861404Sbill }
1871404Sbill 
1881404Sbill /*
1891404Sbill  * Swfree(index) frees the index'th portion of the swap map.
1901404Sbill  * Each of the nswdev devices provides 1/nswdev'th of the swap
19112490Ssam  * space, which is laid out with blocks of dmmax pages circularly
1921404Sbill  * among the devices.
1931404Sbill  */
19447976Skarels swfree(p, index)
19547976Skarels 	struct proc *p;
1961404Sbill 	int index;
1971404Sbill {
19830750Skarels 	register struct swdevt *sp;
1991404Sbill 	register swblk_t vsbase;
2008772Sroot 	register long blk;
20137729Smckusick 	struct vnode *vp;
20212490Ssam 	register swblk_t dvbase;
20312490Ssam 	register int nblks;
20430750Skarels 	int error;
2051404Sbill 
20630750Skarels 	sp = &swdevt[index];
20737729Smckusick 	vp = sp->sw_vp;
20848041Smckusick 	if (error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p))
20930750Skarels 		return (error);
21030750Skarels 	sp->sw_freed = 1;
21130750Skarels 	nblks = sp->sw_nblks;
21212490Ssam 	for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
21312490Ssam 		blk = nblks - dvbase;
21412490Ssam 		if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
21512490Ssam 			panic("swfree");
21612490Ssam 		if (blk > dmmax)
21712490Ssam 			blk = dmmax;
2181404Sbill 		if (vsbase == 0) {
2191404Sbill 			/*
2202788Swnj 			 * First of all chunks... initialize the swapmap
2212788Swnj 			 * the second half of the hunk.
2222788Swnj 			 */
22337729Smckusick 			rminit(swapmap, (long)(blk/2), (long)(blk/2),
2248794Sroot 			    "swap", nswapmap);
22530750Skarels 		} else if (dvbase == 0) {
22630750Skarels 			/*
22730750Skarels 			 * Don't use the first cluster of the device
22830750Skarels 			 * in case it starts with a label or boot block.
22930750Skarels 			 */
23030750Skarels 			rmfree(swapmap, blk - ctod(CLSIZE),
23130750Skarels 			    vsbase + ctod(CLSIZE));
2321404Sbill 		} else
2332788Swnj 			rmfree(swapmap, blk, vsbase);
2341404Sbill 	}
23530750Skarels 	return (0);
2361404Sbill }
237