xref: /freebsd/sys/vm/vm_pager.c (revision 2ac8b1608936d008605baed356c150d86e9470f8)
1df8bae1dSRodney W. Grimes /*
2df8bae1dSRodney W. Grimes  * Copyright (c) 1991, 1993
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
6df8bae1dSRodney W. Grimes  * The Mach Operating System project at Carnegie-Mellon University.
7df8bae1dSRodney W. Grimes  *
8df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
9df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
10df8bae1dSRodney W. Grimes  * are met:
11df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
12df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
13df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
14df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
15df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
16df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
175929bcfaSPhilippe Charnier  *    must display the following acknowledgement:
18df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
19df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
20df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
21df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
22df8bae1dSRodney W. Grimes  *    without specific prior written permission.
23df8bae1dSRodney W. Grimes  *
24df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
35df8bae1dSRodney W. Grimes  *
363c4dd356SDavid Greenman  *	from: @(#)vm_pager.c	8.6 (Berkeley) 1/12/94
37df8bae1dSRodney W. Grimes  *
38df8bae1dSRodney W. Grimes  *
39df8bae1dSRodney W. Grimes  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
40df8bae1dSRodney W. Grimes  * All rights reserved.
41df8bae1dSRodney W. Grimes  *
42df8bae1dSRodney W. Grimes  * Authors: Avadis Tevanian, Jr., Michael Wayne Young
43df8bae1dSRodney W. Grimes  *
44df8bae1dSRodney W. Grimes  * Permission to use, copy, modify and distribute this software and
45df8bae1dSRodney W. Grimes  * its documentation is hereby granted, provided that both the copyright
46df8bae1dSRodney W. Grimes  * notice and this permission notice appear in all copies of the
47df8bae1dSRodney W. Grimes  * software, derivative works or modified versions, and any portions
48df8bae1dSRodney W. Grimes  * thereof, and that both notices appear in supporting documentation.
49df8bae1dSRodney W. Grimes  *
50df8bae1dSRodney W. Grimes  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51df8bae1dSRodney W. Grimes  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
52df8bae1dSRodney W. Grimes  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53df8bae1dSRodney W. Grimes  *
54df8bae1dSRodney W. Grimes  * Carnegie Mellon requests users of this software to return to
55df8bae1dSRodney W. Grimes  *
56df8bae1dSRodney W. Grimes  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
57df8bae1dSRodney W. Grimes  *  School of Computer Science
58df8bae1dSRodney W. Grimes  *  Carnegie Mellon University
59df8bae1dSRodney W. Grimes  *  Pittsburgh PA 15213-3890
60df8bae1dSRodney W. Grimes  *
61df8bae1dSRodney W. Grimes  * any improvements or extensions that they make and grant Carnegie the
62df8bae1dSRodney W. Grimes  * rights to redistribute these changes.
633c4dd356SDavid Greenman  *
64c3aac50fSPeter Wemm  * $FreeBSD$
65df8bae1dSRodney W. Grimes  */
66df8bae1dSRodney W. Grimes 
67df8bae1dSRodney W. Grimes /*
68df8bae1dSRodney W. Grimes  *	Paging space routine stubs.  Emulates a matchmaker-like interface
69df8bae1dSRodney W. Grimes  *	for builtin pagers.
70df8bae1dSRodney W. Grimes  */
71df8bae1dSRodney W. Grimes 
72df8bae1dSRodney W. Grimes #include <sys/param.h>
73df8bae1dSRodney W. Grimes #include <sys/systm.h>
741c5bb3eaSPeter Wemm #include <sys/kernel.h>
75a5296b05SJulian Elischer #include <sys/vnode.h>
769626b608SPoul-Henning Kamp #include <sys/bio.h>
7716f62314SDavid Greenman #include <sys/buf.h>
7803b67a39SBruce Evans #include <sys/ucred.h>
79a1c995b6SPoul-Henning Kamp #include <sys/malloc.h>
80df8bae1dSRodney W. Grimes 
81df8bae1dSRodney W. Grimes #include <vm/vm.h>
82efeaf95aSDavid Greenman #include <vm/vm_param.h>
83efeaf95aSDavid Greenman #include <vm/vm_object.h>
84df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
8524a1cce3SDavid Greenman #include <vm/vm_pager.h>
86efeaf95aSDavid Greenman #include <vm/vm_extern.h>
87df8bae1dSRodney W. Grimes 
88a1c995b6SPoul-Henning Kamp MALLOC_DEFINE(M_VMPGDATA, "VM pgdata", "XXX: VM pager private data");
89a1c995b6SPoul-Henning Kamp 
9024a1cce3SDavid Greenman extern struct pagerops defaultpagerops;
91df8bae1dSRodney W. Grimes extern struct pagerops swappagerops;
92df8bae1dSRodney W. Grimes extern struct pagerops vnodepagerops;
93df8bae1dSRodney W. Grimes extern struct pagerops devicepagerops;
9424964514SPeter Wemm extern struct pagerops physpagerops;
95df8bae1dSRodney W. Grimes 
961c7c3c6aSMatthew Dillon int cluster_pbuf_freecnt = -1;	/* unlimited to begin with */
971c7c3c6aSMatthew Dillon 
9811caded3SAlfred Perlstein static int dead_pager_getpages(vm_object_t, vm_page_t *, int, int);
9911caded3SAlfred Perlstein static vm_object_t dead_pager_alloc(void *, vm_ooffset_t, vm_prot_t,
10011caded3SAlfred Perlstein 	vm_ooffset_t);
10111caded3SAlfred Perlstein static void dead_pager_putpages(vm_object_t, vm_page_t *, int, int, int *);
10211caded3SAlfred Perlstein static boolean_t dead_pager_haspage(vm_object_t, vm_pindex_t, int *, int *);
10311caded3SAlfred Perlstein static void dead_pager_dealloc(vm_object_t);
104bef608bdSJohn Dyson 
105e4542174SMatthew Dillon static int
106bef608bdSJohn Dyson dead_pager_getpages(obj, ma, count, req)
107bef608bdSJohn Dyson 	vm_object_t obj;
108bef608bdSJohn Dyson 	vm_page_t *ma;
109bef608bdSJohn Dyson 	int count;
110bef608bdSJohn Dyson 	int req;
111bef608bdSJohn Dyson {
112bef608bdSJohn Dyson 	return VM_PAGER_FAIL;
113bef608bdSJohn Dyson }
114bef608bdSJohn Dyson 
115e4542174SMatthew Dillon static vm_object_t
116bef608bdSJohn Dyson dead_pager_alloc(handle, size, prot, off)
117bef608bdSJohn Dyson 	void *handle;
1186cde7a16SDavid Greenman 	vm_ooffset_t size;
119bef608bdSJohn Dyson 	vm_prot_t prot;
120bef608bdSJohn Dyson 	vm_ooffset_t off;
121bef608bdSJohn Dyson {
122bef608bdSJohn Dyson 	return NULL;
123bef608bdSJohn Dyson }
124bef608bdSJohn Dyson 
125e4542174SMatthew Dillon static void
126bef608bdSJohn Dyson dead_pager_putpages(object, m, count, flags, rtvals)
127bef608bdSJohn Dyson 	vm_object_t object;
128bef608bdSJohn Dyson 	vm_page_t *m;
129bef608bdSJohn Dyson 	int count;
130bef608bdSJohn Dyson 	int flags;
131bef608bdSJohn Dyson 	int *rtvals;
132bef608bdSJohn Dyson {
133bef608bdSJohn Dyson 	int i;
134e4542174SMatthew Dillon 
135bef608bdSJohn Dyson 	for (i = 0; i < count; i++) {
136bef608bdSJohn Dyson 		rtvals[i] = VM_PAGER_AGAIN;
137bef608bdSJohn Dyson 	}
138bef608bdSJohn Dyson }
139bef608bdSJohn Dyson 
140e4542174SMatthew Dillon static int
141bef608bdSJohn Dyson dead_pager_haspage(object, pindex, prev, next)
142bef608bdSJohn Dyson 	vm_object_t object;
143bef608bdSJohn Dyson 	vm_pindex_t pindex;
144bef608bdSJohn Dyson 	int *prev;
145bef608bdSJohn Dyson 	int *next;
146bef608bdSJohn Dyson {
147bef608bdSJohn Dyson 	if (prev)
148bef608bdSJohn Dyson 		*prev = 0;
149bef608bdSJohn Dyson 	if (next)
150bef608bdSJohn Dyson 		*next = 0;
151bef608bdSJohn Dyson 	return FALSE;
152bef608bdSJohn Dyson }
153bef608bdSJohn Dyson 
154e4542174SMatthew Dillon static void
155bef608bdSJohn Dyson dead_pager_dealloc(object)
156bef608bdSJohn Dyson 	vm_object_t object;
157bef608bdSJohn Dyson {
158bef608bdSJohn Dyson 	return;
159bef608bdSJohn Dyson }
160bef608bdSJohn Dyson 
1610776e10cSEivind Eklund static struct pagerops deadpagerops = {
162bef608bdSJohn Dyson 	NULL,
163bef608bdSJohn Dyson 	dead_pager_alloc,
164bef608bdSJohn Dyson 	dead_pager_dealloc,
165bef608bdSJohn Dyson 	dead_pager_getpages,
166bef608bdSJohn Dyson 	dead_pager_putpages,
167bef608bdSJohn Dyson 	dead_pager_haspage,
168bef608bdSJohn Dyson 	NULL
169bef608bdSJohn Dyson };
170bef608bdSJohn Dyson 
1711c7c3c6aSMatthew Dillon struct pagerops *pagertab[] = {
17224a1cce3SDavid Greenman 	&defaultpagerops,	/* OBJT_DEFAULT */
17324a1cce3SDavid Greenman 	&swappagerops,		/* OBJT_SWAP */
17424a1cce3SDavid Greenman 	&vnodepagerops,		/* OBJT_VNODE */
17524a1cce3SDavid Greenman 	&devicepagerops,	/* OBJT_DEVICE */
17624964514SPeter Wemm 	&physpagerops,		/* OBJT_PHYS */
177bef608bdSJohn Dyson 	&deadpagerops		/* OBJT_DEAD */
178df8bae1dSRodney W. Grimes };
1791c7c3c6aSMatthew Dillon 
1801c7c3c6aSMatthew Dillon int npagers = sizeof(pagertab) / sizeof(pagertab[0]);
181df8bae1dSRodney W. Grimes 
182df8bae1dSRodney W. Grimes /*
183df8bae1dSRodney W. Grimes  * Kernel address space for mapping pages.
184df8bae1dSRodney W. Grimes  * Used by pagers where KVAs are needed for IO.
185df8bae1dSRodney W. Grimes  *
186df8bae1dSRodney W. Grimes  * XXX needs to be large enough to support the number of pending async
187df8bae1dSRodney W. Grimes  * cleaning requests (NPENDINGIO == 64) * the maximum swap cluster size
188df8bae1dSRodney W. Grimes  * (MAXPHYS == 64k) if you want to get the most efficiency.
189df8bae1dSRodney W. Grimes  */
19016f62314SDavid Greenman #define PAGER_MAP_SIZE	(8 * 1024 * 1024)
191df8bae1dSRodney W. Grimes 
19226f9a767SRodney W. Grimes int pager_map_size = PAGER_MAP_SIZE;
193df8bae1dSRodney W. Grimes vm_map_t pager_map;
194f708ef1bSPoul-Henning Kamp static int bswneeded;
195f708ef1bSPoul-Henning Kamp static vm_offset_t swapbkva;		/* swap buffers kva */
1962a758ebeSAlfred Perlstein struct mtx pbuf_mtx;
197f52bd684SEivind Eklund static TAILQ_HEAD(swqueue, buf) bswlist;
198df8bae1dSRodney W. Grimes 
199df8bae1dSRodney W. Grimes void
200df8bae1dSRodney W. Grimes vm_pager_init()
201df8bae1dSRodney W. Grimes {
202df8bae1dSRodney W. Grimes 	struct pagerops **pgops;
203df8bae1dSRodney W. Grimes 
204f52bd684SEivind Eklund 	TAILQ_INIT(&bswlist);
205df8bae1dSRodney W. Grimes 	/*
206df8bae1dSRodney W. Grimes 	 * Initialize known pagers
207df8bae1dSRodney W. Grimes 	 */
208df8bae1dSRodney W. Grimes 	for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++)
20924a1cce3SDavid Greenman 		if (pgops && ((*pgops)->pgo_init != NULL))
210df8bae1dSRodney W. Grimes 			(*(*pgops)->pgo_init) ();
211df8bae1dSRodney W. Grimes }
212df8bae1dSRodney W. Grimes 
21316f62314SDavid Greenman void
21416f62314SDavid Greenman vm_pager_bufferinit()
21516f62314SDavid Greenman {
21616f62314SDavid Greenman 	struct buf *bp;
21716f62314SDavid Greenman 	int i;
2180d94caffSDavid Greenman 
2196008862bSJohn Baldwin 	mtx_init(&pbuf_mtx, "pbuf mutex", NULL, MTX_DEF);
22016f62314SDavid Greenman 	bp = swbuf;
22116f62314SDavid Greenman 	/*
22216f62314SDavid Greenman 	 * Now set up swap and physical I/O buffer headers.
22316f62314SDavid Greenman 	 */
22450ce7ff4SJohn Dyson 	for (i = 0; i < nswbuf; i++, bp++) {
22516f62314SDavid Greenman 		TAILQ_INSERT_HEAD(&bswlist, bp, b_freelist);
22667812eacSKirk McKusick 		BUF_LOCKINIT(bp);
22767812eacSKirk McKusick 		LIST_INIT(&bp->b_dep);
22816f62314SDavid Greenman 		bp->b_rcred = bp->b_wcred = NOCRED;
22940c8cfe5SPeter Wemm 		bp->b_xflags = 0;
23016f62314SDavid Greenman 	}
23116f62314SDavid Greenman 
2321c7c3c6aSMatthew Dillon 	cluster_pbuf_freecnt = nswbuf / 2;
2331c7c3c6aSMatthew Dillon 
23416f62314SDavid Greenman 	swapbkva = kmem_alloc_pageable(pager_map, nswbuf * MAXPHYS);
23516f62314SDavid Greenman 	if (!swapbkva)
23616f62314SDavid Greenman 		panic("Not enough pager_map VM space for physical buffers");
23716f62314SDavid Greenman }
23816f62314SDavid Greenman 
239df8bae1dSRodney W. Grimes /*
240df8bae1dSRodney W. Grimes  * Allocate an instance of a pager of the given type.
241df8bae1dSRodney W. Grimes  * Size, protection and offset parameters are passed in for pagers that
242df8bae1dSRodney W. Grimes  * need to perform page-level validation (e.g. the device pager).
243df8bae1dSRodney W. Grimes  */
24424a1cce3SDavid Greenman vm_object_t
24523955314SAlfred Perlstein vm_pager_allocate(objtype_t type, void *handle, vm_ooffset_t size,
24623955314SAlfred Perlstein 		  vm_prot_t prot, vm_ooffset_t off)
247df8bae1dSRodney W. Grimes {
24823955314SAlfred Perlstein 	vm_object_t ret;
249df8bae1dSRodney W. Grimes 	struct pagerops *ops;
250df8bae1dSRodney W. Grimes 
25124a1cce3SDavid Greenman 	ops = pagertab[type];
252df8bae1dSRodney W. Grimes 	if (ops)
25323955314SAlfred Perlstein 		ret = (*ops->pgo_alloc) (handle, size, prot, off);
25423955314SAlfred Perlstein 	else
25523955314SAlfred Perlstein 		ret = NULL;
25623955314SAlfred Perlstein 	return (ret);
257df8bae1dSRodney W. Grimes }
258df8bae1dSRodney W. Grimes 
259df8bae1dSRodney W. Grimes void
26024a1cce3SDavid Greenman vm_pager_deallocate(object)
26124a1cce3SDavid Greenman 	vm_object_t object;
262df8bae1dSRodney W. Grimes {
26324a1cce3SDavid Greenman 	(*pagertab[object->type]->pgo_dealloc) (object);
264df8bae1dSRodney W. Grimes }
265df8bae1dSRodney W. Grimes 
266df8bae1dSRodney W. Grimes /*
267a5296b05SJulian Elischer  *      vm_pager_strategy:
268a5296b05SJulian Elischer  *
269a5296b05SJulian Elischer  *      called with no specific spl
270a5296b05SJulian Elischer  *      Execute strategy routine directly to pager.
271a5296b05SJulian Elischer  */
272a5296b05SJulian Elischer void
2730b441832SPoul-Henning Kamp vm_pager_strategy(vm_object_t object, struct bio *bp)
274a5296b05SJulian Elischer {
275a5296b05SJulian Elischer 	if (pagertab[object->type]->pgo_strategy) {
276a5296b05SJulian Elischer 		(*pagertab[object->type]->pgo_strategy)(object, bp);
277a5296b05SJulian Elischer 	} else {
2780b441832SPoul-Henning Kamp 		bp->bio_flags |= BIO_ERROR;
2790b441832SPoul-Henning Kamp 		bp->bio_error = ENXIO;
2800b441832SPoul-Henning Kamp 		biodone(bp);
281a5296b05SJulian Elischer 	}
282a5296b05SJulian Elischer }
283a5296b05SJulian Elischer 
284a5296b05SJulian Elischer /*
2851c7c3c6aSMatthew Dillon  * vm_pager_get_pages() - inline, see vm/vm_pager.h
2861c7c3c6aSMatthew Dillon  * vm_pager_put_pages() - inline, see vm/vm_pager.h
2871c7c3c6aSMatthew Dillon  * vm_pager_has_page() - inline, see vm/vm_pager.h
2881c7c3c6aSMatthew Dillon  * vm_pager_page_inserted() - inline, see vm/vm_pager.h
2891c7c3c6aSMatthew Dillon  * vm_pager_page_removed() - inline, see vm/vm_pager.h
2901c7c3c6aSMatthew Dillon  */
2911c7c3c6aSMatthew Dillon 
292df8bae1dSRodney W. Grimes vm_offset_t
29326f9a767SRodney W. Grimes vm_pager_map_page(m)
294df8bae1dSRodney W. Grimes 	vm_page_t m;
29526f9a767SRodney W. Grimes {
29626f9a767SRodney W. Grimes 	vm_offset_t kva;
297df8bae1dSRodney W. Grimes 
29826f9a767SRodney W. Grimes 	kva = kmem_alloc_wait(pager_map, PAGE_SIZE);
299ac59490bSJake Burkholder 	pmap_qenter(kva, &m, 1);
300df8bae1dSRodney W. Grimes 	return (kva);
301df8bae1dSRodney W. Grimes }
302df8bae1dSRodney W. Grimes 
303df8bae1dSRodney W. Grimes void
30426f9a767SRodney W. Grimes vm_pager_unmap_page(kva)
305df8bae1dSRodney W. Grimes 	vm_offset_t kva;
306df8bae1dSRodney W. Grimes {
307ac59490bSJake Burkholder 
308ac59490bSJake Burkholder 	pmap_qremove(kva, 1);
30926f9a767SRodney W. Grimes 	kmem_free_wakeup(pager_map, kva, PAGE_SIZE);
310df8bae1dSRodney W. Grimes }
311df8bae1dSRodney W. Grimes 
31224a1cce3SDavid Greenman vm_object_t
31324a1cce3SDavid Greenman vm_pager_object_lookup(pg_list, handle)
31454d92145SMatthew Dillon 	struct pagerlst *pg_list;
31524a1cce3SDavid Greenman 	void *handle;
316df8bae1dSRodney W. Grimes {
31754d92145SMatthew Dillon 	vm_object_t object;
318df8bae1dSRodney W. Grimes 
319fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(object, pg_list, pager_object_list)
32024a1cce3SDavid Greenman 		if (object->handle == handle)
32124a1cce3SDavid Greenman 			return (object);
322df8bae1dSRodney W. Grimes 	return (NULL);
323df8bae1dSRodney W. Grimes }
324df8bae1dSRodney W. Grimes 
325df8bae1dSRodney W. Grimes /*
32609e0c6ccSJohn Dyson  * initialize a physical buffer
32709e0c6ccSJohn Dyson  */
32809e0c6ccSJohn Dyson 
329f52bd684SEivind Eklund /*
330f52bd684SEivind Eklund  * XXX This probably belongs in vfs_bio.c
331f52bd684SEivind Eklund  */
33209e0c6ccSJohn Dyson static void
333e96c1fdcSPeter Wemm initpbuf(struct buf *bp)
334e96c1fdcSPeter Wemm {
33509e0c6ccSJohn Dyson 	bp->b_rcred = NOCRED;
33609e0c6ccSJohn Dyson 	bp->b_wcred = NOCRED;
337f52bd684SEivind Eklund 	bp->b_qindex = 0;	/* On no queue (QUEUE_NONE) */
33809e0c6ccSJohn Dyson 	bp->b_data = (caddr_t) (MAXPHYS * (bp - swbuf)) + swapbkva;
33909e0c6ccSJohn Dyson 	bp->b_kvabase = bp->b_data;
34009e0c6ccSJohn Dyson 	bp->b_kvasize = MAXPHYS;
34140c8cfe5SPeter Wemm 	bp->b_xflags = 0;
34267812eacSKirk McKusick 	bp->b_flags = 0;
343c244d2deSPoul-Henning Kamp 	bp->b_ioflags = 0;
34421144e3bSPoul-Henning Kamp 	bp->b_iodone = NULL;
34567812eacSKirk McKusick 	bp->b_error = 0;
346f84e29a0SPoul-Henning Kamp 	bp->b_magic = B_MAGIC_BIO;
347f84e29a0SPoul-Henning Kamp 	bp->b_op = &buf_ops_bio;
34817661e5aSJeff Roberson 	BUF_LOCK(bp, LK_EXCLUSIVE, NULL);
34909e0c6ccSJohn Dyson }
35009e0c6ccSJohn Dyson 
35109e0c6ccSJohn Dyson /*
35216f62314SDavid Greenman  * allocate a physical buffer
3531c7c3c6aSMatthew Dillon  *
3541c7c3c6aSMatthew Dillon  *	There are a limited number (nswbuf) of physical buffers.  We need
3551c7c3c6aSMatthew Dillon  *	to make sure that no single subsystem is able to hog all of them,
3561c7c3c6aSMatthew Dillon  *	so each subsystem implements a counter which is typically initialized
3571c7c3c6aSMatthew Dillon  *	to 1/2 nswbuf.  getpbuf() decrements this counter in allocation and
3581c7c3c6aSMatthew Dillon  *	increments it on release, and blocks if the counter hits zero.  A
3591c7c3c6aSMatthew Dillon  *	subsystem may initialize the counter to -1 to disable the feature,
3601c7c3c6aSMatthew Dillon  *	but it must still be sure to match up all uses of getpbuf() with
3611c7c3c6aSMatthew Dillon  *	relpbuf() using the same variable.
3621c7c3c6aSMatthew Dillon  *
3631c7c3c6aSMatthew Dillon  *	NOTE: pfreecnt can be NULL, but this 'feature' will be removed
3641c7c3c6aSMatthew Dillon  *	relatively soon when the rest of the subsystems get smart about it. XXX
36516f62314SDavid Greenman  */
36616f62314SDavid Greenman struct buf *
3671c7c3c6aSMatthew Dillon getpbuf(pfreecnt)
3681c7c3c6aSMatthew Dillon 	int *pfreecnt;
3690d94caffSDavid Greenman {
37016f62314SDavid Greenman 	int s;
37116f62314SDavid Greenman 	struct buf *bp;
37216f62314SDavid Greenman 
373e47ed70bSJohn Dyson 	s = splvm();
3742a758ebeSAlfred Perlstein 	mtx_lock(&pbuf_mtx);
3751c7c3c6aSMatthew Dillon 
376652fcae0SStephen McKay 	for (;;) {
3771c7c3c6aSMatthew Dillon 		if (pfreecnt) {
3781c7c3c6aSMatthew Dillon 			while (*pfreecnt == 0) {
3792a758ebeSAlfred Perlstein 				msleep(pfreecnt, &pbuf_mtx, PVM, "wswbuf0", 0);
3801c7c3c6aSMatthew Dillon 			}
3811c7c3c6aSMatthew Dillon 		}
3821c7c3c6aSMatthew Dillon 
38316f62314SDavid Greenman 		/* get a bp from the swap buffer header pool */
384652fcae0SStephen McKay 		if ((bp = TAILQ_FIRST(&bswlist)) != NULL)
385652fcae0SStephen McKay 			break;
386652fcae0SStephen McKay 
38716f62314SDavid Greenman 		bswneeded = 1;
3882a758ebeSAlfred Perlstein 		msleep(&bswneeded, &pbuf_mtx, PVM, "wswbuf1", 0);
389652fcae0SStephen McKay 		/* loop in case someone else grabbed one */
39016f62314SDavid Greenman 	}
39116f62314SDavid Greenman 	TAILQ_REMOVE(&bswlist, bp, b_freelist);
3921c7c3c6aSMatthew Dillon 	if (pfreecnt)
3931c7c3c6aSMatthew Dillon 		--*pfreecnt;
3942a758ebeSAlfred Perlstein 	mtx_unlock(&pbuf_mtx);
39516f62314SDavid Greenman 	splx(s);
39616f62314SDavid Greenman 
39709e0c6ccSJohn Dyson 	initpbuf(bp);
39816f62314SDavid Greenman 	return bp;
39916f62314SDavid Greenman }
40016f62314SDavid Greenman 
40116f62314SDavid Greenman /*
4021c7c3c6aSMatthew Dillon  * allocate a physical buffer, if one is available.
4031c7c3c6aSMatthew Dillon  *
4041c7c3c6aSMatthew Dillon  *	Note that there is no NULL hack here - all subsystems using this
4051c7c3c6aSMatthew Dillon  *	call understand how to use pfreecnt.
40616f62314SDavid Greenman  */
40716f62314SDavid Greenman struct buf *
4081c7c3c6aSMatthew Dillon trypbuf(pfreecnt)
4091c7c3c6aSMatthew Dillon 	int *pfreecnt;
4100d94caffSDavid Greenman {
41116f62314SDavid Greenman 	int s;
41216f62314SDavid Greenman 	struct buf *bp;
41316f62314SDavid Greenman 
414e47ed70bSJohn Dyson 	s = splvm();
4152a758ebeSAlfred Perlstein 	mtx_lock(&pbuf_mtx);
4161c7c3c6aSMatthew Dillon 	if (*pfreecnt == 0 || (bp = TAILQ_FIRST(&bswlist)) == NULL) {
4172a758ebeSAlfred Perlstein 		mtx_unlock(&pbuf_mtx);
41816f62314SDavid Greenman 		splx(s);
41916f62314SDavid Greenman 		return NULL;
42016f62314SDavid Greenman 	}
42116f62314SDavid Greenman 	TAILQ_REMOVE(&bswlist, bp, b_freelist);
4221c7c3c6aSMatthew Dillon 
4231c7c3c6aSMatthew Dillon 	--*pfreecnt;
4241c7c3c6aSMatthew Dillon 
4252a758ebeSAlfred Perlstein 	mtx_unlock(&pbuf_mtx);
42616f62314SDavid Greenman 	splx(s);
42716f62314SDavid Greenman 
42809e0c6ccSJohn Dyson 	initpbuf(bp);
42909e0c6ccSJohn Dyson 
43016f62314SDavid Greenman 	return bp;
43116f62314SDavid Greenman }
43216f62314SDavid Greenman 
43316f62314SDavid Greenman /*
43416f62314SDavid Greenman  * release a physical buffer
4351c7c3c6aSMatthew Dillon  *
4361c7c3c6aSMatthew Dillon  *	NOTE: pfreecnt can be NULL, but this 'feature' will be removed
4371c7c3c6aSMatthew Dillon  *	relatively soon when the rest of the subsystems get smart about it. XXX
43816f62314SDavid Greenman  */
43916f62314SDavid Greenman void
4401c7c3c6aSMatthew Dillon relpbuf(bp, pfreecnt)
44116f62314SDavid Greenman 	struct buf *bp;
4421c7c3c6aSMatthew Dillon 	int *pfreecnt;
44316f62314SDavid Greenman {
44416f62314SDavid Greenman 	int s;
44516f62314SDavid Greenman 
446e47ed70bSJohn Dyson 	s = splvm();
44716f62314SDavid Greenman 
44816f62314SDavid Greenman 	if (bp->b_rcred != NOCRED) {
44916f62314SDavid Greenman 		crfree(bp->b_rcred);
45016f62314SDavid Greenman 		bp->b_rcred = NOCRED;
45116f62314SDavid Greenman 	}
45216f62314SDavid Greenman 	if (bp->b_wcred != NOCRED) {
45316f62314SDavid Greenman 		crfree(bp->b_wcred);
45416f62314SDavid Greenman 		bp->b_wcred = NOCRED;
45516f62314SDavid Greenman 	}
4561c7c3c6aSMatthew Dillon 
45716f62314SDavid Greenman 	if (bp->b_vp)
4580d94caffSDavid Greenman 		pbrelvp(bp);
45916f62314SDavid Greenman 
46067812eacSKirk McKusick 	BUF_UNLOCK(bp);
46161854083SDavid Greenman 
4622ac8b160SAlan Cox 	mtx_lock(&pbuf_mtx);
46316f62314SDavid Greenman 	TAILQ_INSERT_HEAD(&bswlist, bp, b_freelist);
46416f62314SDavid Greenman 
46516f62314SDavid Greenman 	if (bswneeded) {
46616f62314SDavid Greenman 		bswneeded = 0;
46724a1cce3SDavid Greenman 		wakeup(&bswneeded);
46816f62314SDavid Greenman 	}
4691c7c3c6aSMatthew Dillon 	if (pfreecnt) {
4701c7c3c6aSMatthew Dillon 		if (++*pfreecnt == 1)
4711c7c3c6aSMatthew Dillon 			wakeup(pfreecnt);
4721c7c3c6aSMatthew Dillon 	}
4732a758ebeSAlfred Perlstein 	mtx_unlock(&pbuf_mtx);
47416f62314SDavid Greenman 	splx(s);
47516f62314SDavid Greenman }
476