home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / vm / swap_pager.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-07  |  22.7 KB  |  888 lines

  1. /*
  2.  * Copyright (c) 1990 University of Utah.
  3.  * Copyright (c) 1991 The Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * This code is derived from software contributed to Berkeley by
  7.  * the Systems Programming Group of the University of Utah Computer
  8.  * Science Department.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  * 1. Redistributions of source code must retain the above copyright
  14.  *    notice, this list of conditions and the following disclaimer.
  15.  * 2. Redistributions in binary form must reproduce the above copyright
  16.  *    notice, this list of conditions and the following disclaimer in the
  17.  *    documentation and/or other materials provided with the distribution.
  18.  * 3. All advertising materials mentioning features or use of this software
  19.  *    must display the following acknowledgement:
  20.  *    This product includes software developed by the University of
  21.  *    California, Berkeley and its contributors.
  22.  * 4. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  *
  38.  * from: Utah $Hdr: swap_pager.c 1.4 91/04/30$
  39.  *
  40.  *    @(#)swap_pager.c    7.4 (Berkeley) 5/7/91
  41.  */
  42.  
  43. /*
  44.  * Quick hack to page to dedicated partition(s).
  45.  * TODO:
  46.  *    Add multiprocessor locks
  47.  *    Deal with async writes in a better fashion
  48.  */
  49.  
  50. #include "swappager.h"
  51. #if NSWAPPAGER > 0
  52.  
  53. #include "param.h"
  54. #include "proc.h"
  55. #include "buf.h"
  56. #include "map.h"
  57. #include "systm.h"
  58. #include "specdev.h"
  59. #include "vnode.h"
  60. #include "malloc.h"
  61. #include "queue.h"
  62.  
  63. #include "vm_param.h"
  64. #include "queue.h"
  65. #include "lock.h"
  66. #include "vm_prot.h"
  67. #include "vm_object.h"
  68. #include "vm_page.h"
  69. #include "vm_pageout.h"
  70. #include "swap_pager.h"
  71.  
  72. #define NSWSIZES    16    /* size of swtab */
  73. #define NPENDINGIO    64    /* max # of pending cleans */
  74. #define MAXDADDRS    64    /* max # of disk addrs for fixed allocations */
  75.  
  76. #ifdef DEBUG
  77. int    swpagerdebug = 0x100;
  78. #define    SDB_FOLLOW    0x001
  79. #define SDB_INIT    0x002
  80. #define SDB_ALLOC    0x004
  81. #define SDB_IO        0x008
  82. #define SDB_WRITE    0x010
  83. #define SDB_FAIL    0x020
  84. #define SDB_ALLOCBLK    0x040
  85. #define SDB_FULL    0x080
  86. #define SDB_ANOM    0x100
  87. #define SDB_ANOMPANIC    0x200
  88. #endif
  89.  
  90. struct swpagerclean {
  91.     queue_head_t        spc_list;
  92.     int            spc_flags;
  93.     struct buf        *spc_bp;
  94.     sw_pager_t        spc_swp;
  95.     vm_offset_t        spc_kva;
  96.     vm_page_t        spc_m;
  97. } swcleanlist[NPENDINGIO];
  98. typedef    struct swpagerclean    *swp_clean_t;
  99.  
  100. /* spc_flags values */
  101. #define SPC_FREE    0x00
  102. #define SPC_BUSY    0x01
  103. #define SPC_DONE    0x02
  104. #define SPC_ERROR    0x04
  105. #define SPC_DIRTY    0x08
  106.  
  107. struct swtab {
  108.     vm_size_t st_osize;    /* size of object (bytes) */
  109.     int      st_bsize;    /* vs. size of swap block (DEV_BSIZE units) */
  110. #ifdef DEBUG
  111.     u_long      st_inuse;    /* number in this range in use */
  112.     u_long      st_usecnt;    /* total used of this size */
  113. #endif
  114. } swtab[NSWSIZES+1];
  115.  
  116. #ifdef DEBUG
  117. int        swap_pager_pendingio;    /* max pending async "clean" ops */
  118. int        swap_pager_poip;    /* pageouts in progress */
  119. int        swap_pager_piip;    /* pageins in progress */
  120. #endif
  121.  
  122. queue_head_t    swap_pager_inuse;    /* list of pending page cleans */
  123. queue_head_t    swap_pager_free;    /* list of free pager clean structs */
  124. queue_head_t    swap_pager_list;    /* list of "named" anon regions */
  125.  
  126. void
  127. swap_pager_init()
  128. {
  129.     register swp_clean_t spc;
  130.     register int i, bsize;
  131.     extern int dmmin, dmmax;
  132.     int maxbsize;
  133.  
  134. #ifdef DEBUG
  135.     if (swpagerdebug & (SDB_FOLLOW|SDB_INIT))
  136.         printf("swpg_init()\n");
  137. #endif
  138.     dfltpagerops = &swappagerops;
  139.     queue_init(&swap_pager_list);
  140.  
  141.     /*
  142.      * Initialize clean lists
  143.      */
  144.     queue_init(&swap_pager_inuse);
  145.     queue_init(&swap_pager_free);
  146.     for (i = 0, spc = swcleanlist; i < NPENDINGIO; i++, spc++) {
  147.         queue_enter(&swap_pager_free, spc, swp_clean_t, spc_list);
  148.         spc->spc_flags = SPC_FREE;
  149.     }
  150.  
  151.     /*
  152.      * Calculate the swap allocation constants.
  153.      */
  154.         if (dmmin == 0) {
  155.                 dmmin = DMMIN;
  156.         if (dmmin < CLBYTES/DEV_BSIZE)
  157.             dmmin = CLBYTES/DEV_BSIZE;
  158.     }
  159.         if (dmmax == 0)
  160.                 dmmax = DMMAX;
  161.  
  162.     /*
  163.      * Fill in our table of object size vs. allocation size
  164.      */
  165.     bsize = btodb(PAGE_SIZE);
  166.     if (bsize < dmmin)
  167.         bsize = dmmin;
  168.     maxbsize = btodb(sizeof(sw_bm_t) * NBBY * PAGE_SIZE);
  169.     if (maxbsize > dmmax)
  170.         maxbsize = dmmax;
  171.     for (i = 0; i < NSWSIZES; i++) {
  172.         swtab[i].st_osize = (vm_size_t) (MAXDADDRS * dbtob(bsize));
  173.         swtab[i].st_bsize = bsize;
  174. #ifdef DEBUG
  175.         if (swpagerdebug & SDB_INIT)
  176.             printf("swpg_init: ix %d, size %x, bsize %x\n",
  177.                    i, swtab[i].st_osize, swtab[i].st_bsize);
  178. #endif
  179.         if (bsize >= maxbsize)
  180.             break;
  181.         bsize *= 2;
  182.     }
  183.     swtab[i].st_osize = 0;
  184.     swtab[i].st_bsize = bsize;
  185. }
  186.  
  187. /*
  188.  * Allocate a pager structure and associated resources.
  189.  * Note that if we are called from the pageout daemon (handle == NULL)
  190.  * we should not wait for memory as it could resulting in deadlock.
  191.  */
  192. vm_pager_t
  193. swap_pager_alloc(handle, size, prot)
  194.     caddr_t handle;
  195.     register vm_size_t size;
  196.     vm_prot_t prot;
  197. {
  198.     register vm_pager_t pager;
  199.     register sw_pager_t swp;
  200.     struct swtab *swt;
  201.     int waitok;
  202.  
  203. #ifdef DEBUG
  204.     if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOC))
  205.         printf("swpg_alloc(%x, %x, %x)\n", handle, size, prot);
  206. #endif
  207.     /*
  208.      * If this is a "named" anonymous region, look it up and
  209.      * return the appropriate pager if it exists.
  210.      */
  211.     if (handle) {
  212.         pager = vm_pager_lookup(&swap_pager_list, handle);
  213.         if (pager != NULL) {
  214.             /*
  215.              * Use vm_object_lookup to gain a reference
  216.              * to the object and also to remove from the
  217.              * object cache.
  218.              */
  219.             if (vm_object_lookup(pager) == NULL)
  220.                 panic("swap_pager_alloc: bad object");
  221.             return(pager);
  222.         }
  223.     }
  224.     /*
  225.      * Pager doesn't exist, allocate swap management resources
  226.      * and initialize.
  227.      */
  228.     waitok = handle ? M_WAITOK : M_NOWAIT;
  229.     pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, waitok);
  230.     if (pager == NULL)
  231.         return(NULL);
  232.     swp = (sw_pager_t)malloc(sizeof *swp, M_VMPGDATA, waitok);
  233.     if (swp == NULL) {
  234. #ifdef DEBUG
  235.         if (swpagerdebug & SDB_FAIL)
  236.             printf("swpg_alloc: swpager malloc failed\n");
  237. #endif
  238.         free((caddr_t)pager, M_VMPAGER);
  239.         return(NULL);
  240.     }
  241.     size = round_page(size);
  242.     for (swt = swtab; swt->st_osize; swt++)
  243.         if (size <= swt->st_osize)
  244.             break;
  245. #ifdef DEBUG
  246.     swt->st_inuse++;
  247.     swt->st_usecnt++;
  248. #endif
  249.     swp->sw_osize = size;
  250.     swp->sw_bsize = swt->st_bsize;
  251.     swp->sw_nblocks = (btodb(size) + swp->sw_bsize - 1) / swp->sw_bsize;
  252.     swp->sw_blocks = (sw_blk_t)
  253.         malloc(swp->sw_nblocks*sizeof(*swp->sw_blocks),
  254.                M_VMPGDATA, M_NOWAIT);
  255.     if (swp->sw_blocks == NULL) {
  256.         free((caddr_t)swp, M_VMPGDATA);
  257.         free((caddr_t)pager, M_VMPAGER);
  258. #ifdef DEBUG
  259.         if (swpagerdebug & SDB_FAIL)
  260.             printf("swpg_alloc: sw_blocks malloc failed\n");
  261.         swt->st_inuse--;
  262.         swt->st_usecnt--;
  263. #endif
  264.         return(FALSE);
  265.     }
  266.     bzero((caddr_t)swp->sw_blocks,
  267.           swp->sw_nblocks * sizeof(*swp->sw_blocks));
  268.     swp->sw_poip = 0;
  269.     if (handle) {
  270.         vm_object_t object;
  271.  
  272.         swp->sw_flags = SW_NAMED;
  273.         queue_enter(&swap_pager_list, pager, vm_pager_t, pg_list);
  274.         /*
  275.          * Consistant with other pagers: return with object
  276.          * referenced.  Can't do this with handle == NULL
  277.          * since it might be the pageout daemon calling.
  278.          */
  279.         object = vm_object_allocate(size);
  280.         vm_object_enter(object, pager);
  281.         vm_object_setpager(object, pager, 0, FALSE);
  282.     } else {
  283.         swp->sw_flags = 0;
  284.         queue_init(&pager->pg_list);
  285.     }
  286.     pager->pg_handle = handle;
  287.     pager->pg_ops = &swappagerops;
  288.     pager->pg_type = PG_SWAP;
  289.     pager->pg_data = (caddr_t)swp;
  290.  
  291. #ifdef DEBUG
  292.     if (swpagerdebug & SDB_ALLOC)
  293.         printf("swpg_alloc: pg_data %x, %x of %x at %x\n",
  294.                swp, swp->sw_nblocks, swp->sw_bsize, swp->sw_blocks);
  295. #endif
  296.     return(pager);
  297. }
  298.  
  299. void
  300. swap_pager_dealloc(pager)
  301.     vm_pager_t pager;
  302. {
  303.     register int i;
  304.     register sw_blk_t bp;
  305.     register sw_pager_t swp;
  306.     struct swtab *swt;
  307.     int s;
  308.  
  309. #ifdef DEBUG
  310.     /* save panic time state */
  311.     if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
  312.         return;
  313.     if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOC))
  314.         printf("swpg_dealloc(%x)\n", pager);
  315. #endif
  316.     /*
  317.      * Remove from list right away so lookups will fail if we
  318.      * block for pageout completion.
  319.      */
  320.     swp = (sw_pager_t) pager->pg_data;
  321.     if (swp->sw_flags & SW_NAMED) {
  322.         queue_remove(&swap_pager_list, pager, vm_pager_t, pg_list);
  323.         swp->sw_flags &= ~SW_NAMED;
  324.     }
  325. #ifdef DEBUG
  326.     for (swt = swtab; swt->st_osize; swt++)
  327.         if (swp->sw_osize <= swt->st_osize)
  328.             break;
  329.     swt->st_inuse--;
  330. #endif
  331.  
  332.     /*
  333.      * Wait for all pageouts to finish and remove
  334.      * all entries from cleaning list.
  335.      */
  336.     s = splbio();
  337.     while (swp->sw_poip) {
  338.         swp->sw_flags |= SW_WANTED;
  339.         assert_wait((int)swp);
  340.         thread_block();
  341.     }
  342.     splx(s);
  343.     (void) swap_pager_clean(NULL, B_WRITE);
  344.  
  345.     /*
  346.      * Free left over swap blocks
  347.      */
  348.     for (i = 0, bp = swp->sw_blocks; i < swp->sw_nblocks; i++, bp++)
  349.         if (bp->swb_block) {
  350. #ifdef DEBUG
  351.             if (swpagerdebug & (SDB_ALLOCBLK|SDB_FULL))
  352.                 printf("swpg_dealloc: blk %x\n",
  353.                        bp->swb_block);
  354. #endif
  355.             rmfree(swapmap, swp->sw_bsize, bp->swb_block);
  356.         }
  357.     /*
  358.      * Free swap management resources
  359.      */
  360.     free((caddr_t)swp->sw_blocks, M_VMPGDATA);
  361.     free((caddr_t)swp, M_VMPGDATA);
  362.     free((caddr_t)pager, M_VMPAGER);
  363. }
  364.  
  365. swap_pager_getpage(pager, m, sync)
  366.     vm_pager_t pager;
  367.     vm_page_t m;
  368.     boolean_t sync;
  369. {
  370. #ifdef DEBUG
  371.     if (swpagerdebug & SDB_FOLLOW)
  372.         printf("swpg_getpage(%x, %x, %d)\n", pager, m, sync);
  373. #endif
  374.     return(swap_pager_io((sw_pager_t)pager->pg_data, m, B_READ));
  375. }
  376.  
  377. swap_pager_putpage(pager, m, sync)
  378.     vm_pager_t pager;
  379.     vm_page_t m;
  380.     boolean_t sync;
  381. {
  382.     int flags;
  383.  
  384. #ifdef DEBUG
  385.     if (swpagerdebug & SDB_FOLLOW)
  386.         printf("swpg_putpage(%x, %x, %d)\n", pager, m, sync);
  387. #endif
  388.     if (pager == NULL) {
  389.         (void) swap_pager_clean(NULL, B_WRITE);
  390.         return;
  391.     }
  392.     flags = B_WRITE;
  393.     if (!sync)
  394.         flags |= B_ASYNC;
  395.     return(swap_pager_io((sw_pager_t)pager->pg_data, m, flags));
  396. }
  397.  
  398. boolean_t
  399. swap_pager_haspage(pager, offset)
  400.     vm_pager_t pager;
  401.     vm_offset_t offset;
  402. {
  403.     register sw_pager_t swp;
  404.     register sw_blk_t swb;
  405.     int ix;
  406.  
  407. #ifdef DEBUG
  408.     if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOCBLK))
  409.         printf("swpg_haspage(%x, %x) ", pager, offset);
  410. #endif
  411.     swp = (sw_pager_t) pager->pg_data;
  412.     ix = offset / dbtob(swp->sw_bsize);
  413.     if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
  414. #ifdef DEBUG
  415.         if (swpagerdebug & (SDB_FAIL|SDB_FOLLOW|SDB_ALLOCBLK))
  416.             printf("swpg_haspage: %x bad offset %x, ix %x\n",
  417.                    swp->sw_blocks, offset, ix);
  418. #endif
  419.         return(FALSE);
  420.     }
  421.     swb = &swp->sw_blocks[ix];
  422.     if (swb->swb_block)
  423.         ix = atop(offset % dbtob(swp->sw_bsize));
  424. #ifdef DEBUG
  425.     if (swpagerdebug & SDB_ALLOCBLK)
  426.         printf("%x blk %x+%x ", swp->sw_blocks, swb->swb_block, ix);
  427.     if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOCBLK))
  428.         printf("-> %c\n",
  429.                "FT"[swb->swb_block && (swb->swb_mask & (1 << ix))]);
  430. #endif
  431.     if (swb->swb_block && (swb->swb_mask & (1 << ix)))
  432.         return(TRUE);
  433.     return(FALSE);
  434. }
  435.  
  436. /*
  437.  * Scaled down version of swap().
  438.  * Assumes that PAGE_SIZE < MAXPHYS; i.e. only one operation needed.
  439.  * BOGUS:  lower level IO routines expect a KVA so we have to map our
  440.  * provided physical page into the KVA to keep them happy.
  441.  */
  442. swap_pager_io(swp, m, flags)
  443.     register sw_pager_t swp;
  444.     vm_page_t m;
  445.     int flags;
  446. {
  447.     register struct buf *bp;
  448.     register sw_blk_t swb;
  449.     register int s;
  450.     int ix;
  451.     boolean_t rv;
  452.     vm_offset_t kva, off;
  453.     swp_clean_t spc;
  454.  
  455. #ifdef DEBUG
  456.     /* save panic time state */
  457.     if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
  458.         return;
  459.     if (swpagerdebug & (SDB_FOLLOW|SDB_IO))
  460.         printf("swpg_io(%x, %x, %x)\n", swp, m, flags);
  461. #endif
  462.  
  463.     /*
  464.      * For reads (pageins) and synchronous writes, we clean up
  465.      * all completed async pageouts.
  466.      */
  467.     if ((flags & B_ASYNC) == 0) {
  468.         s = splbio();
  469. #ifdef DEBUG
  470.         /*
  471.          * Check to see if this page is currently being cleaned.
  472.          * If it is, we just wait til the operation is done before
  473.          * continuing.
  474.          */
  475.         while (swap_pager_clean(m, flags&B_READ)) {
  476.             if (swpagerdebug & SDB_ANOM)
  477.                 printf("swap_pager_io: page %x cleaning\n", m);
  478.  
  479.             swp->sw_flags |= SW_WANTED;
  480.             assert_wait((int)swp);
  481.             thread_block();
  482.         }
  483. #else
  484.         (void) swap_pager_clean(m, flags&B_READ);
  485. #endif
  486.         splx(s);
  487.     }
  488.     /*
  489.      * For async writes (pageouts), we cleanup completed pageouts so
  490.      * that all available resources are freed.  Also tells us if this
  491.      * page is already being cleaned.  If it is, or no resources
  492.      * are available, we try again later.
  493.      */
  494.     else if (swap_pager_clean(m, B_WRITE) ||
  495.          queue_empty(&swap_pager_free)) {
  496. #ifdef DEBUG
  497.         if ((swpagerdebug & SDB_ANOM) &&
  498.             !queue_empty(&swap_pager_free))
  499.             printf("swap_pager_io: page %x already cleaning\n", m);
  500. #endif
  501.         return(VM_PAGER_FAIL);
  502.     }
  503.  
  504.     /*
  505.      * Determine swap block and allocate as necessary.
  506.      */
  507.     off = m->offset + m->object->paging_offset;
  508.     ix = off / dbtob(swp->sw_bsize);
  509.     if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
  510. #ifdef DEBUG
  511.         if (swpagerdebug & SDB_FAIL)
  512.             printf("swpg_io: bad offset %x+%x(%d) in %x\n",
  513.                    m->offset, m->object->paging_offset,
  514.                    ix, swp->sw_blocks);
  515. #endif
  516.         return(VM_PAGER_FAIL);
  517.     }
  518.     swb = &swp->sw_blocks[ix];
  519.     off = off % dbtob(swp->sw_bsize);
  520.     if (flags & B_READ) {
  521.         if (swb->swb_block == 0 ||
  522.             (swb->swb_mask & (1 << atop(off))) == 0) {
  523. #ifdef DEBUG
  524.             if (swpagerdebug & (SDB_ALLOCBLK|SDB_FAIL))
  525.                 printf("swpg_io: %x bad read: blk %x+%x, mask %x, off %x+%x\n",
  526.                        swp->sw_blocks,
  527.                        swb->swb_block, atop(off),
  528.                        swb->swb_mask,
  529.                        m->offset, m->object->paging_offset);
  530. #endif
  531.             /* XXX: should we zero page here?? */
  532.             return(VM_PAGER_FAIL);
  533.         }
  534.     } else if (swb->swb_block == 0) {
  535.         swb->swb_block = rmalloc(swapmap, swp->sw_bsize);
  536.         if (swb->swb_block == 0) {
  537. #ifdef DEBUG
  538.             if (swpagerdebug & SDB_FAIL)
  539.                 printf("swpg_io: rmalloc of %x failed\n",
  540.                        swp->sw_bsize);
  541. #endif
  542.             return(VM_PAGER_FAIL);
  543.         }
  544. #ifdef DEBUG
  545.         if (swpagerdebug & (SDB_FULL|SDB_ALLOCBLK))
  546.             printf("swpg_io: %x alloc blk %x at ix %x\n",
  547.                    swp->sw_blocks, swb->swb_block, ix);
  548. #endif
  549.     }
  550.  
  551.     /*
  552.      * Allocate a kernel virtual address and initialize so that PTE
  553.      * is available for lower level IO drivers.
  554.      */
  555.     kva = vm_pager_map_page(m);
  556.  
  557.     /*
  558.      * Get a swap buffer header and perform the IO
  559.      */
  560.     s = splbio();
  561.     while (bswlist.av_forw == NULL) {
  562. #ifdef DEBUG
  563.         if (swpagerdebug & SDB_ANOM)
  564.             printf("swap_pager_io: wait on swbuf for %x (%d)\n",
  565.                    m, flags);
  566. #endif
  567.         bswlist.b_flags |= B_WANTED;
  568.         sleep((caddr_t)&bswlist, PSWP+1);
  569.     }
  570.     bp = bswlist.av_forw;
  571.     bswlist.av_forw = bp->av_forw;
  572.     splx(s);
  573.     bp->b_flags = B_BUSY | (flags & B_READ);
  574.     bp->b_proc = &proc0;    /* XXX (but without B_PHYS set this is ok) */
  575.     bp->b_un.b_addr = (caddr_t)kva;
  576.     bp->b_blkno = swb->swb_block + btodb(off);
  577.     VHOLD(swapdev_vp);
  578.     bp->b_vp = swapdev_vp;
  579.     if (swapdev_vp->v_type == VBLK)
  580.         bp->b_dev = swapdev_vp->v_rdev;
  581.     bp->b_bcount = PAGE_SIZE;
  582.     if ((bp->b_flags & B_READ) == 0)
  583.         swapdev_vp->v_numoutput++;
  584.  
  585.     /*
  586.      * If this is an async write we set up additional buffer fields
  587.      * and place a "cleaning" entry on the inuse queue.
  588.      */
  589.     if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) {
  590. #ifdef DEBUG
  591.         if (queue_empty(&swap_pager_free))
  592.             panic("swpg_io: lost spc");
  593. #endif
  594.         queue_remove_first(&swap_pager_free,
  595.                    spc, swp_clean_t, spc_list);
  596. #ifdef DEBUG
  597.         if (spc->spc_flags != SPC_FREE)
  598.             panic("swpg_io: bad free spc");
  599. #endif
  600.         spc->spc_flags = SPC_BUSY;
  601.         spc->spc_bp = bp;
  602.         spc->spc_swp = swp;
  603.         spc->spc_kva = kva;
  604.         spc->spc_m = m;
  605.         bp->b_flags |= B_CALL;
  606.         bp->b_iodone = swap_pager_iodone;
  607.         s = splbio();
  608.         swp->sw_poip++;
  609.         queue_enter(&swap_pager_inuse, spc, swp_clean_t, spc_list);
  610.  
  611. #ifdef DEBUG
  612.         swap_pager_poip++;
  613.         if (swpagerdebug & SDB_WRITE)
  614.             printf("swpg_io: write: bp=%x swp=%x spc=%x poip=%d\n",
  615.                    bp, swp, spc, swp->sw_poip);
  616.         if ((swpagerdebug & SDB_ALLOCBLK) &&
  617.             (swb->swb_mask & (1 << atop(off))) == 0)
  618.             printf("swpg_io: %x write blk %x+%x\n",
  619.                    swp->sw_blocks, swb->swb_block, atop(off));
  620. #endif
  621.         swb->swb_mask |= (1 << atop(off));
  622.         splx(s);
  623.     }
  624. #ifdef DEBUG
  625.     if (swpagerdebug & SDB_IO)
  626.         printf("swpg_io: IO start: bp %x, db %x, va %x, pa %x\n",
  627.                bp, swb->swb_block+btodb(off), kva, VM_PAGE_TO_PHYS(m));
  628. #endif
  629.     VOP_STRATEGY(bp);
  630.     if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) {
  631. #ifdef DEBUG
  632.         if (swpagerdebug & SDB_IO)
  633.             printf("swpg_io:  IO started: bp %x\n", bp);
  634. #endif
  635.         return(VM_PAGER_PEND);
  636.     }
  637.     s = splbio();
  638. #ifdef DEBUG
  639.     if (flags & B_READ)
  640.         swap_pager_piip++;
  641.     else
  642.         swap_pager_poip++;
  643. #endif
  644.     while ((bp->b_flags & B_DONE) == 0) {
  645.         assert_wait((int)bp);
  646.         thread_block();
  647.     }
  648. #ifdef DEBUG
  649.     if (flags & B_READ)
  650.         --swap_pager_piip;
  651.     else
  652.         --swap_pager_poip;
  653. #endif
  654.     rv = (bp->b_flags & B_ERROR) ? VM_PAGER_FAIL : VM_PAGER_OK;
  655.     bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
  656.     bp->av_forw = bswlist.av_forw;
  657.     bswlist.av_forw = bp;
  658.     if (bp->b_vp)
  659.         brelvp(bp);
  660.     if (bswlist.b_flags & B_WANTED) {
  661.         bswlist.b_flags &= ~B_WANTED;
  662.         thread_wakeup((int)&bswlist);
  663.     }
  664.     if ((flags & B_READ) == 0 && rv == VM_PAGER_OK) {
  665.         m->clean = TRUE;
  666.         pmap_clear_modify(VM_PAGE_TO_PHYS(m));
  667.     }
  668.     splx(s);
  669. #ifdef DEBUG
  670.     if (swpagerdebug & SDB_IO)
  671.         printf("swpg_io:  IO done: bp %x, rv %d\n", bp, rv);
  672.     if ((swpagerdebug & SDB_FAIL) && rv == VM_PAGER_FAIL)
  673.         printf("swpg_io: IO error\n");
  674. #endif
  675.     vm_pager_unmap_page(kva);
  676.     return(rv);
  677. }
  678.  
  679. boolean_t
  680. swap_pager_clean(m, rw)
  681.     vm_page_t m;
  682.     int rw;
  683. {
  684.     register swp_clean_t spc, tspc;
  685.     register int s;
  686.  
  687. #ifdef DEBUG
  688.     /* save panic time state */
  689.     if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
  690.         return;
  691.     if (swpagerdebug & SDB_FOLLOW)
  692.         printf("swpg_clean(%x, %d)\n", m, rw);
  693. #endif
  694.     tspc = NULL;
  695.     for (;;) {
  696.         /*
  697.          * Look up and removal from inuse list must be done
  698.          * at splbio() to avoid conflicts with swap_pager_iodone.
  699.          */
  700.         s = splbio();
  701.         spc = (swp_clean_t) queue_first(&swap_pager_inuse);
  702.         while (!queue_end(&swap_pager_inuse, (queue_entry_t)spc)) {
  703.             if ((spc->spc_flags & SPC_DONE) &&
  704.                 swap_pager_finish(spc)) {
  705.                 queue_remove(&swap_pager_inuse, spc,
  706.                          swp_clean_t, spc_list);
  707.                 break;
  708.             }
  709.             if (m && m == spc->spc_m) {
  710. #ifdef DEBUG
  711.                 if (swpagerdebug & SDB_ANOM)
  712.                     printf("swap_pager_clean: page %x on list, flags %x\n",
  713.                            m, spc->spc_flags);
  714. #endif
  715.                 tspc = spc;
  716.             }
  717.             spc = (swp_clean_t) queue_next(&spc->spc_list);
  718.         }
  719.  
  720.         /*
  721.          * No operations done, thats all we can do for now.
  722.          */
  723.         if (queue_end(&swap_pager_inuse, (queue_entry_t)spc))
  724.             break;
  725.         splx(s);
  726.  
  727.         /*
  728.          * The desired page was found to be busy earlier in
  729.          * the scan but has since completed.
  730.          */
  731.         if (tspc && tspc == spc) {
  732. #ifdef DEBUG
  733.             if (swpagerdebug & SDB_ANOM)
  734.                 printf("swap_pager_clean: page %x done while looking\n",
  735.                        m);
  736. #endif
  737.             tspc = NULL;
  738.         }
  739.         spc->spc_flags = SPC_FREE;
  740.         vm_pager_unmap_page(spc->spc_kva);
  741.         queue_enter(&swap_pager_free, spc, swp_clean_t, spc_list);
  742. #ifdef DEBUG
  743.         if (swpagerdebug & SDB_WRITE)
  744.             printf("swpg_clean: free spc %x\n", spc);
  745. #endif
  746.     }
  747. #ifdef DEBUG
  748.     /*
  749.      * If we found that the desired page is already being cleaned
  750.      * mark it so that swap_pager_iodone() will not set the clean
  751.      * flag before the pageout daemon has another chance to clean it.
  752.      */
  753.     if (tspc && rw == B_WRITE) {
  754.         if (swpagerdebug & SDB_ANOM)
  755.             printf("swap_pager_clean: page %x on clean list\n",
  756.                    tspc);
  757.         tspc->spc_flags |= SPC_DIRTY;
  758.     }
  759. #endif
  760.     splx(s);
  761.  
  762. #ifdef DEBUG
  763.     if (swpagerdebug & SDB_WRITE)
  764.         printf("swpg_clean: return %d\n", tspc ? TRUE : FALSE);
  765.     if ((swpagerdebug & SDB_ANOM) && tspc)
  766.         printf("swpg_clean: %s of cleaning page %x\n",
  767.                rw == B_READ ? "get" : "put", m);
  768. #endif
  769.     return(tspc ? TRUE : FALSE);
  770. }
  771.  
  772. swap_pager_finish(spc)
  773.     register swp_clean_t spc;
  774. {
  775.     vm_object_t object = spc->spc_m->object;
  776.  
  777.     /*
  778.      * Mark the paging operation as done.
  779.      * (XXX) If we cannot get the lock, leave it til later.
  780.      * (XXX) Also we are assuming that an async write is a
  781.      *       pageout operation that has incremented the counter.
  782.      */
  783.     if (!vm_object_lock_try(object))
  784.         return(0);
  785.  
  786.     if (--object->paging_in_progress == 0)
  787.         thread_wakeup((int) object);
  788.  
  789. #ifdef DEBUG
  790.     /*
  791.      * XXX: this isn't even close to the right thing to do,
  792.      * introduces a variety of race conditions.
  793.      *
  794.      * If dirty, vm_pageout() has attempted to clean the page
  795.      * again.  In this case we do not do anything as we will
  796.      * see the page again shortly.
  797.      */
  798.     if (spc->spc_flags & SPC_DIRTY) {
  799.         if (swpagerdebug & SDB_ANOM)
  800.             printf("swap_pager_finish: page %x dirty again\n",
  801.                    spc->spc_m);
  802.         spc->spc_m->busy = FALSE;
  803.         PAGE_WAKEUP(spc->spc_m);
  804.         vm_object_unlock(object);
  805.         return(1);
  806.     }
  807. #endif
  808.     /*
  809.      * If no error mark as clean and inform the pmap system.
  810.      * If error, mark as dirty so we will try again.
  811.      * (XXX could get stuck doing this, should give up after awhile)
  812.      */
  813.     if (spc->spc_flags & SPC_ERROR) {
  814.         printf("swap_pager_finish: clean of page %x failed\n",
  815.                VM_PAGE_TO_PHYS(spc->spc_m));
  816.         spc->spc_m->laundry = TRUE;
  817.     } else {
  818.         spc->spc_m->clean = TRUE;
  819.         pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m));
  820.     }
  821.     spc->spc_m->busy = FALSE;
  822.     PAGE_WAKEUP(spc->spc_m);
  823.  
  824.     vm_object_unlock(object);
  825.     return(1);
  826. }
  827.  
  828. swap_pager_iodone(bp)
  829.     register struct buf *bp;
  830. {
  831.     register swp_clean_t spc;
  832.     daddr_t blk;
  833.     int s;
  834.  
  835. #ifdef DEBUG
  836.     /* save panic time state */
  837.     if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
  838.         return;
  839.     if (swpagerdebug & SDB_FOLLOW)
  840.         printf("swpg_iodone(%x)\n", bp);
  841. #endif
  842.     s = splbio();
  843.     spc = (swp_clean_t) queue_first(&swap_pager_inuse);
  844.     while (!queue_end(&swap_pager_inuse, (queue_entry_t)spc)) {
  845.         if (spc->spc_bp == bp)
  846.             break;
  847.         spc = (swp_clean_t) queue_next(&spc->spc_list);
  848.     }
  849. #ifdef DEBUG
  850.     if (queue_end(&swap_pager_inuse, (queue_entry_t)spc))
  851.         panic("swap_pager_iodone: bp not found");
  852. #endif
  853.  
  854.     spc->spc_flags &= ~SPC_BUSY;
  855.     spc->spc_flags |= SPC_DONE;
  856.     if (bp->b_flags & B_ERROR)
  857.         spc->spc_flags |= SPC_ERROR;
  858.     spc->spc_bp = NULL;
  859.     blk = bp->b_blkno;
  860.  
  861. #ifdef DEBUG
  862.     --swap_pager_poip;
  863.     if (swpagerdebug & SDB_WRITE)
  864.         printf("swpg_iodone: bp=%x swp=%x flags=%x spc=%x poip=%x\n",
  865.                bp, spc->spc_swp, spc->spc_swp->sw_flags,
  866.                spc, spc->spc_swp->sw_poip);
  867. #endif
  868.  
  869.     spc->spc_swp->sw_poip--;
  870.     if (spc->spc_swp->sw_flags & SW_WANTED) {
  871.         spc->spc_swp->sw_flags &= ~SW_WANTED;
  872.         thread_wakeup((int)spc->spc_swp);
  873.     }
  874.         
  875.     bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
  876.     bp->av_forw = bswlist.av_forw;
  877.     bswlist.av_forw = bp;
  878.     if (bp->b_vp)
  879.         brelvp(bp);
  880.     if (bswlist.b_flags & B_WANTED) {
  881.         bswlist.b_flags &= ~B_WANTED;
  882.         thread_wakeup((int)&bswlist);
  883.     }
  884.     thread_wakeup((int) &vm_pages_needed);
  885.     splx(s);
  886. }
  887. #endif
  888.