diff options
| author | David Schultz <das@FreeBSD.org> | 2004-11-05 05:36:56 +0000 |
|---|---|---|
| committer | David Schultz <das@FreeBSD.org> | 2004-11-05 05:36:56 +0000 |
| commit | b3fed13e9dba0b74972266f78bc6df6c51613b1a (patch) | |
| tree | 94c5d1589c4833b313bdb27920dd84d12e5f85b3 /sys/vm | |
| parent | 88507deac27c3ee1293b8a380f632edb61410bb8 (diff) | |
Notes
Diffstat (limited to 'sys/vm')
| -rw-r--r-- | sys/vm/swap_pager.c | 123 |
1 files changed, 53 insertions, 70 deletions
diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c index b4c6a6a862fc..da7f1c03d6e1 100644 --- a/sys/vm/swap_pager.c +++ b/sys/vm/swap_pager.c @@ -236,7 +236,7 @@ static boolean_t swap_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before, int *after); static void swap_pager_init(void); static void swap_pager_unswapped(vm_page_t); -static void swap_pager_swapoff(struct swdevt *sp, int *sw_used); +static void swap_pager_swapoff(struct swdevt *sp); struct pagerops swappagerops = { .pgo_init = swap_pager_init, /* early system initialization of pager */ @@ -609,19 +609,11 @@ done: return (blk); } -static struct swdevt * -swp_pager_find_dev(daddr_t blk) +static int +swp_pager_isondev(daddr_t blk, struct swdevt *sp) { - struct swdevt *sp; - mtx_lock(&sw_dev_mtx); - TAILQ_FOREACH(sp, &swtailq, sw_list) { - if (blk >= sp->sw_first && blk < sp->sw_end) { - mtx_unlock(&sw_dev_mtx); - return (sp); - } - } - panic("Swapdev not found"); + return (blk >= sp->sw_first && blk < sp->sw_end); } static void @@ -1597,27 +1589,24 @@ swap_pager_isswapped(vm_object_t object, struct swdevt *sp) if (object->type != OBJT_SWAP) return (0); + mtx_lock(&swhash_mtx); for (bcount = 0; bcount < object->un_pager.swp.swp_bcount; bcount++) { struct swblock *swap; - mtx_lock(&swhash_mtx); if ((swap = *swp_pager_hash(object, index)) != NULL) { for (i = 0; i < SWAP_META_PAGES; ++i) { - daddr_t v = swap->swb_pages[i]; - if (v == SWAPBLK_NONE) - continue; - if (swp_pager_find_dev(v) == sp) { + if (swp_pager_isondev(swap->swb_pages[i], sp)) { mtx_unlock(&swhash_mtx); - return 1; + return (1); } } } - mtx_unlock(&swhash_mtx); index += SWAP_META_PAGES; if (index > 0x20000000) panic("swap_pager_isswapped: failed to locate all swap meta blocks"); } - return 0; + mtx_unlock(&swhash_mtx); + return (0); } /* @@ -1635,19 +1624,12 @@ swap_pager_isswapped(vm_object_t object, struct swdevt *sp) * revert to the one-by-one behavior for now. Sigh. */ static __inline void -swp_pager_force_pagein(struct swblock *swap, int idx) +swp_pager_force_pagein(vm_object_t object, vm_pindex_t pindex) { - vm_object_t object; vm_page_t m; - vm_pindex_t pindex; - object = swap->swb_object; - pindex = swap->swb_index; - mtx_unlock(&swhash_mtx); - - VM_OBJECT_LOCK(object); vm_object_pip_add(object, 1); - m = vm_page_grab(object, pindex + idx, VM_ALLOC_NORMAL|VM_ALLOC_RETRY); + m = vm_page_grab(object, pindex, VM_ALLOC_NORMAL|VM_ALLOC_RETRY); if (m->valid == VM_PAGE_BITS_ALL) { vm_object_pip_subtract(object, 1); vm_page_lock_queues(); @@ -1656,12 +1638,10 @@ swp_pager_force_pagein(struct swblock *swap, int idx) vm_page_wakeup(m); vm_page_unlock_queues(); vm_pager_page_unswapped(m); - VM_OBJECT_UNLOCK(object); return; } - if (swap_pager_getpages(object, &m, 1, 0) != - VM_PAGER_OK) + if (swap_pager_getpages(object, &m, 1, 0) != VM_PAGER_OK) panic("swap_pager_force_pagein: read from swap failed");/*XXX*/ vm_object_pip_subtract(object, 1); vm_page_lock_queues(); @@ -1670,10 +1650,8 @@ swp_pager_force_pagein(struct swblock *swap, int idx) vm_page_wakeup(m); vm_page_unlock_queues(); vm_pager_page_unswapped(m); - VM_OBJECT_UNLOCK(object); } - /* * swap_pager_swapoff: * @@ -1682,60 +1660,65 @@ swp_pager_force_pagein(struct swblock *swap, int idx) * marked as allocated and the device must be flagged SW_CLOSING. * There may be no processes swapped out to the device. * - * The sw_used parameter points to the field in the swdev structure - * that contains a count of the number of blocks still allocated - * on the device. If we encounter objects with a nonzero pip count - * in our scan, we use this number to determine if we're really done. - * * This routine may block. */ static void -swap_pager_swapoff(struct swdevt *sp, int *sw_used) +swap_pager_swapoff(struct swdevt *sp) { - struct swblock **pswap; struct swblock *swap; vm_object_t waitobj; - daddr_t v; int i, j; GIANT_REQUIRED; full_rescan: waitobj = NULL; + mtx_lock(&swhash_mtx); for (i = 0; i <= swhash_mask; i++) { /* '<=' is correct here */ restart: - pswap = &swhash[i]; - mtx_lock(&swhash_mtx); - while ((swap = *pswap) != NULL) { + for (swap = swhash[i]; swap != NULL; swap = swap->swb_hnext) { + vm_object_t object = swap->swb_object; + vm_pindex_t pindex = swap->swb_index; for (j = 0; j < SWAP_META_PAGES; ++j) { - v = swap->swb_pages[j]; - if (v != SWAPBLK_NONE && - swp_pager_find_dev(v) == sp) - break; + if (swp_pager_isondev(swap->swb_pages[j], sp)) { + /* avoid deadlock */ + if (!VM_OBJECT_TRYLOCK(object)) { + waitobj = object; + break; + } else { + mtx_unlock(&swhash_mtx); + swp_pager_force_pagein(object, + pindex + j); + VM_OBJECT_UNLOCK(object); + mtx_lock(&swhash_mtx); + goto restart; + } + } } - if (j < SWAP_META_PAGES) { - swp_pager_force_pagein(swap, j); - goto restart; - } else if (swap->swb_object->paging_in_progress) { - if (!waitobj) - waitobj = swap->swb_object; - } - pswap = &swap->swb_hnext; + if (object->paging_in_progress) + waitobj = object; } - mtx_unlock(&swhash_mtx); } - if (waitobj && *sw_used) { - /* - * We wait on an arbitrary object to clock our rescans - * to the rate of paging completion. - */ - VM_OBJECT_LOCK(waitobj); - vm_object_pip_wait(waitobj, "swpoff"); - VM_OBJECT_UNLOCK(waitobj); - goto full_rescan; + mtx_unlock(&swhash_mtx); + if (waitobj && sp->sw_used) { + /* + * The most likely reason we will have to do another pass is + * that something is being paged out to the device being + * removed. This can't happen forever because new allocations + * will not be made on this device, but we still need to wait + * for the activity to finish. We have no way of knowing + * which objects we need to wait for, so we pick an arbitrary + * object that is paging and hope that it finishes paging at + * about the same time as one of the objects we care about. + * + * XXX Unfortunately, our waitobj reference might not be valid + * anymore, so we also retry after 50 ms. + */ + tsleep(waitobj, PVM, "swpoff", hz / 20); + goto full_rescan; } - if (*sw_used) - panic("swapoff: failed to locate %d swap blocks", *sw_used); + if (sp->sw_used) + panic("swapoff: failed to locate %d swap blocks", sp->sw_used); } /************************************************************************ @@ -2237,7 +2220,7 @@ found: #ifndef NO_SWAPPING vm_proc_swapin_all(sp); #endif /* !NO_SWAPPING */ - swap_pager_swapoff(sp, &sp->sw_used); + swap_pager_swapoff(sp); sp->sw_close(td, sp); sp->sw_id = NULL; |
