summaryrefslogtreecommitdiffstats
path: root/sys/vm
diff options
context:
space:
mode:
authordas <das@FreeBSD.org>2004-11-06 07:17:50 +0000
committerdas <das@FreeBSD.org>2004-11-06 07:17:50 +0000
commit9d935df169273c60c7362e63fe5d98bc85e23d8b (patch)
treef606cc223b6da16a09340e1d6c06212f6dac31be /sys/vm
parent8bc275db5e700002108ad80bc1c460cbe85457bb (diff)
downloadFreeBSD-src-9d935df169273c60c7362e63fe5d98bc85e23d8b.zip
FreeBSD-src-9d935df169273c60c7362e63fe5d98bc85e23d8b.tar.gz
Fix the last known race in swapoff(), which could lead to a spurious panic:
swapoff: failed to locate %d swap blocks The race occurred because putpages() can block between the time it allocates swap space and the time it updates the swap metadata to associate that space with a vm_object, so swapoff() would complain about the temporary inconsistency. I hoped to fix this by making swp_pager_getswapspace() and swp_pager_meta_build() a single atomic operation, but that proved to be inconvenient. With this change, swapoff() simply doesn't attempt to be so clever about detecting when all the pageout activity to the target device should have drained.
Diffstat (limited to 'sys/vm')
-rw-r--r--sys/vm/swap_pager.c35
1 files changed, 14 insertions, 21 deletions
diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c
index da7f1c0..6ce0c610 100644
--- a/sys/vm/swap_pager.c
+++ b/sys/vm/swap_pager.c
@@ -1666,13 +1666,12 @@ static void
swap_pager_swapoff(struct swdevt *sp)
{
struct swblock *swap;
- vm_object_t waitobj;
- int i, j;
+ int i, j, retries;
GIANT_REQUIRED;
+ retries = 0;
full_rescan:
- waitobj = NULL;
mtx_lock(&swhash_mtx);
for (i = 0; i <= swhash_mask; i++) { /* '<=' is correct here */
restart:
@@ -1683,7 +1682,6 @@ restart:
if (swp_pager_isondev(swap->swb_pages[j], sp)) {
/* avoid deadlock */
if (!VM_OBJECT_TRYLOCK(object)) {
- waitobj = object;
break;
} else {
mtx_unlock(&swhash_mtx);
@@ -1695,30 +1693,25 @@ restart:
}
}
}
- if (object->paging_in_progress)
- waitobj = object;
}
}
mtx_unlock(&swhash_mtx);
- if (waitobj && sp->sw_used) {
+ if (sp->sw_used) {
+ int dummy;
/*
- * 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.
+ * Objects may be locked or paging to the device being
+ * removed, so we will miss their pages and need to
+ * make another pass. We have marked this device as
+ * SW_CLOSING, so the activity should finish soon.
*/
- tsleep(waitobj, PVM, "swpoff", hz / 20);
+ retries++;
+ if (retries > 100) {
+ panic("swapoff: failed to locate %d swap blocks",
+ sp->sw_used);
+ }
+ tsleep(&dummy, PVM, "swpoff", hz / 20);
goto full_rescan;
}
- if (sp->sw_used)
- panic("swapoff: failed to locate %d swap blocks", sp->sw_used);
}
/************************************************************************
OpenPOWER on IntegriCloud