BSD 4_4_Lite1 release
[unix-history] / usr / src / sys / vm / vm_swap.c
index 9dc467f..10b7523 100644 (file)
@@ -30,7 +30,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)vm_swap.c   8.1 (Berkeley) 7/15/93
+ *     @(#)vm_swap.c   8.5 (Berkeley) 2/17/94
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
  */
 
 int    nswap, nswdev;
  */
 
 int    nswap, nswdev;
+#ifdef SEQSWAP
+int    niswdev;                /* number of interleaved swap devices */
+int    niswap;                 /* size of interleaved swap area */
+#endif
 
 /*
  * Set up swap devices.
 
 /*
  * Set up swap devices.
@@ -70,11 +74,49 @@ swapinit()
 
        /*
         * Count swap devices, and adjust total swap space available.
 
        /*
         * 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.
+        * Some of the space will not be countable until later (dynamically
+        * configurable devices) and some of the counted space will not be
+        * available until a swapon() system call is issued, both usually
+        * happen when the system goes multi-user.
         *
         * If using NFS for swap, swdevt[0] will already be bdevvp'd.   XXX
         */
         *
         * If using NFS for swap, swdevt[0] will already be bdevvp'd.   XXX
         */
+#ifdef SEQSWAP
+       nswdev = niswdev = 0;
+       nswap = niswap = 0;
+       /*
+        * All interleaved devices must come first
+        */
+       for (swp = swdevt; swp->sw_dev != NODEV || swp->sw_vp != NULL; swp++) {
+               if (swp->sw_flags & SW_SEQUENTIAL)
+                       break;
+               niswdev++;
+               if (swp->sw_nblks > niswap)
+                       niswap = swp->sw_nblks;
+       }
+       niswap = roundup(niswap, dmmax);
+       niswap *= niswdev;
+       if (swdevt[0].sw_vp == NULL &&
+           bdevvp(swdevt[0].sw_dev, &swdevt[0].sw_vp))
+               panic("swapvp");
+       /*
+        * The remainder must be sequential
+        */
+       for ( ; swp->sw_dev != NODEV; swp++) {
+               if ((swp->sw_flags & SW_SEQUENTIAL) == 0)
+                       panic("binit: mis-ordered swap devices");
+               nswdev++;
+               if (swp->sw_nblks > 0) {
+                       if (swp->sw_nblks % dmmax)
+                               swp->sw_nblks -= (swp->sw_nblks % dmmax);
+                       nswap += swp->sw_nblks;
+               }
+       }
+       nswdev += niswdev;
+       if (nswdev == 0)
+               panic("swapinit");
+       nswap += niswap;
+#else
        nswdev = 0;
        nswap = 0;
        for (swp = swdevt; swp->sw_dev != NODEV || swp->sw_vp != NULL; swp++) {
        nswdev = 0;
        nswap = 0;
        for (swp = swdevt; swp->sw_dev != NODEV || swp->sw_vp != NULL; swp++) {
@@ -90,6 +132,7 @@ swapinit()
        if (swdevt[0].sw_vp == NULL &&
            bdevvp(swdevt[0].sw_dev, &swdevt[0].sw_vp))
                panic("swapvp");
        if (swdevt[0].sw_vp == NULL &&
            bdevvp(swdevt[0].sw_dev, &swdevt[0].sw_vp))
                panic("swapvp");
+#endif
        if (nswap == 0)
                printf("WARNING: no swap space found\n");
        else if (error = swfree(p, 0)) {
        if (nswap == 0)
                printf("WARNING: no swap space found\n");
        else if (error = swfree(p, 0)) {
@@ -104,10 +147,10 @@ swapinit()
        for (i = 0; i < nswbuf - 1; i++, sp++) {
                sp->b_actf = sp + 1;
                sp->b_rcred = sp->b_wcred = p->p_ucred;
        for (i = 0; i < nswbuf - 1; i++, sp++) {
                sp->b_actf = sp + 1;
                sp->b_rcred = sp->b_wcred = p->p_ucred;
-               sp->b_vnbufs.qe_next = NOLIST;
+               sp->b_vnbufs.le_next = NOLIST;
        }
        sp->b_rcred = sp->b_wcred = p->p_ucred;
        }
        sp->b_rcred = sp->b_wcred = p->p_ucred;
-       sp->b_vnbufs.qe_next = NOLIST;
+       sp->b_vnbufs.le_next = NOLIST;
        sp->b_actf = NULL;
 }
 
        sp->b_actf = NULL;
 }
 
@@ -132,13 +175,52 @@ swstrategy(bp)
 #endif
        sz = howmany(bp->b_bcount, DEV_BSIZE);
        if (bp->b_blkno + sz > nswap) {
 #endif
        sz = howmany(bp->b_bcount, DEV_BSIZE);
        if (bp->b_blkno + sz > nswap) {
+               bp->b_error = EINVAL;
                bp->b_flags |= B_ERROR;
                biodone(bp);
                return;
        }
        if (nswdev > 1) {
                bp->b_flags |= B_ERROR;
                biodone(bp);
                return;
        }
        if (nswdev > 1) {
+#ifdef SEQSWAP
+               if (bp->b_blkno < niswap) {
+                       if (niswdev > 1) {
+                               off = bp->b_blkno % dmmax;
+                               if (off+sz > dmmax) {
+                                       bp->b_error = EINVAL;
+                                       bp->b_flags |= B_ERROR;
+                                       biodone(bp);
+                                       return;
+                               }
+                               seg = bp->b_blkno / dmmax;
+                               index = seg % niswdev;
+                               seg /= niswdev;
+                               bp->b_blkno = seg*dmmax + off;
+                       } else
+                               index = 0;
+               } else {
+                       register struct swdevt *swp;
+
+                       bp->b_blkno -= niswap;
+                       for (index = niswdev, swp = &swdevt[niswdev];
+                            swp->sw_dev != NODEV;
+                            swp++, index++) {
+                               if (bp->b_blkno < swp->sw_nblks)
+                                       break;
+                               bp->b_blkno -= swp->sw_nblks;
+                       }
+                       if (swp->sw_dev == NODEV ||
+                           bp->b_blkno+sz > swp->sw_nblks) {
+                               bp->b_error = swp->sw_dev == NODEV ?
+                                       ENODEV : EINVAL;
+                               bp->b_flags |= B_ERROR;
+                               biodone(bp);
+                               return;
+                       }
+               }
+#else
                off = bp->b_blkno % dmmax;
                if (off+sz > dmmax) {
                off = bp->b_blkno % dmmax;
                if (off+sz > dmmax) {
+                       bp->b_error = EINVAL;
                        bp->b_flags |= B_ERROR;
                        biodone(bp);
                        return;
                        bp->b_flags |= B_ERROR;
                        biodone(bp);
                        return;
@@ -147,13 +229,15 @@ swstrategy(bp)
                index = seg % nswdev;
                seg /= nswdev;
                bp->b_blkno = seg*dmmax + off;
                index = seg % nswdev;
                seg /= nswdev;
                bp->b_blkno = seg*dmmax + off;
+#endif
        } else
                index = 0;
        sp = &swdevt[index];
        if ((bp->b_dev = sp->sw_dev) == NODEV)
                panic("swstrategy");
        if (sp->sw_vp == NULL) {
        } else
                index = 0;
        sp = &swdevt[index];
        if ((bp->b_dev = sp->sw_dev) == NODEV)
                panic("swstrategy");
        if (sp->sw_vp == NULL) {
-               bp->b_error |= B_ERROR;
+               bp->b_error = ENODEV;
+               bp->b_flags |= B_ERROR;
                biodone(bp);
                return;
        }
                biodone(bp);
                return;
        }
@@ -210,9 +294,9 @@ swapon(p, uap, retval)
                vrele(vp);
                return (ENXIO);
        }
                vrele(vp);
                return (ENXIO);
        }
-       for (sp = &swdevt[0]; sp->sw_dev != NODEV; sp++)
+       for (sp = &swdevt[0]; sp->sw_dev != NODEV; sp++) {
                if (sp->sw_dev == dev) {
                if (sp->sw_dev == dev) {
-                       if (sp->sw_freed) {
+                       if (sp->sw_flags & SW_FREED) {
                                vrele(vp);
                                return (EBUSY);
                        }
                                vrele(vp);
                                return (EBUSY);
                        }
@@ -223,6 +307,17 @@ swapon(p, uap, retval)
                        }
                        return (0);
                }
                        }
                        return (0);
                }
+#ifdef SEQSWAP
+               /*
+                * If we have reached a non-freed sequential device without
+                * finding what we are looking for, it is an error.
+                * That is because all interleaved devices must come first
+                * and sequential devices must be freed in order.
+                */
+               if ((sp->sw_flags & (SW_SEQUENTIAL|SW_FREED)) == SW_SEQUENTIAL)
+                       break;
+#endif
+       }
        vrele(vp);
        return (EINVAL);
 }
        vrele(vp);
        return (EINVAL);
 }
