xref: /freebsd/sys/vm/vm_pager.c (revision 1c7c3c6a869e5eb64a19fda327dbe9f37af584b2)
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
17df8bae1dSRodney W. Grimes  *    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  *
641c7c3c6aSMatthew Dillon  * $Id: vm_pager.c,v 1.40 1998/11/10 09:16:27 peter Exp $
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>
7516f62314SDavid Greenman #include <sys/buf.h>
7616f62314SDavid Greenman #include <sys/ucred.h>
77a1c995b6SPoul-Henning Kamp #include <sys/malloc.h>
78df8bae1dSRodney W. Grimes 
79df8bae1dSRodney W. Grimes #include <vm/vm.h>
80efeaf95aSDavid Greenman #include <vm/vm_param.h>
81efeaf95aSDavid Greenman #include <vm/vm_prot.h>
82efeaf95aSDavid Greenman #include <vm/vm_object.h>
83df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
8424a1cce3SDavid Greenman #include <vm/vm_pager.h>
85efeaf95aSDavid Greenman #include <vm/vm_extern.h>
86df8bae1dSRodney W. Grimes 
87a1c995b6SPoul-Henning Kamp MALLOC_DEFINE(M_VMPGDATA, "VM pgdata", "XXX: VM pager private data");
88a1c995b6SPoul-Henning Kamp 
8924a1cce3SDavid Greenman extern struct pagerops defaultpagerops;
90df8bae1dSRodney W. Grimes extern struct pagerops swappagerops;
91df8bae1dSRodney W. Grimes extern struct pagerops vnodepagerops;
92df8bae1dSRodney W. Grimes extern struct pagerops devicepagerops;
93df8bae1dSRodney W. Grimes 
941c7c3c6aSMatthew Dillon int cluster_pbuf_freecnt = -1;	/* unlimited to begin with */
951c7c3c6aSMatthew Dillon 
96bef608bdSJohn Dyson static int dead_pager_getpages __P((vm_object_t, vm_page_t *, int, int));
976cde7a16SDavid Greenman static vm_object_t dead_pager_alloc __P((void *, vm_ooffset_t, vm_prot_t,
98bef608bdSJohn Dyson 	vm_ooffset_t));
99bef608bdSJohn Dyson static int dead_pager_putpages __P((vm_object_t, vm_page_t *, int, int, int *));
100bef608bdSJohn Dyson static boolean_t dead_pager_haspage __P((vm_object_t, vm_pindex_t, int *, int *));
101bef608bdSJohn Dyson static void dead_pager_dealloc __P((vm_object_t));
102bef608bdSJohn Dyson 
103bef608bdSJohn Dyson int
104bef608bdSJohn Dyson dead_pager_getpages(obj, ma, count, req)
105bef608bdSJohn Dyson 	vm_object_t obj;
106bef608bdSJohn Dyson 	vm_page_t *ma;
107bef608bdSJohn Dyson 	int count;
108bef608bdSJohn Dyson 	int req;
109bef608bdSJohn Dyson {
110bef608bdSJohn Dyson 	return VM_PAGER_FAIL;
111bef608bdSJohn Dyson }
112bef608bdSJohn Dyson 
113bef608bdSJohn Dyson vm_object_t
114bef608bdSJohn Dyson dead_pager_alloc(handle, size, prot, off)
115bef608bdSJohn Dyson 	void *handle;
1166cde7a16SDavid Greenman 	vm_ooffset_t size;
117bef608bdSJohn Dyson 	vm_prot_t prot;
118bef608bdSJohn Dyson 	vm_ooffset_t off;
119bef608bdSJohn Dyson {
120bef608bdSJohn Dyson 	return NULL;
121bef608bdSJohn Dyson }
122bef608bdSJohn Dyson 
123bef608bdSJohn Dyson int
124bef608bdSJohn Dyson dead_pager_putpages(object, m, count, flags, rtvals)
125bef608bdSJohn Dyson 	vm_object_t object;
126bef608bdSJohn Dyson 	vm_page_t *m;
127bef608bdSJohn Dyson 	int count;
128bef608bdSJohn Dyson 	int flags;
129bef608bdSJohn Dyson 	int *rtvals;
130bef608bdSJohn Dyson {
131bef608bdSJohn Dyson 	int i;
132bef608bdSJohn Dyson 	for (i = 0; i < count; i++) {
133bef608bdSJohn Dyson 		rtvals[i] = VM_PAGER_AGAIN;
134bef608bdSJohn Dyson 	}
135bef608bdSJohn Dyson 	return VM_PAGER_AGAIN;
136bef608bdSJohn Dyson }
137bef608bdSJohn Dyson 
138bef608bdSJohn Dyson int
139bef608bdSJohn Dyson dead_pager_haspage(object, pindex, prev, next)
140bef608bdSJohn Dyson 	vm_object_t object;
141bef608bdSJohn Dyson 	vm_pindex_t pindex;
142bef608bdSJohn Dyson 	int *prev;
143bef608bdSJohn Dyson 	int *next;
144bef608bdSJohn Dyson {
145bef608bdSJohn Dyson 	if (prev)
146bef608bdSJohn Dyson 		*prev = 0;
147bef608bdSJohn Dyson 	if (next)
148bef608bdSJohn Dyson 		*next = 0;
149bef608bdSJohn Dyson 	return FALSE;
150bef608bdSJohn Dyson }
151bef608bdSJohn Dyson 
152bef608bdSJohn Dyson void
153bef608bdSJohn Dyson dead_pager_dealloc(object)
154bef608bdSJohn Dyson 	vm_object_t object;
155bef608bdSJohn Dyson {
156bef608bdSJohn Dyson 	return;
157bef608bdSJohn Dyson }
158bef608bdSJohn Dyson 
159bef608bdSJohn Dyson struct pagerops deadpagerops = {
160bef608bdSJohn Dyson 	NULL,
161bef608bdSJohn Dyson 	dead_pager_alloc,
162bef608bdSJohn Dyson 	dead_pager_dealloc,
163bef608bdSJohn Dyson 	dead_pager_getpages,
164bef608bdSJohn Dyson 	dead_pager_putpages,
165bef608bdSJohn Dyson 	dead_pager_haspage,
166bef608bdSJohn Dyson 	NULL
167bef608bdSJohn Dyson };
168bef608bdSJohn Dyson 
1691c7c3c6aSMatthew Dillon struct pagerops *pagertab[] = {
17024a1cce3SDavid Greenman 	&defaultpagerops,	/* OBJT_DEFAULT */
17124a1cce3SDavid Greenman 	&swappagerops,		/* OBJT_SWAP */
17224a1cce3SDavid Greenman 	&vnodepagerops,		/* OBJT_VNODE */
17324a1cce3SDavid Greenman 	&devicepagerops,	/* OBJT_DEVICE */
174bef608bdSJohn Dyson 	&deadpagerops		/* OBJT_DEAD */
175df8bae1dSRodney W. Grimes };
1761c7c3c6aSMatthew Dillon 
1771c7c3c6aSMatthew Dillon int npagers = sizeof(pagertab) / sizeof(pagertab[0]);
178df8bae1dSRodney W. Grimes 
179df8bae1dSRodney W. Grimes /*
180df8bae1dSRodney W. Grimes  * Kernel address space for mapping pages.
181df8bae1dSRodney W. Grimes  * Used by pagers where KVAs are needed for IO.
182df8bae1dSRodney W. Grimes  *
183df8bae1dSRodney W. Grimes  * XXX needs to be large enough to support the number of pending async
184df8bae1dSRodney W. Grimes  * cleaning requests (NPENDINGIO == 64) * the maximum swap cluster size
185df8bae1dSRodney W. Grimes  * (MAXPHYS == 64k) if you want to get the most efficiency.
186df8bae1dSRodney W. Grimes  */
18716f62314SDavid Greenman #define PAGER_MAP_SIZE	(8 * 1024 * 1024)
188df8bae1dSRodney W. Grimes 
18926f9a767SRodney W. Grimes int pager_map_size = PAGER_MAP_SIZE;
190df8bae1dSRodney W. Grimes vm_map_t pager_map;
191f708ef1bSPoul-Henning Kamp static int bswneeded;
192f708ef1bSPoul-Henning Kamp static vm_offset_t swapbkva;		/* swap buffers kva */
193df8bae1dSRodney W. Grimes 
194df8bae1dSRodney W. Grimes void
195df8bae1dSRodney W. Grimes vm_pager_init()
196df8bae1dSRodney W. Grimes {
197df8bae1dSRodney W. Grimes 	struct pagerops **pgops;
198df8bae1dSRodney W. Grimes 
199df8bae1dSRodney W. Grimes 	/*
200df8bae1dSRodney W. Grimes 	 * Initialize known pagers
201df8bae1dSRodney W. Grimes 	 */
202df8bae1dSRodney W. Grimes 	for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++)
20324a1cce3SDavid Greenman 		if (pgops && ((*pgops)->pgo_init != NULL))
204df8bae1dSRodney W. Grimes 			(*(*pgops)->pgo_init) ();
205df8bae1dSRodney W. Grimes }
206df8bae1dSRodney W. Grimes 
20716f62314SDavid Greenman void
20816f62314SDavid Greenman vm_pager_bufferinit()
20916f62314SDavid Greenman {
21016f62314SDavid Greenman 	struct buf *bp;
21116f62314SDavid Greenman 	int i;
2120d94caffSDavid Greenman 
21316f62314SDavid Greenman 	bp = swbuf;
21416f62314SDavid Greenman 	/*
21516f62314SDavid Greenman 	 * Now set up swap and physical I/O buffer headers.
21616f62314SDavid Greenman 	 */
21750ce7ff4SJohn Dyson 	for (i = 0; i < nswbuf; i++, bp++) {
21816f62314SDavid Greenman 		TAILQ_INSERT_HEAD(&bswlist, bp, b_freelist);
21916f62314SDavid Greenman 		bp->b_rcred = bp->b_wcred = NOCRED;
22040c8cfe5SPeter Wemm 		bp->b_xflags = 0;
22116f62314SDavid Greenman 	}
22216f62314SDavid Greenman 
2231c7c3c6aSMatthew Dillon 	cluster_pbuf_freecnt = nswbuf / 2;
2241c7c3c6aSMatthew Dillon 
22516f62314SDavid Greenman 	swapbkva = kmem_alloc_pageable(pager_map, nswbuf * MAXPHYS);
22616f62314SDavid Greenman 	if (!swapbkva)
22716f62314SDavid Greenman 		panic("Not enough pager_map VM space for physical buffers");
22816f62314SDavid Greenman }
22916f62314SDavid Greenman 
230df8bae1dSRodney W. Grimes /*
231df8bae1dSRodney W. Grimes  * Allocate an instance of a pager of the given type.
232df8bae1dSRodney W. Grimes  * Size, protection and offset parameters are passed in for pagers that
233df8bae1dSRodney W. Grimes  * need to perform page-level validation (e.g. the device pager).
234df8bae1dSRodney W. Grimes  */
23524a1cce3SDavid Greenman vm_object_t
2366cde7a16SDavid Greenman vm_pager_allocate(objtype_t type, void *handle, vm_ooffset_t size, vm_prot_t prot,
237b9dcd593SBruce Evans 		  vm_ooffset_t off)
238df8bae1dSRodney W. Grimes {
239df8bae1dSRodney W. Grimes 	struct pagerops *ops;
240df8bae1dSRodney W. Grimes 
24124a1cce3SDavid Greenman 	ops = pagertab[type];
242df8bae1dSRodney W. Grimes 	if (ops)
243df8bae1dSRodney W. Grimes 		return ((*ops->pgo_alloc) (handle, size, prot, off));
244df8bae1dSRodney W. Grimes 	return (NULL);
245df8bae1dSRodney W. Grimes }
246df8bae1dSRodney W. Grimes 
247df8bae1dSRodney W. Grimes void
24824a1cce3SDavid Greenman vm_pager_deallocate(object)
24924a1cce3SDavid Greenman 	vm_object_t object;
250df8bae1dSRodney W. Grimes {
25124a1cce3SDavid Greenman 	(*pagertab[object->type]->pgo_dealloc) (object);
252df8bae1dSRodney W. Grimes }
253df8bae1dSRodney W. Grimes 
254df8bae1dSRodney W. Grimes /*
2551c7c3c6aSMatthew Dillon  * vm_pager_get_pages() - inline, see vm/vm_pager.h
2561c7c3c6aSMatthew Dillon  * vm_pager_put_pages() - inline, see vm/vm_pager.h
2571c7c3c6aSMatthew Dillon  * vm_pager_has_page() - inline, see vm/vm_pager.h
2581c7c3c6aSMatthew Dillon  * vm_pager_page_inserted() - inline, see vm/vm_pager.h
2591c7c3c6aSMatthew Dillon  * vm_pager_page_removed() - inline, see vm/vm_pager.h
2601c7c3c6aSMatthew Dillon  */
2611c7c3c6aSMatthew Dillon 
2621c7c3c6aSMatthew Dillon #if 0
2631c7c3c6aSMatthew Dillon /*
2641c7c3c6aSMatthew Dillon  *	vm_pager_sync:
2651c7c3c6aSMatthew Dillon  *
266df8bae1dSRodney W. Grimes  *	Called by pageout daemon before going back to sleep.
2671c7c3c6aSMatthew Dillon  *	Gives pagers a chance to clean up any completed async pageing
2681c7c3c6aSMatthew Dillon  *	operations.
269df8bae1dSRodney W. Grimes  */
270df8bae1dSRodney W. Grimes void
271df8bae1dSRodney W. Grimes vm_pager_sync()
272df8bae1dSRodney W. Grimes {
273df8bae1dSRodney W. Grimes 	struct pagerops **pgops;
274df8bae1dSRodney W. Grimes 
275df8bae1dSRodney W. Grimes 	for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++)
27624a1cce3SDavid Greenman 		if (pgops && ((*pgops)->pgo_sync != NULL))
27724a1cce3SDavid Greenman 			(*(*pgops)->pgo_sync) ();
278df8bae1dSRodney W. Grimes }
279df8bae1dSRodney W. Grimes 
2801c7c3c6aSMatthew Dillon #endif
2811c7c3c6aSMatthew Dillon 
282df8bae1dSRodney W. Grimes vm_offset_t
28326f9a767SRodney W. Grimes vm_pager_map_page(m)
284df8bae1dSRodney W. Grimes 	vm_page_t m;
28526f9a767SRodney W. Grimes {
28626f9a767SRodney W. Grimes 	vm_offset_t kva;
287df8bae1dSRodney W. Grimes 
28826f9a767SRodney W. Grimes 	kva = kmem_alloc_wait(pager_map, PAGE_SIZE);
289a481f200SDavid Greenman 	pmap_kenter(kva, VM_PAGE_TO_PHYS(m));
290df8bae1dSRodney W. Grimes 	return (kva);
291df8bae1dSRodney W. Grimes }
292df8bae1dSRodney W. Grimes 
293df8bae1dSRodney W. Grimes void
29426f9a767SRodney W. Grimes vm_pager_unmap_page(kva)
295df8bae1dSRodney W. Grimes 	vm_offset_t kva;
296df8bae1dSRodney W. Grimes {
297a481f200SDavid Greenman 	pmap_kremove(kva);
29826f9a767SRodney W. Grimes 	kmem_free_wakeup(pager_map, kva, PAGE_SIZE);
299df8bae1dSRodney W. Grimes }
300df8bae1dSRodney W. Grimes 
30124a1cce3SDavid Greenman vm_object_t
30224a1cce3SDavid Greenman vm_pager_object_lookup(pg_list, handle)
30324a1cce3SDavid Greenman 	register struct pagerlst *pg_list;
30424a1cce3SDavid Greenman 	void *handle;
305df8bae1dSRodney W. Grimes {
30624a1cce3SDavid Greenman 	register vm_object_t object;
307df8bae1dSRodney W. Grimes 
308b18bfc3dSJohn Dyson 	for (object = TAILQ_FIRST(pg_list); object != NULL; object = TAILQ_NEXT(object,pager_object_list))
30924a1cce3SDavid Greenman 		if (object->handle == handle)
31024a1cce3SDavid Greenman 			return (object);
311df8bae1dSRodney W. Grimes 	return (NULL);
312df8bae1dSRodney W. Grimes }
313df8bae1dSRodney W. Grimes 
314df8bae1dSRodney W. Grimes /*
31509e0c6ccSJohn Dyson  * initialize a physical buffer
31609e0c6ccSJohn Dyson  */
31709e0c6ccSJohn Dyson 
31809e0c6ccSJohn Dyson static void
31909e0c6ccSJohn Dyson initpbuf(struct buf *bp) {
32009e0c6ccSJohn Dyson 	bzero(bp, sizeof *bp);
32109e0c6ccSJohn Dyson 	bp->b_rcred = NOCRED;
32209e0c6ccSJohn Dyson 	bp->b_wcred = NOCRED;
32309e0c6ccSJohn Dyson 	bp->b_qindex = QUEUE_NONE;
32409e0c6ccSJohn Dyson 	bp->b_data = (caddr_t) (MAXPHYS * (bp - swbuf)) + swapbkva;
32509e0c6ccSJohn Dyson 	bp->b_kvabase = bp->b_data;
32609e0c6ccSJohn Dyson 	bp->b_kvasize = MAXPHYS;
32740c8cfe5SPeter Wemm 	bp->b_xflags = 0;
32809e0c6ccSJohn Dyson }
32909e0c6ccSJohn Dyson 
33009e0c6ccSJohn Dyson /*
33116f62314SDavid Greenman  * allocate a physical buffer
3321c7c3c6aSMatthew Dillon  *
3331c7c3c6aSMatthew Dillon  *	There are a limited number (nswbuf) of physical buffers.  We need
3341c7c3c6aSMatthew Dillon  *	to make sure that no single subsystem is able to hog all of them,
3351c7c3c6aSMatthew Dillon  *	so each subsystem implements a counter which is typically initialized
3361c7c3c6aSMatthew Dillon  *	to 1/2 nswbuf.  getpbuf() decrements this counter in allocation and
3371c7c3c6aSMatthew Dillon  *	increments it on release, and blocks if the counter hits zero.  A
3381c7c3c6aSMatthew Dillon  *	subsystem may initialize the counter to -1 to disable the feature,
3391c7c3c6aSMatthew Dillon  *	but it must still be sure to match up all uses of getpbuf() with
3401c7c3c6aSMatthew Dillon  *	relpbuf() using the same variable.
3411c7c3c6aSMatthew Dillon  *
3421c7c3c6aSMatthew Dillon  *	NOTE: pfreecnt can be NULL, but this 'feature' will be removed
3431c7c3c6aSMatthew Dillon  *	relatively soon when the rest of the subsystems get smart about it. XXX
34416f62314SDavid Greenman  */
34516f62314SDavid Greenman struct buf *
3461c7c3c6aSMatthew Dillon getpbuf(pfreecnt)
3471c7c3c6aSMatthew Dillon 	int *pfreecnt;
3480d94caffSDavid Greenman {
34916f62314SDavid Greenman 	int s;
35016f62314SDavid Greenman 	struct buf *bp;
35116f62314SDavid Greenman 
352e47ed70bSJohn Dyson 	s = splvm();
3531c7c3c6aSMatthew Dillon 
3541c7c3c6aSMatthew Dillon 	if (pfreecnt) {
3551c7c3c6aSMatthew Dillon 		while (*pfreecnt == 0) {
3561c7c3c6aSMatthew Dillon 			tsleep(pfreecnt, PVM, "wswbuf0", 0);
3571c7c3c6aSMatthew Dillon 		}
3581c7c3c6aSMatthew Dillon 	}
3591c7c3c6aSMatthew Dillon 
36016f62314SDavid Greenman 	/* get a bp from the swap buffer header pool */
361b18bfc3dSJohn Dyson 	while ((bp = TAILQ_FIRST(&bswlist)) == NULL) {
36216f62314SDavid Greenman 		bswneeded = 1;
3631c7c3c6aSMatthew Dillon 		tsleep(&bswneeded, PVM, "wswbuf1", 0);
36416f62314SDavid Greenman 	}
36516f62314SDavid Greenman 	TAILQ_REMOVE(&bswlist, bp, b_freelist);
3661c7c3c6aSMatthew Dillon 	if (pfreecnt)
3671c7c3c6aSMatthew Dillon 		--*pfreecnt;
36816f62314SDavid Greenman 	splx(s);
36916f62314SDavid Greenman 
37009e0c6ccSJohn Dyson 	initpbuf(bp);
37116f62314SDavid Greenman 	return bp;
37216f62314SDavid Greenman }
37316f62314SDavid Greenman 
37416f62314SDavid Greenman /*
3751c7c3c6aSMatthew Dillon  * allocate a physical buffer, if one is available.
3761c7c3c6aSMatthew Dillon  *
3771c7c3c6aSMatthew Dillon  *	Note that there is no NULL hack here - all subsystems using this
3781c7c3c6aSMatthew Dillon  *	call understand how to use pfreecnt.
37916f62314SDavid Greenman  */
38016f62314SDavid Greenman struct buf *
3811c7c3c6aSMatthew Dillon trypbuf(pfreecnt)
3821c7c3c6aSMatthew Dillon 	int *pfreecnt;
3830d94caffSDavid Greenman {
38416f62314SDavid Greenman 	int s;
38516f62314SDavid Greenman 	struct buf *bp;
38616f62314SDavid Greenman 
387e47ed70bSJohn Dyson 	s = splvm();
3881c7c3c6aSMatthew Dillon 	if (*pfreecnt == 0 || (bp = TAILQ_FIRST(&bswlist)) == NULL) {
38916f62314SDavid Greenman 		splx(s);
39016f62314SDavid Greenman 		return NULL;
39116f62314SDavid Greenman 	}
39216f62314SDavid Greenman 	TAILQ_REMOVE(&bswlist, bp, b_freelist);
3931c7c3c6aSMatthew Dillon 
3941c7c3c6aSMatthew Dillon 	--*pfreecnt;
3951c7c3c6aSMatthew Dillon 
39616f62314SDavid Greenman 	splx(s);
39716f62314SDavid Greenman 
39809e0c6ccSJohn Dyson 	initpbuf(bp);
39909e0c6ccSJohn Dyson 
40016f62314SDavid Greenman 	return bp;
40116f62314SDavid Greenman }
40216f62314SDavid Greenman 
40316f62314SDavid Greenman /*
40416f62314SDavid Greenman  * release a physical buffer
4051c7c3c6aSMatthew Dillon  *
4061c7c3c6aSMatthew Dillon  *	NOTE: pfreecnt can be NULL, but this 'feature' will be removed
4071c7c3c6aSMatthew Dillon  *	relatively soon when the rest of the subsystems get smart about it. XXX
40816f62314SDavid Greenman  */
40916f62314SDavid Greenman void
4101c7c3c6aSMatthew Dillon relpbuf(bp, pfreecnt)
41116f62314SDavid Greenman 	struct buf *bp;
4121c7c3c6aSMatthew Dillon 	int *pfreecnt;
41316f62314SDavid Greenman {
41416f62314SDavid Greenman 	int s;
41516f62314SDavid Greenman 
416e47ed70bSJohn Dyson 	s = splvm();
41716f62314SDavid Greenman 
41816f62314SDavid Greenman 	if (bp->b_rcred != NOCRED) {
41916f62314SDavid Greenman 		crfree(bp->b_rcred);
42016f62314SDavid Greenman 		bp->b_rcred = NOCRED;
42116f62314SDavid Greenman 	}
42216f62314SDavid Greenman 	if (bp->b_wcred != NOCRED) {
42316f62314SDavid Greenman 		crfree(bp->b_wcred);
42416f62314SDavid Greenman 		bp->b_wcred = NOCRED;
42516f62314SDavid Greenman 	}
4261c7c3c6aSMatthew Dillon 
42716f62314SDavid Greenman 	if (bp->b_vp)
4280d94caffSDavid Greenman 		pbrelvp(bp);
42916f62314SDavid Greenman 
43061854083SDavid Greenman 	if (bp->b_flags & B_WANTED)
43124a1cce3SDavid Greenman 		wakeup(bp);
43261854083SDavid Greenman 
43316f62314SDavid Greenman 	TAILQ_INSERT_HEAD(&bswlist, bp, b_freelist);
43416f62314SDavid Greenman 
43516f62314SDavid Greenman 	if (bswneeded) {
43616f62314SDavid Greenman 		bswneeded = 0;
43724a1cce3SDavid Greenman 		wakeup(&bswneeded);
43816f62314SDavid Greenman 	}
4391c7c3c6aSMatthew Dillon 	if (pfreecnt) {
4401c7c3c6aSMatthew Dillon 		if (++*pfreecnt == 1)
4411c7c3c6aSMatthew Dillon 			wakeup(pfreecnt);
4421c7c3c6aSMatthew Dillon 	}
44316f62314SDavid Greenman 	splx(s);
44416f62314SDavid Greenman }
445