* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
* This code is derived from software contributed to Berkeley by
* The Mach Operating System project at Carnegie-Mellon University.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* @(#)vm_pager.c 8.6 (Berkeley) 1/12/94
* Copyright (c) 1987, 1990 Carnegie-Mellon University.
* Authors: Avadis Tevanian, Jr., Michael Wayne Young
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
* Carnegie Mellon requests users of this software to return to
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
* Paging space routine stubs. Emulates a matchmaker-like interface
extern struct pagerops swappagerops
;
extern struct pagerops vnodepagerops
;
extern struct pagerops devicepagerops
;
struct pagerops
*pagertab
[] = {
&swappagerops
, /* PG_SWAP */
&vnodepagerops
, /* PG_VNODE */
&devicepagerops
, /* PG_DEV */
int npagers
= sizeof (pagertab
) / sizeof (pagertab
[0]);
struct pagerops
*dfltpagerops
= NULL
; /* default pager */
* Kernel address space for mapping pages.
* Used by pagers where KVAs are needed for IO.
* XXX needs to be large enough to support the number of pending async
* cleaning requests (NPENDINGIO == 64) * the maximum swap cluster size
* (MAXPHYS == 64k) if you want to get the most efficiency.
#define PAGER_MAP_SIZE (4 * 1024 * 1024)
boolean_t pager_map_wanted
;
vm_offset_t pager_sva
, pager_eva
;
* Allocate a kernel submap for tracking get/put page mappings
pager_map
= kmem_suballoc(kernel_map
, &pager_sva
, &pager_eva
,
* Initialize known pagers
for (pgops
= pagertab
; pgops
< &pagertab
[npagers
]; pgops
++)
if (dfltpagerops
== NULL
)
panic("no default pager");
* Allocate an instance of a pager of the given type.
* Size, protection and offset parameters are passed in for pagers that
* need to perform page-level validation (e.g. the device pager).
vm_pager_allocate(type
, handle
, size
, prot
, off
)
ops
= (type
== PG_DFLT
) ? dfltpagerops
: pagertab
[type
];
return ((*ops
->pgo_alloc
)(handle
, size
, prot
, off
));
vm_pager_deallocate(pager
)
panic("vm_pager_deallocate: null pager");
(*pager
->pg_ops
->pgo_dealloc
)(pager
);
vm_pager_get_pages(pager
, mlist
, npages
, sync
)
if (!vm_page_zero_fill(*mlist
)) {
return ((*pager
->pg_ops
->pgo_getpages
)(pager
, mlist
, npages
, sync
));
vm_pager_put_pages(pager
, mlist
, npages
, sync
)
panic("vm_pager_put_pages: null pager");
return ((*pager
->pg_ops
->pgo_putpages
)(pager
, mlist
, npages
, sync
));
vm_pager_has_page(pager
, offset
)
panic("vm_pager_has_page: null pager");
return ((*pager
->pg_ops
->pgo_haspage
)(pager
, offset
));
* Called by pageout daemon before going back to sleep.
* Gives pagers a chance to clean up any completed async pageing operations.
for (pgops
= pagertab
; pgops
< &pagertab
[npagers
]; pgops
++)
(*(*pgops
)->pgo_putpages
)(NULL
, NULL
, 0, FALSE
);
vm_pager_cluster(pager
, offset
, loff
, hoff
)
panic("vm_pager_cluster: null pager");
return ((*pager
->pg_ops
->pgo_cluster
)(pager
, offset
, loff
, hoff
));
vm_pager_clusternull(pager
, offset
, loff
, hoff
)
panic("vm_pager_nullcluster called");
vm_pager_map_pages(mlist
, npages
, canwait
)
* Allocate space in the pager map, if none available return 0.
* This is basically an expansion of kmem_alloc_wait with optional
size
= npages
* PAGE_SIZE
;
while (vm_map_findspace(pager_map
, 0, size
, &kva
)) {
vm_map_unlock(pager_map
);
vm_map_unlock(pager_map
);
(void) tsleep(pager_map
, PVM
, "pager_map", 0);
vm_map_insert(pager_map
, NULL
, 0, kva
, kva
+ size
);
vm_map_unlock(pager_map
);
for (va
= kva
; npages
--; va
+= PAGE_SIZE
) {
if ((m
->flags
& PG_BUSY
) == 0)
panic("vm_pager_map_pages: page not busy");
if (m
->flags
& PG_PAGEROWNED
)
panic("vm_pager_map_pages: page already in pager");
m
->flags
|= PG_PAGEROWNED
;
pmap_enter(vm_map_pmap(pager_map
), va
, VM_PAGE_TO_PHYS(m
),
vm_pager_unmap_pages(kva
, npages
)
vm_size_t size
= npages
* PAGE_SIZE
;
for (va
= kva
; np
--; va
+= PAGE_SIZE
) {
if (m
->flags
& PG_PAGEROWNED
)
m
->flags
&= ~PG_PAGEROWNED
;
printf("vm_pager_unmap_pages: %x(%x/%x) not owned\n",
m
, va
, VM_PAGE_TO_PHYS(m
));
pmap_remove(vm_map_pmap(pager_map
), kva
, kva
+ size
);
(void) vm_map_delete(pager_map
, kva
, kva
+ size
);
vm_map_unlock(pager_map
);
pa
= pmap_extract(vm_map_pmap(pager_map
), kva
);
return (PHYS_TO_VM_PAGE(pa
));
vm_pager_lookup(pglist
, handle
)
register struct pagerlst
*pglist
;
register vm_pager_t pager
;
for (pager
= pglist
->tqh_first
; pager
; pager
= pager
->pg_list
.tqe_next
)
if (pager
->pg_handle
== handle
)
* This routine gains a reference to the object.
* Explicit deallocation is necessary.
pager_cache(object
, should_cache
)
return (KERN_INVALID_ARGUMENT
);
object
->flags
|= OBJ_CANPERSIST
;
object
->flags
&= ~OBJ_CANPERSIST
;
vm_object_unlock(object
);
vm_object_cache_unlock();
vm_object_deallocate(object
);