phys_pager.c revision 98605
1161748Scperciva/*
2161748Scperciva * Copyright (c) 2000 Peter Wemm
3161748Scperciva *
4161748Scperciva * Redistribution and use in source and binary forms, with or without
5161748Scperciva * modification, are permitted provided that the following conditions
6161748Scperciva * are met:
7161748Scperciva * 1. Redistributions of source code must retain the above copyright
8161748Scperciva *    notice, this list of conditions and the following disclaimer.
9161748Scperciva * 2. Redistributions in binary form must reproduce the above copyright
10161748Scperciva *    notice, this list of conditions and the following disclaimer in the
11161748Scperciva *    documentation and/or other materials provided with the distribution.
12161748Scperciva *
13161748Scperciva * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
14161748Scperciva * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15161748Scperciva * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16161748Scperciva * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
17161748Scperciva * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18161748Scperciva * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19161748Scperciva * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20161748Scperciva * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21161748Scperciva * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22161748Scperciva * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23161748Scperciva * SUCH DAMAGE.
24161748Scperciva *
25161748Scperciva * $FreeBSD: head/sys/vm/phys_pager.c 98605 2002-06-22 07:54:42Z alc $
26161748Scperciva */
27161748Scperciva
28161748Scperciva#include <sys/param.h>
29161748Scperciva#include <sys/systm.h>
30161748Scperciva#include <sys/linker_set.h>
31161748Scperciva#include <sys/conf.h>
32161748Scperciva#include <sys/kernel.h>
33161748Scperciva#include <sys/lock.h>
34161748Scperciva#include <sys/proc.h>
35161748Scperciva#include <sys/mutex.h>
36161748Scperciva#include <sys/mman.h>
37161748Scperciva#include <sys/sysctl.h>
38161748Scperciva
39161748Scperciva#include <vm/vm.h>
40161748Scperciva#include <vm/vm_object.h>
41161748Scperciva#include <vm/vm_page.h>
42161748Scperciva#include <vm/vm_pager.h>
43161748Scperciva
44161748Scperciva/* prevent concurrant creation races */
45161748Scpercivastatic int phys_pager_alloc_lock;
46161748Scperciva/* list of device pager objects */
47161748Scpercivastatic struct pagerlst phys_pager_object_list;
48161748Scperciva/* protect access to phys_pager_object_list */
49161748Scpercivastatic struct mtx phys_pager_mtx;
50161748Scperciva
51161748Scpercivastatic void
52161748Scpercivaphys_pager_init(void)
53161748Scperciva{
54161748Scperciva
55161748Scperciva	TAILQ_INIT(&phys_pager_object_list);
56161748Scperciva	mtx_init(&phys_pager_mtx, "phys_pager list", NULL, MTX_DEF);
57161748Scperciva}
58161748Scperciva
59161748Scperciva/*
60161748Scperciva * MPSAFE
61161748Scperciva */
62161748Scpercivastatic vm_object_t
63161748Scpercivaphys_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot,
64161748Scperciva		 vm_ooffset_t foff)
65161748Scperciva{
66161748Scperciva	vm_object_t object;
67161748Scperciva
68161748Scperciva	/*
69161748Scperciva	 * Offset should be page aligned.
70161748Scperciva	 */
71161748Scperciva	if (foff & PAGE_MASK)
72161748Scperciva		return (NULL);
73161748Scperciva
74161748Scperciva	size = round_page(size);
75161748Scperciva
76161748Scperciva	if (handle != NULL) {
77161748Scperciva		mtx_lock(&Giant);
78161748Scperciva		/*
79161748Scperciva		 * Lock to prevent object creation race condition.
80161748Scperciva		 */
81161748Scperciva		while (phys_pager_alloc_lock) {
82161748Scperciva			phys_pager_alloc_lock = -1;
83161748Scperciva			tsleep(&phys_pager_alloc_lock, PVM, "swpalc", 0);
84161748Scperciva		}
85161748Scperciva		phys_pager_alloc_lock = 1;
86161748Scperciva
87161748Scperciva		/*
88161748Scperciva		 * Look up pager, creating as necessary.
89161748Scperciva		 */
90161748Scperciva		object = vm_pager_object_lookup(&phys_pager_object_list, handle);
91161748Scperciva		if (object == NULL) {
92161748Scperciva			/*
93161748Scperciva			 * Allocate object and associate it with the pager.
94161748Scperciva			 */
95161748Scperciva			object = vm_object_allocate(OBJT_PHYS,
96161748Scperciva				OFF_TO_IDX(foff + size));
97161748Scperciva			object->handle = handle;
98161748Scperciva			mtx_lock(&phys_pager_mtx);
99161748Scperciva			TAILQ_INSERT_TAIL(&phys_pager_object_list, object,
100161748Scperciva			    pager_object_list);
101161748Scperciva			mtx_unlock(&phys_pager_mtx);
102161748Scperciva		} else {
103161748Scperciva			/*
104161748Scperciva			 * Gain a reference to the object.
105161748Scperciva			 */
106161748Scperciva			vm_object_reference(object);
107161748Scperciva			if (OFF_TO_IDX(foff + size) > object->size)
108161748Scperciva				object->size = OFF_TO_IDX(foff + size);
109161748Scperciva		}
110161748Scperciva		if (phys_pager_alloc_lock == -1)
111161748Scperciva			wakeup(&phys_pager_alloc_lock);
112161748Scperciva		phys_pager_alloc_lock = 0;
113161748Scperciva		mtx_unlock(&Giant);
114161748Scperciva	} else {
115161748Scperciva		object = vm_object_allocate(OBJT_PHYS,
116161748Scperciva			OFF_TO_IDX(foff + size));
117161748Scperciva	}
118161748Scperciva
119161748Scperciva	return (object);
120161748Scperciva}
121161748Scperciva
122161748Scperciva/*
123161748Scperciva * MPSAFE
124161748Scperciva */
125161748Scpercivastatic void
126161748Scpercivaphys_pager_dealloc(vm_object_t object)
127161748Scperciva{
128161748Scperciva
129161748Scperciva	if (object->handle != NULL) {
130161748Scperciva		mtx_lock(&phys_pager_mtx);
131161748Scperciva		TAILQ_REMOVE(&phys_pager_object_list, object, pager_object_list);
132161748Scperciva		mtx_unlock(&phys_pager_mtx);
133161748Scperciva	}
134161748Scperciva}
135161748Scperciva
136161748Scpercivastatic int
137161748Scpercivaphys_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage)
138161748Scperciva{
139161748Scperciva	int i, s;
140161748Scperciva
141161748Scperciva	s = splvm();
142161748Scperciva	/*
143161748Scperciva	 * Fill as many pages as vm_fault has allocated for us.
144161748Scperciva	 */
145161748Scperciva	for (i = 0; i < count; i++) {
146161748Scperciva		if ((m[i]->flags & PG_ZERO) == 0)
147161748Scperciva			vm_page_zero_fill(m[i]);
148161748Scperciva		vm_page_flag_set(m[i], PG_ZERO);
149161748Scperciva		/* Switch off pv_entries */
150161748Scperciva		vm_page_unmanage(m[i]);
151161748Scperciva		m[i]->valid = VM_PAGE_BITS_ALL;
152161748Scperciva		m[i]->dirty = 0;
153161748Scperciva		/* The requested page must remain busy, the others not. */
154161748Scperciva		if (reqpage != i) {
155161748Scperciva			vm_page_flag_clear(m[i], PG_BUSY);
156161748Scperciva			m[i]->busy = 0;
157161748Scperciva		}
158161748Scperciva	}
159161748Scperciva	splx(s);
160161748Scperciva
161161748Scperciva	return (VM_PAGER_OK);
162161748Scperciva}
163161748Scperciva
164161748Scpercivastatic void
165161748Scpercivaphys_pager_putpages(vm_object_t object, vm_page_t *m, int count, boolean_t sync,
166161748Scperciva		    int *rtvals)
167161748Scperciva{
168161748Scperciva
169161748Scperciva	panic("phys_pager_putpage called");
170161748Scperciva}
171161748Scperciva
172161748Scperciva/*
173161748Scperciva * Implement a pretty aggressive clustered getpages strategy.  Hint that
174161748Scperciva * everything in an entire 4MB window should be prefaulted at once.
175161748Scperciva *
176161748Scperciva * XXX 4MB (1024 slots per page table page) is convenient for x86,
177161748Scperciva * but may not be for other arches.
178161748Scperciva */
179161748Scperciva#ifndef PHYSCLUSTER
180161748Scperciva#define PHYSCLUSTER 1024
181161748Scperciva#endif
182161748Scpercivastatic boolean_t
183161748Scpercivaphys_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before,
184161748Scperciva		   int *after)
185161748Scperciva{
186161748Scperciva	vm_pindex_t base, end;
187161748Scperciva
188161748Scperciva	base = pindex & (~(PHYSCLUSTER - 1));
189161748Scperciva	end = base + (PHYSCLUSTER - 1);
190161748Scperciva	if (before != NULL)
191161748Scperciva		*before = pindex - base;
192161748Scperciva	if (after != NULL)
193161748Scperciva		*after = end - pindex;
194161748Scperciva	return (TRUE);
195161748Scperciva}
196161748Scperciva
197161748Scpercivastruct pagerops physpagerops = {
198161748Scperciva	phys_pager_init,
199161748Scperciva	phys_pager_alloc,
200161748Scperciva	phys_pager_dealloc,
201161748Scperciva	phys_pager_getpages,
202161748Scperciva	phys_pager_putpages,
203161748Scperciva	phys_pager_haspage,
204161748Scperciva	NULL
205161748Scperciva};
206161748Scperciva