merge in 7.7.1.1 (ralphs 3100 changes)
[unix-history] / usr / src / sys / vm / vm_swap.c
index 6f4f7ad..5da93a6 100644 (file)
-/*     vm_swap.c       4.5     82/03/12        */
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)vm_swap.c   7.18 (Berkeley) %G%
+ */
 
 
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/buf.h"
-#include "../h/conf.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/inode.h"
-#include "../h/map.h"
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "conf.h"
+#include "proc.h"
+#include "namei.h"
+#include "dmap.h"              /* XXX */
+#include "vnode.h"
+#include "specdev.h"
+#include "map.h"
+#include "file.h"
+#include "stat.h"
 
 
-struct buf rswbuf;
 /*
  * Indirect driver for multi-controller paging.
  */
 /*
  * Indirect driver for multi-controller paging.
  */
-swstrategy(bp)
-       register struct buf *bp;
-{
-       int sz, off, seg;
-       dev_t dev;
 
 
-       sz = (bp->b_bcount+511)/512;
-       off = bp->b_blkno % DMMAX;
-       if (bp->b_blkno+sz > nswap || off+sz > DMMAX) {
-               bp->b_flags |= B_ERROR;
-               iodone(bp);
-               return;
-       }
-       seg = bp->b_blkno / DMMAX;
-       dev = swdevt[seg % nswdev].sw_dev;
-       seg /= nswdev;
-       bp->b_blkno = seg*DMMAX + off;
-       bp->b_dev = dev;
-       if (dev == 0)
-               panic("swstrategy");
-       (*bdevsw[major(dev)].d_strategy)(bp);
-}
+int    nswap, nswdev;
 
 
-swread(dev)
+/*
+ * Set up swap devices.
+ * Initialize linked list of free swap
+ * headers. These do not actually point
+ * to buffers, but rather to pages that
+ * are being swapped in and out.
+ */
+swapinit()
 {
 {
+       register int i;
+       register struct buf *sp = swbuf;
+       struct swdevt *swp;
+       int error;
+
+       /*
+        * Count swap devices, and adjust total swap space available.
+        * Some of this space will not be available until a swapon()
+        * system is issued, usually when the system goes multi-user.
+        */
+       nswdev = 0;
+       nswap = 0;
+       for (swp = swdevt; swp->sw_dev; swp++) {
+               nswdev++;
+               if (swp->sw_nblks > nswap)
+                       nswap = swp->sw_nblks;
+       }
+       if (nswdev == 0)
+               panic("swapinit");
+       if (nswdev > 1)
+               nswap = ((nswap + dmmax - 1) / dmmax) * dmmax;
+       nswap *= nswdev;
+       if (bdevvp(swdevt[0].sw_dev, &swdevt[0].sw_vp))
+               panic("swapvp");
+       if (error = swfree(&proc0, 0)) {
+               printf("swfree errno %d\n", error);     /* XXX */
+               panic("swapinit swfree 0");
+       }
 
 
-       physio(swstrategy, &rswbuf, dev, B_READ, minphys);
+       /*
+        * Now set up swap buffer headers.
+        */
+       bswlist.av_forw = sp;
+       for (i = 0; i < nswbuf - 1; i++, sp++)
+               sp->av_forw = sp + 1;
+       sp->av_forw = NULL;
 }
 
 }
 