@@ -250,12 +345,64 @@ swfree(p, index)
        vp = sp->sw_vp;
        if (error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p))
                return (error);
        vp = sp->sw_vp;
        if (error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p))
                return (error);
-       sp->sw_freed = 1;
+       sp->sw_flags |= SW_FREED;
        nblks = sp->sw_nblks;
        nblks = sp->sw_nblks;
+       /*
+        * Some devices may not exist til after boot time.
+        * If so, their nblk count will be 0.
+        */
+       if (nblks <= 0) {
+               int perdev;
+               dev_t dev = sp->sw_dev;
+
+               if (bdevsw[major(dev)].d_psize == 0 ||
+                   (nblks = (*bdevsw[major(dev)].d_psize)(dev)) == -1) {
+                       (void) VOP_CLOSE(vp, FREAD|FWRITE, p->p_ucred, p);
+                       sp->sw_flags &= ~SW_FREED;
+                       return (ENXIO);
+               }
+#ifdef SEQSWAP
+               if (index < niswdev) {
+                       perdev = niswap / niswdev;
+                       if (nblks > perdev)
+                               nblks = perdev;
+               } else {
+                       if (nblks % dmmax)
+                               nblks -= (nblks % dmmax);
+                       nswap += nblks;
+               }
+#else
+               perdev = nswap / nswdev;
+               if (nblks > perdev)
+                       nblks = perdev;
+#endif
+               sp->sw_nblks = nblks;
+       }
+       if (nblks == 0) {
+               (void) VOP_CLOSE(vp, FREAD|FWRITE, p->p_ucred, p);
+               sp->sw_flags &= ~SW_FREED;
+               return (0);     /* XXX error? */
+       }
+#ifdef SEQSWAP
+       if (sp->sw_flags & SW_SEQUENTIAL) {
+               register struct swdevt *swp;
+
+               blk = niswap;
+               for (swp = &swdevt[niswdev]; swp != sp; swp++)
+                       blk += swp->sw_nblks;
+               rmfree(swapmap, nblks, blk);
+               return (0);
+       }
+#endif
        for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
                blk = nblks - dvbase;
        for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
                blk = nblks - dvbase;
+#ifdef SEQSWAP
+               if ((vsbase = index*dmmax + dvbase*niswdev) >= niswap)
+                       panic("swfree");
+#else
                if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
                        panic("swfree");
                if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
                        panic("swfree");
+#endif
                if (blk > dmmax)
                        blk = dmmax;
                if (vsbase == 0) {
                if (blk > dmmax)
                        blk = dmmax;
                if (vsbase == 0) {