BSD 4_4 release
[unix-history] / usr / src / sys / vm / swap_pager.c
index 337a928..3f863e5 100644 (file)
@@ -1,17 +1,43 @@
 /*
  * Copyright (c) 1990 University of Utah.
 /*
  * Copyright (c) 1990 University of Utah.
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * the Systems Programming Group of the University of Utah Computer
  * Science Department.
  *
  *
  * This code is derived from software contributed to Berkeley by
  * the Systems Programming Group of the University of Utah Computer
  * Science Department.
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  *
  * from: Utah $Hdr: swap_pager.c 1.4 91/04/30$
  *
  *
  * from: Utah $Hdr: swap_pager.c 1.4 91/04/30$
  *
- *     @(#)swap_pager.c        7.4 (Berkeley) %G%
+ *     @(#)swap_pager.c        8.1 (Berkeley) 6/11/93
  */
 
 /*
  */
 
 /*
  *     Deal with async writes in a better fashion
  */
 
  *     Deal with async writes in a better fashion
  */
 
-#include "swappager.h"
-#if NSWAPPAGER > 0
-
-#include "param.h"
-#include "proc.h"
-#include "buf.h"
-#include "map.h"
-#include "systm.h"
-#include "specdev.h"
-#include "vnode.h"
-#include "malloc.h"
-#include "queue.h"
-
-#include "vm_param.h"
-#include "queue.h"
-#include "lock.h"
-#include "vm_prot.h"
-#include "vm_object.h"
-#include "vm_page.h"
-#include "vm_pageout.h"
-#include "swap_pager.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/buf.h>
+#include <sys/map.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+
+#include <miscfs/specfs/specdev.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pageout.h>
+#include <vm/swap_pager.h>
 
 #define NSWSIZES       16      /* size of swtab */
 #define NPENDINGIO     64      /* max # of pending cleans */
 
 #define NSWSIZES       16      /* size of swtab */
 #define NPENDINGIO     64      /* max # of pending cleans */
@@ -69,7 +88,8 @@ struct swpagerclean {
        vm_offset_t             spc_kva;
        vm_page_t               spc_m;
 } swcleanlist[NPENDINGIO];
        vm_offset_t             spc_kva;
        vm_page_t               spc_m;
 } swcleanlist[NPENDINGIO];
-typedef        struct swpagerclean     *swp_clean_t;
+typedef struct swpagerclean *swp_clean_t;
+
 
 /* spc_flags values */
 #define SPC_FREE       0x00
 
 /* spc_flags values */
 #define SPC_FREE       0x00
@@ -97,7 +117,29 @@ queue_head_t        swap_pager_inuse;       /* list of pending page cleans */
 queue_head_t   swap_pager_free;        /* list of free pager clean structs */
 queue_head_t   swap_pager_list;        /* list of "named" anon regions */
 
 queue_head_t   swap_pager_free;        /* list of free pager clean structs */
 queue_head_t   swap_pager_list;        /* list of "named" anon regions */
 
-void
+static int             swap_pager_finish __P((swp_clean_t));
+static void            swap_pager_init __P((void));
+static vm_pager_t      swap_pager_alloc __P((caddr_t, vm_size_t, vm_prot_t));
+static boolean_t       swap_pager_clean __P((vm_page_t, int));
+static void            swap_pager_dealloc __P((vm_pager_t));
+static int             swap_pager_getpage
+                           __P((vm_pager_t, vm_page_t, boolean_t));
+static boolean_t       swap_pager_haspage __P((vm_pager_t, vm_offset_t));
+static int             swap_pager_io __P((sw_pager_t, vm_page_t, int));
+static void            swap_pager_iodone __P((struct buf *));
+static int             swap_pager_putpage
+                           __P((vm_pager_t, vm_page_t, boolean_t));
+
+struct pagerops swappagerops = {
+       swap_pager_init,
+       swap_pager_alloc,
+       swap_pager_dealloc,
+       swap_pager_getpage,
+       swap_pager_putpage,
+       swap_pager_haspage
+};
+
+static void
 swap_pager_init()
 {
        register swp_clean_t spc;
 swap_pager_init()
 {
        register swp_clean_t spc;
@@ -163,7 +205,7 @@ swap_pager_init()
  * Note that if we are called from the pageout daemon (handle == NULL)
  * we should not wait for memory as it could resulting in deadlock.
  */
  * Note that if we are called from the pageout daemon (handle == NULL)
  * we should not wait for memory as it could resulting in deadlock.
  */
-vm_pager_t
+static vm_pager_t
 swap_pager_alloc(handle, size, prot)
        caddr_t handle;
        register vm_size_t size;
 swap_pager_alloc(handle, size, prot)
        caddr_t handle;
        register vm_size_t size;
@@ -270,7 +312,7 @@ swap_pager_alloc(handle, size, prot)
        return(pager);
 }
 
        return(pager);
 }
 
