phys_pager.c revision 118466
151973Smsmith/*
251973Smsmith * Copyright (c) 2000 Peter Wemm
351973Smsmith *
451973Smsmith * Redistribution and use in source and binary forms, with or without
551973Smsmith * modification, are permitted provided that the following conditions
651973Smsmith * are met:
751973Smsmith * 1. Redistributions of source code must retain the above copyright
851973Smsmith *    notice, this list of conditions and the following disclaimer.
951973Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1051973Smsmith *    notice, this list of conditions and the following disclaimer in the
1151973Smsmith *    documentation and/or other materials provided with the distribution.
1251973Smsmith *
1351973Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1451973Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1551973Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1651973Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
1751973Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1851973Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1951973Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2051973Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2151973Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2251973Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2351973Smsmith * SUCH DAMAGE.
2451973Smsmith */
2551973Smsmith
2651973Smsmith#include <sys/cdefs.h>
2751973Smsmith__FBSDID("$FreeBSD: head/sys/vm/phys_pager.c 118466 2003-08-05 06:51:26Z phk $");
2851973Smsmith
2951973Smsmith#include <sys/param.h>
3058188Smsmith#include <sys/systm.h>
3158188Smsmith#include <sys/linker_set.h>
3258188Smsmith#include <sys/conf.h>
3358188Smsmith#include <sys/kernel.h>
3458188Smsmith#include <sys/lock.h>
3558188Smsmith#include <sys/proc.h>
3687599Sobrien#include <sys/mutex.h>
3787599Sobrien#include <sys/mman.h>
3858188Smsmith#include <sys/sysctl.h>
3958188Smsmith
4058188Smsmith#include <vm/vm.h>
4158188Smsmith#include <vm/vm_object.h>
4258188Smsmith#include <vm/vm_page.h>
4358188Smsmith#include <vm/vm_pager.h>
4460074Smsmith
4560074Smsmith/* prevent concurrant creation races */
4660074Smsmithstatic int phys_pager_alloc_lock;
4760074Smsmith/* list of device pager objects */
4860074Smsmithstatic struct pagerlst phys_pager_object_list;
4951973Smsmith/* protect access to phys_pager_object_list */
50238997Sdelphijstatic struct mtx phys_pager_mtx;
5160074Smsmith
5260074Smsmithstatic void
5351973Smsmithphys_pager_init(void)
5451973Smsmith{
5558188Smsmith
5651973Smsmith	TAILQ_INIT(&phys_pager_object_list);
5751973Smsmith	mtx_init(&phys_pager_mtx, "phys_pager list", NULL, MTX_DEF);
5851973Smsmith}
5951973Smsmith
6051973Smsmith/*
6151973Smsmith * MPSAFE
6251973Smsmith */
6351973Smsmithstatic vm_object_t
6451973Smsmithphys_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot,
6551973Smsmith		 vm_ooffset_t foff)
6651973Smsmith{
6751973Smsmith	vm_object_t object;
6851973Smsmith
6951973Smsmith	/*
7051973Smsmith	 * Offset should be page aligned.
7151973Smsmith	 */
7251973Smsmith	if (foff & PAGE_MASK)
7351973Smsmith		return (NULL);
7451973Smsmith
7551973Smsmith	size = round_page(size);
7651973Smsmith
7751973Smsmith	if (handle != NULL) {
7851973Smsmith		mtx_lock(&Giant);
7951973Smsmith		/*
8051973Smsmith		 * Lock to prevent object creation race condition.
8160938Sjake		 */
8251973Smsmith		while (phys_pager_alloc_lock) {
8351973Smsmith			phys_pager_alloc_lock = -1;
8451973Smsmith			tsleep(&phys_pager_alloc_lock, PVM, "swpalc", 0);
8551973Smsmith		}
8654419Smsmith		phys_pager_alloc_lock = 1;
8751973Smsmith
8851973Smsmith		/*
8951973Smsmith		 * Look up pager, creating as necessary.
9051973Smsmith		 */
9151973Smsmith		object = vm_pager_object_lookup(&phys_pager_object_list, handle);
9251973Smsmith		if (object == NULL) {
9351973Smsmith			/*
9451973Smsmith			 * Allocate object and associate it with the pager.
9551973Smsmith			 */
9651973Smsmith			object = vm_object_allocate(OBJT_PHYS,
9751973Smsmith				OFF_TO_IDX(foff + size));
9851973Smsmith			object->handle = handle;
9951973Smsmith			mtx_lock(&phys_pager_mtx);
10051973Smsmith			TAILQ_INSERT_TAIL(&phys_pager_object_list, object,
10151973Smsmith			    pager_object_list);
102119665Sscottl			mtx_unlock(&phys_pager_mtx);
10351973Smsmith		} else {
10451973Smsmith			/*
10551973Smsmith			 * Gain a reference to the object.
10651973Smsmith			 */
10751973Smsmith			vm_object_reference(object);
10851973Smsmith			if (OFF_TO_IDX(foff + size) > object->size)
10951973Smsmith				object->size = OFF_TO_IDX(foff + size);
11051973Smsmith		}
11151973Smsmith		if (phys_pager_alloc_lock == -1)
112130585Sphk			wakeup(&phys_pager_alloc_lock);
11351973Smsmith		phys_pager_alloc_lock = 0;
11469292Smdodd		mtx_unlock(&Giant);
11569292Smdodd	} else {
11651973Smsmith		object = vm_object_allocate(OBJT_PHYS,
11751973Smsmith			OFF_TO_IDX(foff + size));
11851973Smsmith	}
11951973Smsmith
12051973Smsmith	return (object);
12151973Smsmith}
12251973Smsmith
12351973Smsmith/*
12451973Smsmith * MPSAFE
12551973Smsmith */
12651973Smsmithstatic void
12751973Smsmithphys_pager_dealloc(vm_object_t object)
12854979Smsmith{
12951973Smsmith
13051973Smsmith	if (object->handle != NULL) {
13151973Smsmith		mtx_lock(&phys_pager_mtx);
13251973Smsmith		TAILQ_REMOVE(&phys_pager_object_list, object, pager_object_list);
13360938Sjake		mtx_unlock(&phys_pager_mtx);
13460938Sjake	}
13551973Smsmith}
13651973Smsmith
13751973Smsmithstatic int
138240963Sjhbphys_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage)
13951973Smsmith{
14051973Smsmith	int i, s;
14151973Smsmith
14251973Smsmith	s = splvm();
14351973Smsmith	vm_page_lock_queues();
14451973Smsmith	/*
14551973Smsmith	 * Fill as many pages as vm_fault has allocated for us.
14651973Smsmith	 */
14751973Smsmith	for (i = 0; i < count; i++) {
14851973Smsmith		if ((m[i]->flags & PG_ZERO) == 0) {
14951973Smsmith			vm_page_unlock_queues();
150240608Sjhb			pmap_zero_page(m[i]);
151240608Sjhb			vm_page_lock_queues();
152240608Sjhb		}
153240608Sjhb		vm_page_flag_set(m[i], PG_ZERO);
15451973Smsmith		/* Switch off pv_entries */
15559136Smsmith		vm_page_unmanage(m[i]);
15654979Smsmith		m[i]->valid = VM_PAGE_BITS_ALL;
15759136Smsmith		m[i]->dirty = 0;
15859136Smsmith		/* The requested page must remain busy, the others not. */
15959136Smsmith		if (reqpage != i) {
16059136Smsmith			vm_page_flag_clear(m[i], PG_BUSY);
16159136Smsmith			m[i]->busy = 0;
16251973Smsmith		}
16351973Smsmith	}
16458188Smsmith	vm_page_unlock_queues();
16558188Smsmith	splx(s);
16659447Smsmith
16754419Smsmith	return (VM_PAGER_OK);
16851973Smsmith}
16951973Smsmith
17058188Smsmithstatic void
17151973Smsmithphys_pager_putpages(vm_object_t object, vm_page_t *m, int count, boolean_t sync,
17251973Smsmith		    int *rtvals)
17351973Smsmith{
17451973Smsmith
17551973Smsmith	panic("phys_pager_putpage called");
17651973Smsmith}
177240608Sjhb
17851973Smsmith/*
17951973Smsmith * Implement a pretty aggressive clustered getpages strategy.  Hint that
18051973Smsmith * everything in an entire 4MB window should be prefaulted at once.
18151973Smsmith *
182240608Sjhb * XXX 4MB (1024 slots per page table page) is convenient for x86,
183240608Sjhb * but may not be for other arches.
184240608Sjhb */
185240608Sjhb#ifndef PHYSCLUSTER
186240608Sjhb#define PHYSCLUSTER 1024
187240608Sjhb#endif
18854419Smsmithstatic boolean_t
18954419Smsmithphys_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before,
19051973Smsmith		   int *after)
19151973Smsmith{
19251973Smsmith	vm_pindex_t base, end;
19351973Smsmith
19451973Smsmith	base = pindex & (~(PHYSCLUSTER - 1));
19551973Smsmith	end = base + (PHYSCLUSTER - 1);
19651973Smsmith	if (before != NULL)
19751973Smsmith		*before = pindex - base;
19851973Smsmith	if (after != NULL)
19951973Smsmith		*after = end - pindex;
20051973Smsmith	return (TRUE);
20151973Smsmith}
20251973Smsmith
20351973Smsmithstruct pagerops physpagerops = {
20451973Smsmith	.pgo_init =	phys_pager_init,
20559136Smsmith	.pgo_alloc =	phys_pager_alloc,
20651973Smsmith	.pgo_dealloc = 	phys_pager_dealloc,
20751973Smsmith	.pgo_getpages =	phys_pager_getpages,
20851973Smsmith	.pgo_putpages =	phys_pager_putpages,
20951973Smsmith	.pgo_haspage =	phys_pager_haspage,
21051973Smsmith};
21151973Smsmith