summaryrefslogtreecommitdiffstats
path: root/sys/vm/swap_pager.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/vm/swap_pager.c')
-rw-r--r--sys/vm/swap_pager.c77
1 files changed, 66 insertions, 11 deletions
diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c
index 8d343f4..44f4465 100644
--- a/sys/vm/swap_pager.c
+++ b/sys/vm/swap_pager.c
@@ -80,7 +80,6 @@
#include <sys/sysctl.h>
#include <sys/blist.h>
#include <sys/lock.h>
-#include <sys/sx.h>
#include <sys/vmmeter.h>
#ifndef MAX_PAGEOUT_CLUSTER
@@ -119,6 +118,7 @@ static int nsw_wcount_sync; /* limit write buffers / synchronous */
static int nsw_wcount_async; /* limit write buffers / asynchronous */
static int nsw_wcount_async_max;/* assigned maximum */
static int nsw_cluster_max; /* maximum VOP I/O allowed */
+static int sw_alloc_interlock; /* swap pager allocation interlock */
struct blist *swapblist;
static struct swblock **swhash;
@@ -145,7 +145,6 @@ SYSCTL_INT(_vm, OID_AUTO, swap_async_max,
#define NOBJLIST(handle) \
(&swap_pager_object_list[((int)(intptr_t)handle >> 4) & (NOBJLISTS-1)])
-static struct sx sw_alloc_sx; /* prevent concurrant creation */
static struct mtx sw_alloc_mtx; /* protect list manipulation */
static struct pagerlst swap_pager_object_list[NOBJLISTS];
struct pagerlst swap_pager_un_object_list;
@@ -233,6 +232,8 @@ static daddr_t swp_pager_meta_ctl __P((vm_object_t, vm_pindex_t, int));
static __inline void
swp_sizecheck()
{
+
+ mtx_assert(&vm_mtx, MA_OWNED);
if (vm_swap_size < nswap_lowat) {
if (swap_pager_almost_full == 0) {
printf("swap_pager: out of swap space\n");
@@ -264,7 +265,6 @@ swap_pager_init()
for (i = 0; i < NOBJLISTS; ++i)
TAILQ_INIT(&swap_pager_object_list[i]);
TAILQ_INIT(&swap_pager_un_object_list);
- sx_init(&sw_alloc_sx, "swap_pager create");
mtx_init(&sw_alloc_mtx, "swap_pager list", MTX_DEF);
/*
@@ -389,7 +389,10 @@ swap_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot,
* of the handle.
*/
- sx_xlock(&sw_alloc_sx);
+ while (sw_alloc_interlock) {
+ sw_alloc_interlock = -1;
+ msleep(&sw_alloc_interlock, &vm_mtx, PVM, "swpalc", 0);
+ }
object = vm_pager_object_lookup(NOBJLIST(handle), handle);
@@ -403,7 +406,9 @@ swap_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot,
swp_pager_meta_build(object, 0, SWAPBLK_NONE);
}
- sx_xunlock(&sw_alloc_sx);
+ if (sw_alloc_interlock < 0)
+ wakeup(&sw_alloc_interlock);
+ sw_alloc_interlock = 0;
} else {
object = vm_object_allocate(OBJT_DEFAULT,
OFF_TO_IDX(offset + PAGE_MASK + size));
@@ -478,6 +483,7 @@ swap_pager_dealloc(object)
*
* This routine may not block
* This routine must be called at splvm().
+ * vm_mtx should be held
*/
static __inline daddr_t
@@ -486,6 +492,7 @@ swp_pager_getswapspace(npages)
{
daddr_t blk;
+ mtx_assert(&vm_mtx, MA_OWNED);
if ((blk = blist_alloc(swapblist, npages)) == SWAPBLK_NONE) {
if (swap_pager_full != 2) {
printf("swap_pager_getswapspace: failed\n");
@@ -514,6 +521,7 @@ swp_pager_getswapspace(npages)
*
* This routine may not block
* This routine must be called at splvm().
+ * vm_mtx should be held
*/
static __inline void
@@ -521,6 +529,8 @@ swp_pager_freeswapspace(blk, npages)
daddr_t blk;
int npages;
{
+
+ mtx_assert(&vm_mtx, MA_OWNED);
blist_free(swapblist, blk, npages);
vm_swap_size += npages;
/* per-swap area stats */
@@ -551,6 +561,9 @@ swap_pager_freespace(object, start, size)
vm_size_t size;
{
int s = splvm();
+
+ mtx_assert(&vm_mtx, MA_OWNED);
+
swp_pager_meta_free(object, start, size);
splx(s);
}
@@ -635,6 +648,8 @@ swap_pager_copy(srcobject, dstobject, offset, destroysource)
s = splvm();
+ mtx_assert(&vm_mtx, MA_OWNED);
+
/*
* If destroysource is set, we remove the source object from the
* swap_pager internal queue now.
@@ -881,7 +896,9 @@ swap_pager_strategy(vm_object_t object, struct bio *bp)
* FREE PAGE(s) - destroy underlying swap that is no longer
* needed.
*/
+ mtx_lock(&vm_mtx);
swp_pager_meta_free(object, start, count);
+ mtx_unlock(&vm_mtx);
splx(s);
bp->bio_resid = 0;
biodone(bp);
@@ -892,6 +909,7 @@ swap_pager_strategy(vm_object_t object, struct bio *bp)
* Execute read or write
*/
+ mtx_lock(&vm_mtx);
while (count > 0) {
daddr_t blk;
@@ -954,7 +972,9 @@ swap_pager_strategy(vm_object_t object, struct bio *bp)
bp->bio_resid -= PAGE_SIZE;
} else {
if (nbp == NULL) {
+ mtx_unlock(&vm_mtx);
nbp = getchainbuf(bp, swapdev_vp, B_ASYNC);
+ mtx_lock(&vm_mtx);
nbp->b_blkno = blk;
nbp->b_bcount = 0;
nbp->b_data = data;
@@ -985,6 +1005,7 @@ swap_pager_strategy(vm_object_t object, struct bio *bp)
/* nbp = NULL; */
}
+ mtx_unlock(&vm_mtx);
/*
* Wait for completion.
*/
@@ -1281,6 +1302,7 @@ swap_pager_putpages(object, m, count, sync, rtvals)
* at this time.
*/
s = splvm();
+ mtx_unlock(&vm_mtx);
mtx_lock(&pbuf_mtx);
n -= nsw_wcount_async_max;
if (nsw_wcount_async + n >= 0) {
@@ -1289,6 +1311,7 @@ swap_pager_putpages(object, m, count, sync, rtvals)
wakeup(&nsw_wcount_async);
}
mtx_unlock(&pbuf_mtx);
+ mtx_lock(&vm_mtx);
splx(s);
}
@@ -1399,6 +1422,8 @@ swap_pager_putpages(object, m, count, sync, rtvals)
swapdev_vp->v_numoutput++;
splx(s);
+ mtx_unlock(&vm_mtx);
+ mtx_lock(&Giant);
/*
* asynchronous
@@ -1410,9 +1435,12 @@ swap_pager_putpages(object, m, count, sync, rtvals)
bp->b_iodone = swp_pager_async_iodone;
BUF_KERNPROC(bp);
BUF_STRATEGY(bp);
+ mtx_unlock(&Giant);
+ mtx_lock(&vm_mtx);
for (j = 0; j < n; ++j)
rtvals[i+j] = VM_PAGER_PEND;
+ /* restart outter loop */
continue;
}
@@ -1445,6 +1473,8 @@ swap_pager_putpages(object, m, count, sync, rtvals)
* normal async completion, which frees everything up.
*/
+ mtx_unlock(&Giant);
+ mtx_lock(&vm_mtx);
swp_pager_async_iodone(bp);
splx(s);
@@ -1732,7 +1762,8 @@ swp_pager_hash(vm_object_t object, vm_pindex_t index)
*
* This routine must be called at splvm(), except when used to convert
* an OBJT_DEFAULT object into an OBJT_SWAP object.
-
+ *
+ * Requires vm_mtx.
*/
static void
@@ -1744,6 +1775,7 @@ swp_pager_meta_build(
struct swblock *swap;
struct swblock **pswap;
+ mtx_assert(&vm_mtx, MA_OWNED);
/*
* Convert default object to swap object if necessary
*/
@@ -1830,12 +1862,16 @@ retry:
* out. This routine does *NOT* operate on swap metadata associated
* with resident pages.
*
+ * mv_mtx must be held
* This routine must be called at splvm()
*/
static void
swp_pager_meta_free(vm_object_t object, vm_pindex_t index, daddr_t count)
{
+
+ mtx_assert(&vm_mtx, MA_OWNED);
+
if (object->type != OBJT_SWAP)
return;
@@ -1875,6 +1911,7 @@ swp_pager_meta_free(vm_object_t object, vm_pindex_t index, daddr_t count)
* an object.
*
* This routine must be called at splvm()
+ * Requires vm_mtx.
*/
static void
@@ -1882,6 +1919,8 @@ swp_pager_meta_free_all(vm_object_t object)
{
daddr_t index = 0;
+ mtx_assert(&vm_mtx, MA_OWNED);
+
if (object->type != OBJT_SWAP)
return;
@@ -1930,6 +1969,7 @@ swp_pager_meta_free_all(vm_object_t object)
* busy page.
*
* This routine must be called at splvm().
+ * Requires vm_mtx.
*
* SWM_FREE remove and free swap block from metadata
* SWM_POP remove from meta data but do not free.. pop it out
@@ -2032,18 +2072,24 @@ vm_pager_chain_iodone(struct buf *nbp)
* Obtain a physical buffer and chain it to its parent buffer. When
* I/O completes, the parent buffer will be B_SIGNAL'd. Errors are
* automatically propagated to the parent
+ *
+ * vm_mtx can't be held
*/
struct buf *
getchainbuf(struct bio *bp, struct vnode *vp, int flags)
{
- struct buf *nbp = getpbuf(NULL);
- u_int *count = (u_int *)&(bp->bio_caller1);
+ struct buf *nbp;
+ u_int *count;
+
+ mtx_assert(&vm_mtx, MA_NOTOWNED);
+ nbp = getpbuf(NULL);
+ count = (u_int *)&(bp->bio_caller1);
nbp->b_caller1 = bp;
++(*count);
- if (*count > 4)
+ if (*count > 4)
waitchainbuf(bp, 4, 0);
nbp->b_iocmd = bp->bio_cmd;
@@ -2063,6 +2109,9 @@ getchainbuf(struct bio *bp, struct vnode *vp, int flags)
void
flushchainbuf(struct buf *nbp)
{
+
+ mtx_unlock(&vm_mtx);
+ mtx_lock(&Giant);
if (nbp->b_bcount) {
nbp->b_bufsize = nbp->b_bcount;
if (nbp->b_iocmd == BIO_WRITE)
@@ -2072,14 +2121,19 @@ flushchainbuf(struct buf *nbp)
} else {
bufdone(nbp);
}
+ mtx_unlock(&Giant);
+ mtx_lock(&vm_mtx);
}
-void
+static void
waitchainbuf(struct bio *bp, int limit, int done)
{
int s;
- u_int *count = (u_int *)&(bp->bio_caller1);
+ u_int *count;
+ mtx_assert(&vm_mtx, MA_NOTOWNED);
+ mtx_lock(&Giant);
+ count = (u_int *)&(bp->bio_caller1);
s = splbio();
while (*count > limit) {
bp->bio_flags |= BIO_FLAG1;
@@ -2092,6 +2146,7 @@ waitchainbuf(struct bio *bp, int limit, int done)
}
biodone(bp);
}
+ mtx_unlock(&Giant);
splx(s);
}
OpenPOWER on IntegriCloud