-void
+static void
 swap_pager_dealloc(pager)
        vm_pager_t pager;
 {
 swap_pager_dealloc(pager)
        vm_pager_t pager;
 {
@@ -310,7 +352,7 @@ swap_pager_dealloc(pager)
        s = splbio();
        while (swp->sw_poip) {
                swp->sw_flags |= SW_WANTED;
        s = splbio();
        while (swp->sw_poip) {
                swp->sw_flags |= SW_WANTED;
-               assert_wait((int)swp);
+               assert_wait((int)swp, 0);
                thread_block();
        }
        splx(s);
                thread_block();
        }
        splx(s);
@@ -336,6 +378,7 @@ swap_pager_dealloc(pager)
        free((caddr_t)pager, M_VMPAGER);
 }
 
        free((caddr_t)pager, M_VMPAGER);
 }
 
+static int
 swap_pager_getpage(pager, m, sync)
        vm_pager_t pager;
        vm_page_t m;
 swap_pager_getpage(pager, m, sync)
        vm_pager_t pager;
        vm_page_t m;
@@ -348,6 +391,7 @@ swap_pager_getpage(pager, m, sync)
        return(swap_pager_io((sw_pager_t)pager->pg_data, m, B_READ));
 }
 
        return(swap_pager_io((sw_pager_t)pager->pg_data, m, B_READ));
 }
 
+static int
 swap_pager_putpage(pager, m, sync)
        vm_pager_t pager;
        vm_page_t m;
 swap_pager_putpage(pager, m, sync)
        vm_pager_t pager;
        vm_page_t m;
@@ -361,7 +405,7 @@ swap_pager_putpage(pager, m, sync)
 #endif
        if (pager == NULL) {
                (void) swap_pager_clean(NULL, B_WRITE);
 #endif
        if (pager == NULL) {
                (void) swap_pager_clean(NULL, B_WRITE);
-               return;
+               return (VM_PAGER_OK);           /* ??? */
        }
        flags = B_WRITE;
        if (!sync)
        }
        flags = B_WRITE;
        if (!sync)
@@ -369,7 +413,7 @@ swap_pager_putpage(pager, m, sync)
        return(swap_pager_io((sw_pager_t)pager->pg_data, m, flags));
 }
 
        return(swap_pager_io((sw_pager_t)pager->pg_data, m, flags));
 }
 
-boolean_t
+static boolean_t
 swap_pager_haspage(pager, offset)
        vm_pager_t pager;
        vm_offset_t offset;
 swap_pager_haspage(pager, offset)
        vm_pager_t pager;
        vm_offset_t offset;
@@ -413,6 +457,7 @@ swap_pager_haspage(pager, offset)
  * BOGUS:  lower level IO routines expect a KVA so we have to map our
  * provided physical page into the KVA to keep them happy.
  */
  * BOGUS:  lower level IO routines expect a KVA so we have to map our
  * provided physical page into the KVA to keep them happy.
  */
+static int
 swap_pager_io(swp, m, flags)
        register sw_pager_t swp;
        vm_page_t m;
 swap_pager_io(swp, m, flags)
        register sw_pager_t swp;
        vm_page_t m;
@@ -429,7 +474,7 @@ swap_pager_io(swp, m, flags)
 #ifdef DEBUG
        /* save panic time state */
        if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
 #ifdef DEBUG
        /* save panic time state */
        if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
-               return;
+               return (VM_PAGER_FAIL);         /* XXX: correct return? */
        if (swpagerdebug & (SDB_FOLLOW|SDB_IO))
                printf("swpg_io(%x, %x, %x)\n", swp, m, flags);
 #endif
        if (swpagerdebug & (SDB_FOLLOW|SDB_IO))
                printf("swpg_io(%x, %x, %x)\n", swp, m, flags);
 #endif
@@ -451,7 +496,7 @@ swap_pager_io(swp, m, flags)
                                printf("swap_pager_io: page %x cleaning\n", m);
 
                        swp->sw_flags |= SW_WANTED;
                                printf("swap_pager_io: page %x cleaning\n", m);
 
                        swp->sw_flags |= SW_WANTED;
-                       assert_wait((int)swp);
+                       assert_wait((int)swp, 0);
                        thread_block();
                }
 #else
                        thread_block();
                }
 #else