-swwrite(dev)
+swstrategy(bp)
+       register struct buf *bp;
 {
 {
+       int sz, off, seg, index;
+       register struct swdevt *sp;
 
 
-       physio(swstrategy, &rswbuf, dev, B_WRITE, minphys);
+#ifdef GENERIC
+       /*
+        * A mini-root gets copied into the front of the swap
+        * and we run over top of the swap area just long
+        * enough for us to do a mkfs and restor of the real
+        * root (sure beats rewriting standalone restor).
+        */
+#define        MINIROOTSIZE    4096
+       if (rootdev == dumpdev)
+               bp->b_blkno += MINIROOTSIZE;
+#endif
+       sz = howmany(bp->b_bcount, DEV_BSIZE);
+       if (bp->b_blkno + sz > nswap) {
+               bp->b_flags |= B_ERROR;
+               biodone(bp);
+               return;
+       }
+       if (nswdev > 1) {
+               off = bp->b_blkno % dmmax;
+               if (off+sz > dmmax) {
+                       bp->b_flags |= B_ERROR;
+                       biodone(bp);
+                       return;
+               }
+               seg = bp->b_blkno / dmmax;
+               index = seg % nswdev;
+               seg /= nswdev;
+               bp->b_blkno = seg*dmmax + off;
+       } else
+               index = 0;
+       sp = &swdevt[index];
+#ifdef SECSIZE
+       bp->b_blkno <<= sp->sw_bshift;
+       bp->b_blksize = sp->sw_blksize;
+#endif SECSIZE
+       bp->b_dev = sp->sw_dev;
+       if (bp->b_dev == 0)
+               panic("swstrategy");
+       (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
 }
 
 /*
 }
 
 /*
@@ -53,74 +125,112 @@ swwrite(dev)
  * which must be in the swdevsw.  Return EBUSY
  * if already swapping on this device.
  */
  * which must be in the swdevsw.  Return EBUSY
  * if already swapping on this device.
  */
-vswapon()
+/* ARGSUSED */
+swapon(p, uap, retval)
+       struct proc *p;
+       struct args {
+               char    *name;
+       } *uap;
+       int *retval;
 {
 {
-       register struct inode *ip;
-       dev_t dev;
+       register struct vnode *vp;
        register struct swdevt *sp;
        register struct swdevt *sp;
+       register struct nameidata *ndp;
+       dev_t dev;
+       int error;
+       struct nameidata nd;
 
 
-       ip = namei(uchar, 0, 1);
-       if (ip == NULL)
-               return;
-       if ((ip->i_mode&IFMT) != IFBLK) {
-               u.u_error = ENOTBLK;
-               iput(ip);
-               return;
+       if (error = suser(p->p_ucred, &p->p_acflag))
+               return (error);
+       ndp = &nd;
+       ndp->ni_nameiop = LOOKUP | FOLLOW;
+       ndp->ni_segflg = UIO_USERSPACE;
+       ndp->ni_dirp = uap->name;
+       if (error = namei(ndp, p))
+               return (error);
+       vp = ndp->ni_vp;
+       if (vp->v_type != VBLK) {
+               vrele(vp);
+               return (ENOTBLK);
        }
        }
-       dev = (dev_t)ip->i_un.i_rdev;
-       iput(ip);
+       dev = (dev_t)vp->v_rdev;
        if (major(dev) >= nblkdev) {
        if (major(dev) >= nblkdev) {
-               u.u_error = ENXIO;
-               return;
+               vrele(vp);
+               return (ENXIO);
        }
        }
-       /*
-        * Search starting at second table entry,
-        * since first (primary swap area) is freed at boot.
-        */
-       for (sp = &swdevt[1]; sp->sw_dev; sp++)
+       for (sp = &swdevt[0]; sp->sw_dev; sp++)
                if (sp->sw_dev == dev) {
                        if (sp->sw_freed) {
                if (sp->sw_dev == dev) {
                        if (sp->sw_freed) {
-                               u.u_error = EBUSY;
-                               return;
+                               vrele(vp);
+                               return (EBUSY);
                        }
                        }
-                       swfree(sp - swdevt);
-                       return;
+                       u.u_error = swfree(sp - swdevt);
+                       return (0);
                }
                }
-       u.u_error = ENODEV;
+       vrele(vp);
+       return (EINVAL);
 }
 
 }
 
+#ifdef SECSIZE
+long   argdbsize;              /* XXX */
+
+#endif SECSIZE
 /*
  * Swfree(index) frees the index'th portion of the swap map.
  * Each of the nswdev devices provides 1/nswdev'th of the swap
 /*
  * Swfree(index) frees the index'th portion of the swap map.
  * Each of the nswdev devices provides 1/nswdev'th of the swap
- * space, which is laid out with blocks of DMMAX pages circularly
+ * space, which is laid out with blocks of dmmax pages circularly
  * among the devices.
  */
  * among the devices.
  */
-swfree(index)
+swfree(p, index)
+       struct proc *p;
        int index;
 {
        int index;
 {
+       register struct swdevt *sp;
+       register struct swdevt *sp;
        register swblk_t vsbase;
        register swblk_t vsbase;
-       register int blk;
+       register long blk;
+       struct vnode *vp;
+       register swblk_t dvbase;
+       register int nblks;
+       int error;
+       int error;
 
 
-       swdevt[index].sw_freed = 1;
-       for (vsbase = index*DMMAX; vsbase < nswap; vsbase += nswdev*DMMAX) {
-               blk = nswap - vsbase;
-               if (blk > DMMAX)
-                       blk = DMMAX;
+       sp = &swdevt[index];
+       dev = sp->sw_dev;
+       if (error = (*bdevsw[major(dev)].d_open)(dev, FREAD|FWRITE, S_IFBLK))
+               return (error);
+       sp->sw_freed = 1;
+       nblks = sp->sw_nblks;
+       for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
+               blk = nblks - dvbase;
+               if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
+                       panic("swfree");
+               if (blk > dmmax)
+                       blk = dmmax;
                if (vsbase == 0) {
                if (vsbase == 0) {
-                       /*
-                        * Can't free a block starting at 0 in the swapmap
-                        * but need some space for argmap so use 1/2 this
-                        * hunk which needs special treatment anyways.
-                        */
-                       argdev = swdevt[0].sw_dev;
-                       rminit(argmap, blk/2-CLSIZE, CLSIZE,
-                           "argmap", ARGMAPSIZE);
                        /*
                         * First of all chunks... initialize the swapmap
                         * the second half of the hunk.
                         */
                        /*
                         * First of all chunks... initialize the swapmap
                         * the second half of the hunk.
                         */
-                       rminit(swapmap, blk/2, blk/2, "swap", nswapmap);
+                       rminit(swapmap, (long)(blk/2), (long)(blk/2),
+                           "swap", nswapmap);
+               } else if (dvbase == 0) {
+                       /*
+                        * Don't use the first cluster of the device
+                        * in case it starts with a label or boot block.
+                        */
+                       rmfree(swapmap, blk - ctod(CLSIZE),
+                           vsbase + ctod(CLSIZE));
+               } else if (dvbase == 0) {
+                       /*
+                        * Don't use the first cluster of the device
+                        * in case it starts with a label or boot block.
+                        */
+                       rmfree(swapmap, blk - ctod(CLSIZE),
+                           vsbase + ctod(CLSIZE));
                } else
                        rmfree(swapmap, blk, vsbase);
        }
                } else
                        rmfree(swapmap, blk, vsbase);
        }
+       return (0);
+       return (0);
 }
 }