xref: /freebsd/sys/vm/vm_pager.c (revision 013818111a1477055223a69d538ebcd1c23b955e)
160727d8bSWarner Losh /*-
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  * 4. Neither the name of the University nor the names of its contributors
17df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
18df8bae1dSRodney W. Grimes  *    without specific prior written permission.
19df8bae1dSRodney W. Grimes  *
20df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
31df8bae1dSRodney W. Grimes  *
323c4dd356SDavid Greenman  *	from: @(#)vm_pager.c	8.6 (Berkeley) 1/12/94
33df8bae1dSRodney W. Grimes  *
34df8bae1dSRodney W. Grimes  *
35df8bae1dSRodney W. Grimes  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
36df8bae1dSRodney W. Grimes  * All rights reserved.
37df8bae1dSRodney W. Grimes  *
38df8bae1dSRodney W. Grimes  * Authors: Avadis Tevanian, Jr., Michael Wayne Young
39df8bae1dSRodney W. Grimes  *
40df8bae1dSRodney W. Grimes  * Permission to use, copy, modify and distribute this software and
41df8bae1dSRodney W. Grimes  * its documentation is hereby granted, provided that both the copyright
42df8bae1dSRodney W. Grimes  * notice and this permission notice appear in all copies of the
43df8bae1dSRodney W. Grimes  * software, derivative works or modified versions, and any portions
44df8bae1dSRodney W. Grimes  * thereof, and that both notices appear in supporting documentation.
45df8bae1dSRodney W. Grimes  *
46df8bae1dSRodney W. Grimes  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
47df8bae1dSRodney W. Grimes  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
48df8bae1dSRodney W. Grimes  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
49df8bae1dSRodney W. Grimes  *
50df8bae1dSRodney W. Grimes  * Carnegie Mellon requests users of this software to return to
51df8bae1dSRodney W. Grimes  *
52df8bae1dSRodney W. Grimes  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
53df8bae1dSRodney W. Grimes  *  School of Computer Science
54df8bae1dSRodney W. Grimes  *  Carnegie Mellon University
55df8bae1dSRodney W. Grimes  *  Pittsburgh PA 15213-3890
56df8bae1dSRodney W. Grimes  *
57df8bae1dSRodney W. Grimes  * any improvements or extensions that they make and grant Carnegie the
58df8bae1dSRodney W. Grimes  * rights to redistribute these changes.
59df8bae1dSRodney W. Grimes  */
60df8bae1dSRodney W. Grimes 
61df8bae1dSRodney W. Grimes /*
62df8bae1dSRodney W. Grimes  *	Paging space routine stubs.  Emulates a matchmaker-like interface
63df8bae1dSRodney W. Grimes  *	for builtin pagers.
64df8bae1dSRodney W. Grimes  */
65df8bae1dSRodney W. Grimes 
66874651b1SDavid E. O'Brien #include <sys/cdefs.h>
67874651b1SDavid E. O'Brien __FBSDID("$FreeBSD$");
68874651b1SDavid E. O'Brien 
69df8bae1dSRodney W. Grimes #include <sys/param.h>
70df8bae1dSRodney W. Grimes #include <sys/systm.h>
711c5bb3eaSPeter Wemm #include <sys/kernel.h>
72a5296b05SJulian Elischer #include <sys/vnode.h>
739626b608SPoul-Henning Kamp #include <sys/bio.h>
7416f62314SDavid Greenman #include <sys/buf.h>
7503b67a39SBruce Evans #include <sys/ucred.h>
76a1c995b6SPoul-Henning Kamp #include <sys/malloc.h>
77df8bae1dSRodney W. Grimes 
78df8bae1dSRodney W. Grimes #include <vm/vm.h>
79efeaf95aSDavid Greenman #include <vm/vm_param.h>
80efeaf95aSDavid Greenman #include <vm/vm_object.h>
81df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
8224a1cce3SDavid Greenman #include <vm/vm_pager.h>
83efeaf95aSDavid Greenman #include <vm/vm_extern.h>
84df8bae1dSRodney W. Grimes 
855bb84bc8SRobert Watson MALLOC_DEFINE(M_VMPGDATA, "vm_pgdata", "XXX: VM pager private data");
86a1c995b6SPoul-Henning Kamp 
871c7c3c6aSMatthew Dillon int cluster_pbuf_freecnt = -1;	/* unlimited to begin with */
881c7c3c6aSMatthew Dillon 
8911caded3SAlfred Perlstein static int dead_pager_getpages(vm_object_t, vm_page_t *, int, int);
9011caded3SAlfred Perlstein static vm_object_t dead_pager_alloc(void *, vm_ooffset_t, vm_prot_t,
913364c323SKonstantin Belousov     vm_ooffset_t, struct ucred *);
9211caded3SAlfred Perlstein static void dead_pager_putpages(vm_object_t, vm_page_t *, int, int, int *);
9311caded3SAlfred Perlstein static boolean_t dead_pager_haspage(vm_object_t, vm_pindex_t, int *, int *);
9411caded3SAlfred Perlstein static void dead_pager_dealloc(vm_object_t);
95bef608bdSJohn Dyson 
96e4542174SMatthew Dillon static int
97bef608bdSJohn Dyson dead_pager_getpages(obj, ma, count, req)
98bef608bdSJohn Dyson 	vm_object_t obj;
99bef608bdSJohn Dyson 	vm_page_t *ma;
100bef608bdSJohn Dyson 	int count;
101bef608bdSJohn Dyson 	int req;
102bef608bdSJohn Dyson {
103bef608bdSJohn Dyson 	return VM_PAGER_FAIL;
104bef608bdSJohn Dyson }
105bef608bdSJohn Dyson 
106e4542174SMatthew Dillon static vm_object_t
107af83f5d7SRoman Divacky dead_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot,
1083364c323SKonstantin Belousov     vm_ooffset_t off, struct ucred *cred)
109bef608bdSJohn Dyson {
110bef608bdSJohn Dyson 	return NULL;
111bef608bdSJohn Dyson }
112bef608bdSJohn Dyson 
113e4542174SMatthew Dillon static void
114bef608bdSJohn Dyson dead_pager_putpages(object, m, count, flags, rtvals)
115bef608bdSJohn Dyson 	vm_object_t object;
116bef608bdSJohn Dyson 	vm_page_t *m;
117bef608bdSJohn Dyson 	int count;
118bef608bdSJohn Dyson 	int flags;
119bef608bdSJohn Dyson 	int *rtvals;
120bef608bdSJohn Dyson {
121bef608bdSJohn Dyson 	int i;
122e4542174SMatthew Dillon 
123bef608bdSJohn Dyson 	for (i = 0; i < count; i++) {
124bef608bdSJohn Dyson 		rtvals[i] = VM_PAGER_AGAIN;
125bef608bdSJohn Dyson 	}
126bef608bdSJohn Dyson }
127bef608bdSJohn Dyson 
128e4542174SMatthew Dillon static int
129bef608bdSJohn Dyson dead_pager_haspage(object, pindex, prev, next)
130bef608bdSJohn Dyson 	vm_object_t object;
131bef608bdSJohn Dyson 	vm_pindex_t pindex;
132bef608bdSJohn Dyson 	int *prev;
133bef608bdSJohn Dyson 	int *next;
134bef608bdSJohn Dyson {
135bef608bdSJohn Dyson 	if (prev)
136bef608bdSJohn Dyson 		*prev = 0;
137bef608bdSJohn Dyson 	if (next)
138bef608bdSJohn Dyson 		*next = 0;
139bef608bdSJohn Dyson 	return FALSE;
140bef608bdSJohn Dyson }
141bef608bdSJohn Dyson 
142e4542174SMatthew Dillon static void
143bef608bdSJohn Dyson dead_pager_dealloc(object)
144bef608bdSJohn Dyson 	vm_object_t object;
145bef608bdSJohn Dyson {
146bef608bdSJohn Dyson 	return;
147bef608bdSJohn Dyson }
148bef608bdSJohn Dyson 
1490776e10cSEivind Eklund static struct pagerops deadpagerops = {
1504e658600SPoul-Henning Kamp 	.pgo_alloc = 	dead_pager_alloc,
1514e658600SPoul-Henning Kamp 	.pgo_dealloc =	dead_pager_dealloc,
1524e658600SPoul-Henning Kamp 	.pgo_getpages =	dead_pager_getpages,
1534e658600SPoul-Henning Kamp 	.pgo_putpages =	dead_pager_putpages,
1544e658600SPoul-Henning Kamp 	.pgo_haspage =	dead_pager_haspage,
155bef608bdSJohn Dyson };
156bef608bdSJohn Dyson 
1571c7c3c6aSMatthew Dillon struct pagerops *pagertab[] = {
15824a1cce3SDavid Greenman 	&defaultpagerops,	/* OBJT_DEFAULT */
15924a1cce3SDavid Greenman 	&swappagerops,		/* OBJT_SWAP */
16024a1cce3SDavid Greenman 	&vnodepagerops,		/* OBJT_VNODE */
16124a1cce3SDavid Greenman 	&devicepagerops,	/* OBJT_DEVICE */
16224964514SPeter Wemm 	&physpagerops,		/* OBJT_PHYS */
16301381811SJohn Baldwin 	&deadpagerops,		/* OBJT_DEAD */
16401381811SJohn Baldwin 	&sgpagerops		/* OBJT_SG */
165df8bae1dSRodney W. Grimes };
1661c7c3c6aSMatthew Dillon 
167253de0a1SPoul-Henning Kamp static const int npagers = sizeof(pagertab) / sizeof(pagertab[0]);
168df8bae1dSRodney W. Grimes 
169df8bae1dSRodney W. Grimes /*
170df8bae1dSRodney W. Grimes  * Kernel address space for mapping pages.
171df8bae1dSRodney W. Grimes  * Used by pagers where KVAs are needed for IO.
172df8bae1dSRodney W. Grimes  *
173df8bae1dSRodney W. Grimes  * XXX needs to be large enough to support the number of pending async
174df8bae1dSRodney W. Grimes  * cleaning requests (NPENDINGIO == 64) * the maximum swap cluster size
175df8bae1dSRodney W. Grimes  * (MAXPHYS == 64k) if you want to get the most efficiency.
176df8bae1dSRodney W. Grimes  */
177df8bae1dSRodney W. Grimes vm_map_t pager_map;
178f708ef1bSPoul-Henning Kamp static int bswneeded;
179f708ef1bSPoul-Henning Kamp static vm_offset_t swapbkva;		/* swap buffers kva */
1802a758ebeSAlfred Perlstein struct mtx pbuf_mtx;
181f52bd684SEivind Eklund static TAILQ_HEAD(swqueue, buf) bswlist;
182df8bae1dSRodney W. Grimes 
183df8bae1dSRodney W. Grimes void
184df8bae1dSRodney W. Grimes vm_pager_init()
185df8bae1dSRodney W. Grimes {
186df8bae1dSRodney W. Grimes 	struct pagerops **pgops;
187df8bae1dSRodney W. Grimes 
188f52bd684SEivind Eklund 	TAILQ_INIT(&bswlist);
189df8bae1dSRodney W. Grimes 	/*
190df8bae1dSRodney W. Grimes 	 * Initialize known pagers
191df8bae1dSRodney W. Grimes 	 */
192df8bae1dSRodney W. Grimes 	for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++)
19324a1cce3SDavid Greenman 		if (pgops && ((*pgops)->pgo_init != NULL))
194df8bae1dSRodney W. Grimes 			(*(*pgops)->pgo_init) ();
195df8bae1dSRodney W. Grimes }
196df8bae1dSRodney W. Grimes 
19716f62314SDavid Greenman void
19816f62314SDavid Greenman vm_pager_bufferinit()
19916f62314SDavid Greenman {
20016f62314SDavid Greenman 	struct buf *bp;
20116f62314SDavid Greenman 	int i;
2020d94caffSDavid Greenman 
2036008862bSJohn Baldwin 	mtx_init(&pbuf_mtx, "pbuf mutex", NULL, MTX_DEF);
20416f62314SDavid Greenman 	bp = swbuf;
20516f62314SDavid Greenman 	/*
20616f62314SDavid Greenman 	 * Now set up swap and physical I/O buffer headers.
20716f62314SDavid Greenman 	 */
20850ce7ff4SJohn Dyson 	for (i = 0; i < nswbuf; i++, bp++) {
20916f62314SDavid Greenman 		TAILQ_INSERT_HEAD(&bswlist, bp, b_freelist);
21067812eacSKirk McKusick 		BUF_LOCKINIT(bp);
21167812eacSKirk McKusick 		LIST_INIT(&bp->b_dep);
21216f62314SDavid Greenman 		bp->b_rcred = bp->b_wcred = NOCRED;
21340c8cfe5SPeter Wemm 		bp->b_xflags = 0;
21416f62314SDavid Greenman 	}
21516f62314SDavid Greenman 
2161c7c3c6aSMatthew Dillon 	cluster_pbuf_freecnt = nswbuf / 2;
217857b66d5SAlexander Kabaev 	vnode_pbuf_freecnt = nswbuf / 2 + 1;
2181c7c3c6aSMatthew Dillon 
21998137162SAlan Cox 	swapbkva = kmem_alloc_nofault(pager_map, nswbuf * MAXPHYS);
22016f62314SDavid Greenman 	if (!swapbkva)
22116f62314SDavid Greenman 		panic("Not enough pager_map VM space for physical buffers");
22216f62314SDavid Greenman }
22316f62314SDavid Greenman 
224df8bae1dSRodney W. Grimes /*
225df8bae1dSRodney W. Grimes  * Allocate an instance of a pager of the given type.
226df8bae1dSRodney W. Grimes  * Size, protection and offset parameters are passed in for pagers that
227df8bae1dSRodney W. Grimes  * need to perform page-level validation (e.g. the device pager).
228df8bae1dSRodney W. Grimes  */
22924a1cce3SDavid Greenman vm_object_t
23023955314SAlfred Perlstein vm_pager_allocate(objtype_t type, void *handle, vm_ooffset_t size,
2313364c323SKonstantin Belousov     vm_prot_t prot, vm_ooffset_t off, struct ucred *cred)
232df8bae1dSRodney W. Grimes {
23323955314SAlfred Perlstein 	vm_object_t ret;
234df8bae1dSRodney W. Grimes 	struct pagerops *ops;
235df8bae1dSRodney W. Grimes 
23624a1cce3SDavid Greenman 	ops = pagertab[type];
237df8bae1dSRodney W. Grimes 	if (ops)
2383364c323SKonstantin Belousov 		ret = (*ops->pgo_alloc) (handle, size, prot, off, cred);
23923955314SAlfred Perlstein 	else
24023955314SAlfred Perlstein 		ret = NULL;
24123955314SAlfred Perlstein 	return (ret);
242df8bae1dSRodney W. Grimes }
243df8bae1dSRodney W. Grimes 
244658ad5ffSAlan Cox /*
245658ad5ffSAlan Cox  *	The object must be locked.
246658ad5ffSAlan Cox  */
247df8bae1dSRodney W. Grimes void
24824a1cce3SDavid Greenman vm_pager_deallocate(object)
24924a1cce3SDavid Greenman 	vm_object_t object;
250df8bae1dSRodney W. Grimes {
251658ad5ffSAlan Cox 
252658ad5ffSAlan Cox 	VM_OBJECT_LOCK_ASSERT(object, MA_OWNED);
25324a1cce3SDavid Greenman 	(*pagertab[object->type]->pgo_dealloc) (object);
254df8bae1dSRodney W. Grimes }
255df8bae1dSRodney W. Grimes 
256df8bae1dSRodney W. Grimes /*
2571c7c3c6aSMatthew Dillon  * vm_pager_get_pages() - inline, see vm/vm_pager.h
2581c7c3c6aSMatthew Dillon  * vm_pager_put_pages() - inline, see vm/vm_pager.h
2591c7c3c6aSMatthew Dillon  * vm_pager_has_page() - inline, see vm/vm_pager.h
2601c7c3c6aSMatthew Dillon  */
2611c7c3c6aSMatthew Dillon 
262b5e8f167SAlan Cox /*
263b5e8f167SAlan Cox  * Search the specified pager object list for an object with the
264b5e8f167SAlan Cox  * specified handle.  If an object with the specified handle is found,
265b5e8f167SAlan Cox  * increase its reference count and return it.  Otherwise, return NULL.
266b5e8f167SAlan Cox  *
267b5e8f167SAlan Cox  * The pager object list must be locked.
268b5e8f167SAlan Cox  */
26924a1cce3SDavid Greenman vm_object_t
270b5e8f167SAlan Cox vm_pager_object_lookup(struct pagerlst *pg_list, void *handle)
271df8bae1dSRodney W. Grimes {
27254d92145SMatthew Dillon 	vm_object_t object;
273df8bae1dSRodney W. Grimes 
274b5e8f167SAlan Cox 	TAILQ_FOREACH(object, pg_list, pager_object_list) {
275b5e8f167SAlan Cox 		VM_OBJECT_LOCK(object);
276b5e8f167SAlan Cox 		if (object->handle == handle &&
277b5e8f167SAlan Cox 		    (object->flags & OBJ_DEAD) == 0) {
278b5e8f167SAlan Cox 			vm_object_reference_locked(object);
279b5e8f167SAlan Cox 			VM_OBJECT_UNLOCK(object);
280b5e8f167SAlan Cox 			break;
281b5e8f167SAlan Cox 		}
282b5e8f167SAlan Cox 		VM_OBJECT_UNLOCK(object);
283b5e8f167SAlan Cox 	}
28424a1cce3SDavid Greenman 	return (object);
285df8bae1dSRodney W. Grimes }
286df8bae1dSRodney W. Grimes 
287df8bae1dSRodney W. Grimes /*
28809e0c6ccSJohn Dyson  * initialize a physical buffer
28909e0c6ccSJohn Dyson  */
29009e0c6ccSJohn Dyson 
291f52bd684SEivind Eklund /*
292f52bd684SEivind Eklund  * XXX This probably belongs in vfs_bio.c
293f52bd684SEivind Eklund  */
29409e0c6ccSJohn Dyson static void
295e96c1fdcSPeter Wemm initpbuf(struct buf *bp)
296e96c1fdcSPeter Wemm {
297287013d2SPoul-Henning Kamp 	KASSERT(bp->b_bufobj == NULL, ("initpbuf with bufobj"));
298287013d2SPoul-Henning Kamp 	KASSERT(bp->b_vp == NULL, ("initpbuf with vp"));
29909e0c6ccSJohn Dyson 	bp->b_rcred = NOCRED;
30009e0c6ccSJohn Dyson 	bp->b_wcred = NOCRED;
301f52bd684SEivind Eklund 	bp->b_qindex = 0;	/* On no queue (QUEUE_NONE) */
302adece6e5SPoul-Henning Kamp 	bp->b_saveaddr = (caddr_t) (MAXPHYS * (bp - swbuf)) + swapbkva;
303adece6e5SPoul-Henning Kamp 	bp->b_data = bp->b_saveaddr;
304adece6e5SPoul-Henning Kamp 	bp->b_kvabase = bp->b_saveaddr;
30509e0c6ccSJohn Dyson 	bp->b_kvasize = MAXPHYS;
30640c8cfe5SPeter Wemm 	bp->b_xflags = 0;
30767812eacSKirk McKusick 	bp->b_flags = 0;
308c244d2deSPoul-Henning Kamp 	bp->b_ioflags = 0;
30921144e3bSPoul-Henning Kamp 	bp->b_iodone = NULL;
31067812eacSKirk McKusick 	bp->b_error = 0;
31117661e5aSJeff Roberson 	BUF_LOCK(bp, LK_EXCLUSIVE, NULL);
31209e0c6ccSJohn Dyson }
31309e0c6ccSJohn Dyson 
31409e0c6ccSJohn Dyson /*
31516f62314SDavid Greenman  * allocate a physical buffer
3161c7c3c6aSMatthew Dillon  *
3171c7c3c6aSMatthew Dillon  *	There are a limited number (nswbuf) of physical buffers.  We need
3181c7c3c6aSMatthew Dillon  *	to make sure that no single subsystem is able to hog all of them,
3191c7c3c6aSMatthew Dillon  *	so each subsystem implements a counter which is typically initialized
3201c7c3c6aSMatthew Dillon  *	to 1/2 nswbuf.  getpbuf() decrements this counter in allocation and
3211c7c3c6aSMatthew Dillon  *	increments it on release, and blocks if the counter hits zero.  A
3221c7c3c6aSMatthew Dillon  *	subsystem may initialize the counter to -1 to disable the feature,
3231c7c3c6aSMatthew Dillon  *	but it must still be sure to match up all uses of getpbuf() with
3241c7c3c6aSMatthew Dillon  *	relpbuf() using the same variable.
3251c7c3c6aSMatthew Dillon  *
3261c7c3c6aSMatthew Dillon  *	NOTE: pfreecnt can be NULL, but this 'feature' will be removed
3271c7c3c6aSMatthew Dillon  *	relatively soon when the rest of the subsystems get smart about it. XXX
32816f62314SDavid Greenman  */
32916f62314SDavid Greenman struct buf *
330d7fe1f51SPoul-Henning Kamp getpbuf(int *pfreecnt)
3310d94caffSDavid Greenman {
33216f62314SDavid Greenman 	struct buf *bp;
33316f62314SDavid Greenman 
3342a758ebeSAlfred Perlstein 	mtx_lock(&pbuf_mtx);
3351c7c3c6aSMatthew Dillon 
336652fcae0SStephen McKay 	for (;;) {
3371c7c3c6aSMatthew Dillon 		if (pfreecnt) {
3381c7c3c6aSMatthew Dillon 			while (*pfreecnt == 0) {
3392a758ebeSAlfred Perlstein 				msleep(pfreecnt, &pbuf_mtx, PVM, "wswbuf0", 0);
3401c7c3c6aSMatthew Dillon 			}
3411c7c3c6aSMatthew Dillon 		}
3421c7c3c6aSMatthew Dillon 
34316f62314SDavid Greenman 		/* get a bp from the swap buffer header pool */
344652fcae0SStephen McKay 		if ((bp = TAILQ_FIRST(&bswlist)) != NULL)
345652fcae0SStephen McKay 			break;
346652fcae0SStephen McKay 
34716f62314SDavid Greenman 		bswneeded = 1;
3482a758ebeSAlfred Perlstein 		msleep(&bswneeded, &pbuf_mtx, PVM, "wswbuf1", 0);
349652fcae0SStephen McKay 		/* loop in case someone else grabbed one */
35016f62314SDavid Greenman 	}
35116f62314SDavid Greenman 	TAILQ_REMOVE(&bswlist, bp, b_freelist);
3521c7c3c6aSMatthew Dillon 	if (pfreecnt)
3531c7c3c6aSMatthew Dillon 		--*pfreecnt;
3542a758ebeSAlfred Perlstein 	mtx_unlock(&pbuf_mtx);
35516f62314SDavid Greenman 
35609e0c6ccSJohn Dyson 	initpbuf(bp);
35716f62314SDavid Greenman 	return bp;
35816f62314SDavid Greenman }
35916f62314SDavid Greenman 
36016f62314SDavid Greenman /*
3611c7c3c6aSMatthew Dillon  * allocate a physical buffer, if one is available.
3621c7c3c6aSMatthew Dillon  *
3631c7c3c6aSMatthew Dillon  *	Note that there is no NULL hack here - all subsystems using this
3641c7c3c6aSMatthew Dillon  *	call understand how to use pfreecnt.
36516f62314SDavid Greenman  */
36616f62314SDavid Greenman struct buf *
367d7fe1f51SPoul-Henning Kamp trypbuf(int *pfreecnt)
3680d94caffSDavid Greenman {
36916f62314SDavid Greenman 	struct buf *bp;
37016f62314SDavid Greenman 
3712a758ebeSAlfred Perlstein 	mtx_lock(&pbuf_mtx);
3721c7c3c6aSMatthew Dillon 	if (*pfreecnt == 0 || (bp = TAILQ_FIRST(&bswlist)) == NULL) {
3732a758ebeSAlfred Perlstein 		mtx_unlock(&pbuf_mtx);
37416f62314SDavid Greenman 		return NULL;
37516f62314SDavid Greenman 	}
37616f62314SDavid Greenman 	TAILQ_REMOVE(&bswlist, bp, b_freelist);
3771c7c3c6aSMatthew Dillon 
3781c7c3c6aSMatthew Dillon 	--*pfreecnt;
3791c7c3c6aSMatthew Dillon 
3802a758ebeSAlfred Perlstein 	mtx_unlock(&pbuf_mtx);
38116f62314SDavid Greenman 
38209e0c6ccSJohn Dyson 	initpbuf(bp);
38309e0c6ccSJohn Dyson 
38416f62314SDavid Greenman 	return bp;
38516f62314SDavid Greenman }
38616f62314SDavid Greenman 
38716f62314SDavid Greenman /*
38816f62314SDavid Greenman  * release a physical buffer
3891c7c3c6aSMatthew Dillon  *
3901c7c3c6aSMatthew Dillon  *	NOTE: pfreecnt can be NULL, but this 'feature' will be removed
3911c7c3c6aSMatthew Dillon  *	relatively soon when the rest of the subsystems get smart about it. XXX
39216f62314SDavid Greenman  */
39316f62314SDavid Greenman void
394d7fe1f51SPoul-Henning Kamp relpbuf(struct buf *bp, int *pfreecnt)
39516f62314SDavid Greenman {
39616f62314SDavid Greenman 
39716f62314SDavid Greenman 	if (bp->b_rcred != NOCRED) {
39816f62314SDavid Greenman 		crfree(bp->b_rcred);
39916f62314SDavid Greenman 		bp->b_rcred = NOCRED;
40016f62314SDavid Greenman 	}
40116f62314SDavid Greenman 	if (bp->b_wcred != NOCRED) {
40216f62314SDavid Greenman 		crfree(bp->b_wcred);
40316f62314SDavid Greenman 		bp->b_wcred = NOCRED;
40416f62314SDavid Greenman 	}
4051c7c3c6aSMatthew Dillon 
406287013d2SPoul-Henning Kamp 	KASSERT(bp->b_vp == NULL, ("relpbuf with vp"));
407287013d2SPoul-Henning Kamp 	KASSERT(bp->b_bufobj == NULL, ("relpbuf with bufobj"));
408287013d2SPoul-Henning Kamp 
40967812eacSKirk McKusick 	BUF_UNLOCK(bp);
41061854083SDavid Greenman 
4112ac8b160SAlan Cox 	mtx_lock(&pbuf_mtx);
41216f62314SDavid Greenman 	TAILQ_INSERT_HEAD(&bswlist, bp, b_freelist);
41316f62314SDavid Greenman 
41416f62314SDavid Greenman 	if (bswneeded) {
41516f62314SDavid Greenman 		bswneeded = 0;
41624a1cce3SDavid Greenman 		wakeup(&bswneeded);
41716f62314SDavid Greenman 	}
4181c7c3c6aSMatthew Dillon 	if (pfreecnt) {
4191c7c3c6aSMatthew Dillon 		if (++*pfreecnt == 1)
4201c7c3c6aSMatthew Dillon 			wakeup(pfreecnt);
4211c7c3c6aSMatthew Dillon 	}
4222a758ebeSAlfred Perlstein 	mtx_unlock(&pbuf_mtx);
42316f62314SDavid Greenman }
424a752aa8fSPoul-Henning Kamp 
425a752aa8fSPoul-Henning Kamp /*
426a752aa8fSPoul-Henning Kamp  * Associate a p-buffer with a vnode.
427a752aa8fSPoul-Henning Kamp  *
428a752aa8fSPoul-Henning Kamp  * Also sets B_PAGING flag to indicate that vnode is not fully associated
429a752aa8fSPoul-Henning Kamp  * with the buffer.  i.e. the bp has not been linked into the vnode or
430a752aa8fSPoul-Henning Kamp  * ref-counted.
431a752aa8fSPoul-Henning Kamp  */
432a752aa8fSPoul-Henning Kamp void
433a752aa8fSPoul-Henning Kamp pbgetvp(struct vnode *vp, struct buf *bp)
434a752aa8fSPoul-Henning Kamp {
435a752aa8fSPoul-Henning Kamp 
436a752aa8fSPoul-Henning Kamp 	KASSERT(bp->b_vp == NULL, ("pbgetvp: not free"));
437287013d2SPoul-Henning Kamp 	KASSERT(bp->b_bufobj == NULL, ("pbgetvp: not free (bufobj)"));
438a752aa8fSPoul-Henning Kamp 
439a752aa8fSPoul-Henning Kamp 	bp->b_vp = vp;
440a752aa8fSPoul-Henning Kamp 	bp->b_flags |= B_PAGING;
441a752aa8fSPoul-Henning Kamp 	bp->b_bufobj = &vp->v_bufobj;
442a752aa8fSPoul-Henning Kamp }
443a752aa8fSPoul-Henning Kamp 
444a752aa8fSPoul-Henning Kamp /*
4455c6e573fSPoul-Henning Kamp  * Associate a p-buffer with a vnode.
4465c6e573fSPoul-Henning Kamp  *
4475c6e573fSPoul-Henning Kamp  * Also sets B_PAGING flag to indicate that vnode is not fully associated
4485c6e573fSPoul-Henning Kamp  * with the buffer.  i.e. the bp has not been linked into the vnode or
4495c6e573fSPoul-Henning Kamp  * ref-counted.
4505c6e573fSPoul-Henning Kamp  */
4515c6e573fSPoul-Henning Kamp void
4525c6e573fSPoul-Henning Kamp pbgetbo(struct bufobj *bo, struct buf *bp)
4535c6e573fSPoul-Henning Kamp {
4545c6e573fSPoul-Henning Kamp 
4555c6e573fSPoul-Henning Kamp 	KASSERT(bp->b_vp == NULL, ("pbgetbo: not free (vnode)"));
4565c6e573fSPoul-Henning Kamp 	KASSERT(bp->b_bufobj == NULL, ("pbgetbo: not free (bufobj)"));
4575c6e573fSPoul-Henning Kamp 
4585c6e573fSPoul-Henning Kamp 	bp->b_flags |= B_PAGING;
4595c6e573fSPoul-Henning Kamp 	bp->b_bufobj = bo;
4605c6e573fSPoul-Henning Kamp }
4615c6e573fSPoul-Henning Kamp 
4625c6e573fSPoul-Henning Kamp /*
463a752aa8fSPoul-Henning Kamp  * Disassociate a p-buffer from a vnode.
464a752aa8fSPoul-Henning Kamp  */
465a752aa8fSPoul-Henning Kamp void
466a752aa8fSPoul-Henning Kamp pbrelvp(struct buf *bp)
467a752aa8fSPoul-Henning Kamp {
468a752aa8fSPoul-Henning Kamp 
469a752aa8fSPoul-Henning Kamp 	KASSERT(bp->b_vp != NULL, ("pbrelvp: NULL"));
470a752aa8fSPoul-Henning Kamp 	KASSERT(bp->b_bufobj != NULL, ("pbrelvp: NULL bufobj"));
471a752aa8fSPoul-Henning Kamp 
472a752aa8fSPoul-Henning Kamp 	/* XXX REMOVE ME */
473a752aa8fSPoul-Henning Kamp 	BO_LOCK(bp->b_bufobj);
474a752aa8fSPoul-Henning Kamp 	if (TAILQ_NEXT(bp, b_bobufs) != NULL) {
475a752aa8fSPoul-Henning Kamp 		panic(
476a752aa8fSPoul-Henning Kamp 		    "relpbuf(): b_vp was probably reassignbuf()d %p %x",
477a752aa8fSPoul-Henning Kamp 		    bp,
478a752aa8fSPoul-Henning Kamp 		    (int)bp->b_flags
479a752aa8fSPoul-Henning Kamp 		);
480a752aa8fSPoul-Henning Kamp 	}
481a752aa8fSPoul-Henning Kamp 	BO_UNLOCK(bp->b_bufobj);
482a752aa8fSPoul-Henning Kamp 	bp->b_vp = NULL;
483a752aa8fSPoul-Henning Kamp 	bp->b_bufobj = NULL;
484a752aa8fSPoul-Henning Kamp 	bp->b_flags &= ~B_PAGING;
485a752aa8fSPoul-Henning Kamp }
4865c6e573fSPoul-Henning Kamp 
4875c6e573fSPoul-Henning Kamp /*
4885c6e573fSPoul-Henning Kamp  * Disassociate a p-buffer from a bufobj.
4895c6e573fSPoul-Henning Kamp  */
4905c6e573fSPoul-Henning Kamp void
4915c6e573fSPoul-Henning Kamp pbrelbo(struct buf *bp)
4925c6e573fSPoul-Henning Kamp {
4935c6e573fSPoul-Henning Kamp 
4945c6e573fSPoul-Henning Kamp 	KASSERT(bp->b_vp == NULL, ("pbrelbo: vnode"));
4955c6e573fSPoul-Henning Kamp 	KASSERT(bp->b_bufobj != NULL, ("pbrelbo: NULL bufobj"));
4965c6e573fSPoul-Henning Kamp 
4975c6e573fSPoul-Henning Kamp 	/* XXX REMOVE ME */
4985c6e573fSPoul-Henning Kamp 	BO_LOCK(bp->b_bufobj);
4995c6e573fSPoul-Henning Kamp 	if (TAILQ_NEXT(bp, b_bobufs) != NULL) {
5005c6e573fSPoul-Henning Kamp 		panic(
5015c6e573fSPoul-Henning Kamp 		    "relpbuf(): b_vp was probably reassignbuf()d %p %x",
5025c6e573fSPoul-Henning Kamp 		    bp,
5035c6e573fSPoul-Henning Kamp 		    (int)bp->b_flags
5045c6e573fSPoul-Henning Kamp 		);
5055c6e573fSPoul-Henning Kamp 	}
5065c6e573fSPoul-Henning Kamp 	BO_UNLOCK(bp->b_bufobj);
5075c6e573fSPoul-Henning Kamp 	bp->b_bufobj = NULL;
5085c6e573fSPoul-Henning Kamp 	bp->b_flags &= ~B_PAGING;
5095c6e573fSPoul-Henning Kamp }
510