@@ -532,7 +577,7 @@ swap_pager_io(swp, m, flags)
         * Get a swap buffer header and perform the IO
         */
        s = splbio();
         * Get a swap buffer header and perform the IO
         */
        s = splbio();
-       while (bswlist.av_forw == NULL) {
+       while (bswlist.b_actf == NULL) {
 #ifdef DEBUG
                if (swpagerdebug & SDB_ANOM)
                        printf("swap_pager_io: wait on swbuf for %x (%d)\n",
 #ifdef DEBUG
                if (swpagerdebug & SDB_ANOM)
                        printf("swap_pager_io: wait on swbuf for %x (%d)\n",
@@ -541,8 +586,8 @@ swap_pager_io(swp, m, flags)
                bswlist.b_flags |= B_WANTED;
                sleep((caddr_t)&bswlist, PSWP+1);
        }
                bswlist.b_flags |= B_WANTED;
                sleep((caddr_t)&bswlist, PSWP+1);
        }
-       bp = bswlist.av_forw;
-       bswlist.av_forw = bp->av_forw;
+       bp = bswlist.b_actf;
+       bswlist.b_actf = bp->b_actf;
        splx(s);
        bp->b_flags = B_BUSY | (flags & B_READ);
        bp->b_proc = &proc0;    /* XXX (but without B_PHYS set this is ok) */
        splx(s);
        bp->b_flags = B_BUSY | (flags & B_READ);
        bp->b_proc = &proc0;    /* XXX (but without B_PHYS set this is ok) */
@@ -553,8 +598,11 @@ swap_pager_io(swp, m, flags)
        if (swapdev_vp->v_type == VBLK)
                bp->b_dev = swapdev_vp->v_rdev;
        bp->b_bcount = PAGE_SIZE;
        if (swapdev_vp->v_type == VBLK)
                bp->b_dev = swapdev_vp->v_rdev;
        bp->b_bcount = PAGE_SIZE;
-       if ((bp->b_flags & B_READ) == 0)
+       if ((bp->b_flags & B_READ) == 0) {
+               bp->b_dirtyoff = 0;
+               bp->b_dirtyend = PAGE_SIZE;
                swapdev_vp->v_numoutput++;
                swapdev_vp->v_numoutput++;
+       }
 
        /*
         * If this is an async write we set up additional buffer fields
 
        /*
         * If this is an async write we set up additional buffer fields
@@ -616,7 +664,7 @@ swap_pager_io(swp, m, flags)
                swap_pager_poip++;
 #endif
        while ((bp->b_flags & B_DONE) == 0) {
                swap_pager_poip++;
 #endif
        while ((bp->b_flags & B_DONE) == 0) {
-               assert_wait((int)bp);
+               assert_wait((int)bp, 0);
                thread_block();
        }
 #ifdef DEBUG
                thread_block();
        }
 #ifdef DEBUG
@@ -625,10 +673,10 @@ swap_pager_io(swp, m, flags)
        else
                --swap_pager_poip;
 #endif
        else
                --swap_pager_poip;
 #endif
-       rv = (bp->b_flags & B_ERROR) ? VM_PAGER_FAIL : VM_PAGER_OK;
+       rv = (bp->b_flags & B_ERROR) ? VM_PAGER_ERROR : VM_PAGER_OK;
        bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
        bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
-       bp->av_forw = bswlist.av_forw;
-       bswlist.av_forw = bp;
+       bp->b_actf = bswlist.b_actf;
+       bswlist.b_actf = bp;
        if (bp->b_vp)
                brelvp(bp);
        if (bswlist.b_flags & B_WANTED) {
        if (bp->b_vp)
                brelvp(bp);
        if (bswlist.b_flags & B_WANTED) {
@@ -636,21 +684,21 @@ swap_pager_io(swp, m, flags)
                thread_wakeup((int)&bswlist);
        }
        if ((flags & B_READ) == 0 && rv == VM_PAGER_OK) {
                thread_wakeup((int)&bswlist);
        }
        if ((flags & B_READ) == 0 && rv == VM_PAGER_OK) {
-               m->clean = TRUE;
+               m->flags |= PG_CLEAN;
                pmap_clear_modify(VM_PAGE_TO_PHYS(m));
        }
        splx(s);
 #ifdef DEBUG
        if (swpagerdebug & SDB_IO)
                printf("swpg_io:  IO done: bp %x, rv %d\n", bp, rv);
                pmap_clear_modify(VM_PAGE_TO_PHYS(m));
        }
        splx(s);
 #ifdef DEBUG
        if (swpagerdebug & SDB_IO)
                printf("swpg_io:  IO done: bp %x, rv %d\n", bp, rv);
-       if ((swpagerdebug & SDB_FAIL) && rv == VM_PAGER_FAIL)
+       if ((swpagerdebug & SDB_FAIL) && rv == VM_PAGER_ERROR)
                printf("swpg_io: IO error\n");
 #endif
        vm_pager_unmap_page(kva);
        return(rv);
 }
 
                printf("swpg_io: IO error\n");
 #endif
        vm_pager_unmap_page(kva);
        return(rv);
 }
 
-boolean_t
+static boolean_t
 swap_pager_clean(m, rw)
        vm_page_t m;
        int rw;
 swap_pager_clean(m, rw)
        vm_page_t m;
        int rw;
@@ -661,7 +709,7 @@ swap_pager_clean(m, rw)
 #ifdef DEBUG
        /* save panic time state */
        if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
 #ifdef DEBUG
        /* save panic time state */
        if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
-               return;
+               return (FALSE);                 /* ??? */
        if (swpagerdebug & SDB_FOLLOW)
                printf("swpg_clean(%x, %d)\n", m, rw);
 #endif
        if (swpagerdebug & SDB_FOLLOW)
                printf("swpg_clean(%x, %d)\n", m, rw);
 #endif
@@ -743,6 +791,7 @@ swap_pager_clean(m, rw)
        return(tspc ? TRUE : FALSE);
 }
 
        return(tspc ? TRUE : FALSE);
 }
 
