aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Schultz <das@FreeBSD.org>2004-11-06 07:17:50 +0000
committerDavid Schultz <das@FreeBSD.org>2004-11-06 07:17:50 +0000
commit8bc61209d44a8114387dcdba2dc1b9e0d880bbf7 (patch)
treef606cc223b6da16a09340e1d6c06212f6dac31be
parent550b156641d67376839540e4202ee73796100a2a (diff)
downloadsrc-8bc61209d44a8114387dcdba2dc1b9e0d880bbf7.tar.gz
src-8bc61209d44a8114387dcdba2dc1b9e0d880bbf7.zip
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.
Notes
Notes: svn path=/head/; revision=137299
-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 da7f1c03d6e1..6ce0c6108605 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);
}
/************************************************************************