|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright (c) 1990 NeXT, Inc.
27: *
28: * History:
29: *
30: * 6-Aug-90: Brian Pinkerton at NeXT
31: * created
32: */
33:
34:
35: #import <mach_xp.h>
36:
37: #import <sys/types.h>
38: #import <sys/param.h>
39:
40: #import <mach/vm_param.h>
41: #import <vm/vm_object.h>
42: #import <vm/vm_map.h>
43: #import <vm/vm_page.h>
44: #import <mach/vm_statistics.h>
45:
46: #import <mach/boolean.h>
47: #import <mach/kern_return.h>
48: #import <kern/task.h>
49: #import <kern/kalloc.h>
50:
51: #import <mach/mach_types.h> /* to get vm_address_t */
52:
53:
54: static kern_return_t map_push_range(vm_map_t map, vm_offset_t start, vm_offset_t end);
55:
56: static kern_return_t object_push(vm_object_t object, vm_offset_t object_start, vm_offset_t object_end);
57:
58: enum pageout_outcome { PAGEOUT_SUCCESS, PAGEOUT_ERROR, PAGEOUT_RERUN };
59:
60: /*
61: * Push all pages to disk.
62: */
63: kern_return_t
64: vm_synchronize(
65: vm_map_t task_map,
66: vm_address_t vmaddr,
67: vm_size_t vmsize)
68: {
69: kern_return_t result;
70:
71: if (!task_map)
72: return KERN_FAILURE;
73:
74: if (vmsize == 0)
75: vmsize = task_map->max_offset - task_map->min_offset;
76:
77: if (vmaddr == 0)
78: vmaddr = task_map->min_offset;
79:
80: result = map_push_range(task_map, vmaddr, vmaddr+vmsize);
81:
82: return result;
83: }
84:
85:
86: /*
87: * Push a range of pages in a map.
88: */
89: static kern_return_t
90: map_push_range(
91: vm_map_t map,
92: vm_offset_t start,
93: vm_offset_t end)
94: {
95: vm_map_entry_t entry;
96: vm_object_t object;
97: vm_offset_t tend;
98: int offset;
99: kern_return_t rtn, realRtn = KERN_SUCCESS;
100:
101: vm_map_lock_read(map);
102: /*
103: * Push all the pages in this map.
104: */
105: for ( entry = vm_map_first_entry(map)
106: ; entry != vm_map_to_entry(map)
107: ; entry = entry->vme_next)
108: {
109: if (entry->is_a_map || entry->is_sub_map) {
110: vm_map_t sub_map;
111: /*
112: * Recurse over this sub-map.
113: */
114: sub_map = entry->object.sub_map;
115: rtn = map_push_range(sub_map, start, end);
116: if (rtn == KERN_FAILURE)
117: realRtn = KERN_FAILURE;
118: continue;
119: }
120: if (entry->vme_start > end || entry->vme_end <= start)
121: continue;
122:
123: /*
124: * Push the pages we can see in this object chain.
125: */
126: object = entry->object.vm_object;
127: if (entry->vme_start > start)
128: start = entry->vme_start;
129: tend = (entry->vme_end > end) ? end : entry->vme_end;
130: offset = entry->offset + start - entry->vme_start;
131: rtn = object_push(object, offset, offset + tend - start);
132: if (rtn)
133: realRtn = KERN_FAILURE;
134: }
135: vm_map_unlock(map);
136:
137: return realRtn;
138: }
139:
140:
141: /*
142: * Page out a page belonging to the given object. The object must be locked.
143: */
144: static enum pageout_outcome
145: vm_pageout_page(vm_object_t object, vm_page_t m)
146: {
147: enum pageout_outcome pageout_succeeded;
148: vm_pager_t pager = object->pager;
149:
150: vm_page_lock_queues();
151: if (m->clean && !pmap_is_modified(VM_PAGE_TO_PHYS(m))) {
152: vm_page_unlock_queues();
153: return PAGEOUT_SUCCESS;
154: }
155:
156: /*
157: * If the page is already busy, sleep on it...
158: */
159: while (m->busy) {
160: vm_page_unlock_queues();
161: PAGE_ASSERT_WAIT(m, FALSE);
162: vm_object_unlock(object);
163: thread_block();
164: vm_object_lock(object);
165: return PAGEOUT_RERUN;
166: }
167:
168: object->paging_in_progress++;
169:
170: m->busy = TRUE;
171: if (m->inactive)
172: vm_page_activate(m);
173: vm_page_deactivate(m);
174:
175: pmap_remove_all(VM_PAGE_TO_PHYS(m));
176: vm_stat.pageouts++;
177:
178: vm_page_unlock_queues();
179: if (pager == vm_pager_null) {
180: object->paging_in_progress--;
181: return PAGEOUT_ERROR;
182: }
183: vm_object_unlock(object);
184:
185: pageout_succeeded = PAGEOUT_ERROR;
186: if (pager != vm_pager_null) {
187: if (vm_pager_put(pager, m) == PAGER_SUCCESS) {
188: pageout_succeeded = PAGEOUT_SUCCESS;
189: }
190: }
191:
192: vm_object_lock(object);
193: vm_page_lock_queues();
194: m->busy = FALSE;
195: PAGE_WAKEUP(m);
196:
197: object->paging_in_progress--;
198: vm_page_unlock_queues();
199:
200: return pageout_succeeded;
201: }
202:
203:
204: /*
205: * Count resident pages in this object and all shadow objects over the
206: * specified address range.
207: *
208: * If we encounter an error, we'll attempt to push the rest of the pages,
209: * and return an error for the whole object.
210: *
211: * If we encounter a locked page, then we'll restart
212: */
213: static kern_return_t
214: object_push(vm_object_t object, vm_offset_t object_start, vm_offset_t object_end)
215: {
216: vm_object_t shadow;
217: vm_page_t page;
218: vm_size_t object_size;
219: int flags;
220: int allPageoutsSucceeded = TRUE;
221: kern_return_t rtn = FALSE;
222:
223: if (object == VM_OBJECT_NULL)
224: return KERN_SUCCESS;
225:
226: vm_object_lock(object);
227:
228: retry:
229: for ( page = (vm_page_t) queue_first(&object->memq)
230: ; !queue_end(&object->memq, (queue_entry_t) page)
231: ; page = (vm_page_t) queue_next(&page->listq))
232: {
233: /*
234: * If this page isn't actually referenced from this
235: * entry, then forget it.
236: */
237: if (page->offset < object_start || page->offset >= object_end)
238: continue;
239:
240: /*
241: * Push this page. If we fail, retry on the whole object.
242: */
243: switch (vm_pageout_page(object, page)) {
244: case PAGEOUT_RERUN:
245: goto retry;
246: case PAGEOUT_ERROR:
247: allPageoutsSucceeded = FALSE;
248: case PAGEOUT_SUCCESS:
249: default:
250: break;
251: }
252: }
253:
254: /*
255: * Recurse over shadow objects.
256: */
257: object_size = object_end - object_start;
258: if (object->size && object_end - object_start > object->size)
259: object_size = object->size;
260: object_start += object->shadow_offset;
261: object_end = object_start + object_size;
262:
263: if (object_push(object->shadow, object_start, object_end) != KERN_SUCCESS)
264: rtn = KERN_FAILURE;
265:
266: vm_object_unlock(object);
267: thread_wakeup(object);
268:
269: if (rtn == KERN_FAILURE || !allPageoutsSucceeded)
270: return KERN_FAILURE;
271: else
272: return KERN_SUCCESS;
273: }
274:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.