+static int
 swap_pager_finish(spc)
        register swp_clean_t spc;
 {
 swap_pager_finish(spc)
        register swp_clean_t spc;
 {
@@ -773,7 +822,7 @@ swap_pager_finish(spc)
                if (swpagerdebug & SDB_ANOM)
                        printf("swap_pager_finish: page %x dirty again\n",
                               spc->spc_m);
                if (swpagerdebug & SDB_ANOM)
                        printf("swap_pager_finish: page %x dirty again\n",
                               spc->spc_m);
-               spc->spc_m->busy = FALSE;
+               spc->spc_m->flags &= ~PG_BUSY;
                PAGE_WAKEUP(spc->spc_m);
                vm_object_unlock(object);
                return(1);
                PAGE_WAKEUP(spc->spc_m);
                vm_object_unlock(object);
                return(1);
@@ -787,18 +836,19 @@ swap_pager_finish(spc)
        if (spc->spc_flags & SPC_ERROR) {
                printf("swap_pager_finish: clean of page %x failed\n",
                       VM_PAGE_TO_PHYS(spc->spc_m));
        if (spc->spc_flags & SPC_ERROR) {
                printf("swap_pager_finish: clean of page %x failed\n",
                       VM_PAGE_TO_PHYS(spc->spc_m));
-               spc->spc_m->laundry = TRUE;
+               spc->spc_m->flags |= PG_LAUNDRY;
        } else {
        } else {
-               spc->spc_m->clean = TRUE;
+               spc->spc_m->flags |= PG_CLEAN;
                pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m));
        }
                pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m));
        }
-       spc->spc_m->busy = FALSE;
+       spc->spc_m->flags &= ~PG_BUSY;
        PAGE_WAKEUP(spc->spc_m);
 
        vm_object_unlock(object);
        return(1);
 }
 
        PAGE_WAKEUP(spc->spc_m);
 
        vm_object_unlock(object);
        return(1);
 }
 
+static void
 swap_pager_iodone(bp)
        register struct buf *bp;
 {
 swap_pager_iodone(bp)
        register struct buf *bp;
 {
@@ -847,15 +897,19 @@ swap_pager_iodone(bp)
        }
                
        bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
        }
                
        bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
-       bp->av_forw = bswlist.av_forw;
-       bswlist.av_forw = bp;
+       bp->b_actf = bswlist.b_actf;
+       bswlist.b_actf = bp;
        if (bp->b_vp)
                brelvp(bp);
        if (bswlist.b_flags & B_WANTED) {
                bswlist.b_flags &= ~B_WANTED;
                thread_wakeup((int)&bswlist);
        }
        if (bp->b_vp)
                brelvp(bp);
        if (bswlist.b_flags & B_WANTED) {
                bswlist.b_flags &= ~B_WANTED;
                thread_wakeup((int)&bswlist);
        }
-       thread_wakeup((int) &vm_pages_needed);
+       /*
+        * Only kick the pageout daemon if we are really hurting
+        * for pages, otherwise this page will be picked up later.
+        */
+       if (cnt.v_free_count < cnt.v_free_min)
+               thread_wakeup((int) &vm_pages_needed);
        splx(s);
 }
        splx(s);
 }
-#endif