]> git.saurik.com Git - apple/xnu.git/blob - osfmk/default_pager/dp_memory_object.c
xnu-792.17.14.tar.gz
[apple/xnu.git] / osfmk / default_pager / dp_memory_object.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56
57 /*
58 * Default Pager.
59 * Memory Object Management.
60 */
61
62 #include "default_pager_internal.h"
63 #include <default_pager/default_pager_object_server.h>
64 #include <mach/memory_object_default_server.h>
65 #include <mach/memory_object_control.h>
66 #include <mach/memory_object_types.h>
67 #include <mach/memory_object_server.h>
68 #include <mach/upl.h>
69 #include <mach/vm_map.h>
70 #include <vm/memory_object.h>
71 #include <vm/vm_pageout.h>
72 #include <vm/vm_map.h>
73 #include <vm/vm_protos.h>
74
75 /* forward declaration */
76 vstruct_t vs_object_create(vm_size_t size);
77
78 /*
79 * List of all vstructs. A specific vstruct is
80 * found directly via its port, this list is
81 * only used for monitoring purposes by the
82 * default_pager_object* calls and by ps_delete
83 * when abstract memory objects must be scanned
84 * to remove any live storage on a segment which
85 * is to be removed.
86 */
87 struct vstruct_list_head vstruct_list;
88
89 __private_extern__ void
90 vstruct_list_insert(
91 vstruct_t vs)
92 {
93 VSL_LOCK();
94 queue_enter(&vstruct_list.vsl_queue, vs, vstruct_t, vs_links);
95 vstruct_list.vsl_count++;
96 VSL_UNLOCK();
97 }
98
99
100 __private_extern__ void
101 vstruct_list_delete(
102 vstruct_t vs)
103 {
104 queue_remove(&vstruct_list.vsl_queue, vs, vstruct_t, vs_links);
105 vstruct_list.vsl_count--;
106 }
107
108 /*
109 * We use the sequence numbers on requests to regulate
110 * our parallelism. In general, we allow multiple reads and writes
111 * to proceed in parallel, with the exception that reads must
112 * wait for previous writes to finish. (Because the kernel might
113 * generate a data-request for a page on the heels of a data-write
114 * for the same page, and we must avoid returning stale data.)
115 * terminate requests wait for proceeding reads and writes to finish.
116 */
117
118 static unsigned int default_pager_total = 0; /* debugging */
119 static unsigned int default_pager_wait_seqno = 0; /* debugging */
120 static unsigned int default_pager_wait_read = 0; /* debugging */
121 static unsigned int default_pager_wait_write = 0; /* debugging */
122
123 __private_extern__ void
124 vs_async_wait(
125 vstruct_t vs)
126 {
127
128 ASSERT(vs->vs_async_pending >= 0);
129 while (vs->vs_async_pending > 0) {
130 vs->vs_waiting_async = TRUE;
131 assert_wait(&vs->vs_async_pending, THREAD_UNINT);
132 VS_UNLOCK(vs);
133 thread_block(THREAD_CONTINUE_NULL);
134 VS_LOCK(vs);
135 }
136 ASSERT(vs->vs_async_pending == 0);
137 }
138
139
140 #if PARALLEL
141 /*
142 * Waits for correct sequence number. Leaves pager locked.
143 *
144 * JMM - Sequence numbers guarantee ordering of requests generated
145 * by a single thread if the receiver is multithreaded and
146 * the interfaces are asynchronous (i.e. sender can generate
147 * more than one request before the first is received in the
148 * pager). Normally, IPC would generate these number in that
149 * case. But we are trying to avoid using IPC for the in-kernel
150 * scenario. Since these are actually invoked synchronously
151 * anyway (in-kernel), we can just fake the sequence number
152 * generation here (thus avoiding the dependence on IPC).
153 */
154 __private_extern__ void
155 vs_lock(
156 vstruct_t vs)
157 {
158 mach_port_seqno_t seqno;
159
160 default_pager_total++;
161 VS_LOCK(vs);
162
163 seqno = vs->vs_next_seqno++;
164
165 while (vs->vs_seqno != seqno) {
166 default_pager_wait_seqno++;
167 vs->vs_waiting_seqno = TRUE;
168 assert_wait(&vs->vs_seqno, THREAD_UNINT);
169 VS_UNLOCK(vs);
170 thread_block(THREAD_CONTINUE_NULL);
171 VS_LOCK(vs);
172 }
173 }
174
175 /*
176 * Increments sequence number and unlocks pager.
177 */
178 __private_extern__ void
179 vs_unlock(vstruct_t vs)
180 {
181 vs->vs_seqno++;
182 if (vs->vs_waiting_seqno) {
183 vs->vs_waiting_seqno = FALSE;
184 VS_UNLOCK(vs);
185 thread_wakeup(&vs->vs_seqno);
186 return;
187 }
188 VS_UNLOCK(vs);
189 }
190
191 /*
192 * Start a read - one more reader. Pager must be locked.
193 */
194 __private_extern__ void
195 vs_start_read(
196 vstruct_t vs)
197 {
198 vs->vs_readers++;
199 }
200
201 /*
202 * Wait for readers. Unlocks and relocks pager if wait needed.
203 */
204 __private_extern__ void
205 vs_wait_for_readers(
206 vstruct_t vs)
207 {
208 while (vs->vs_readers != 0) {
209 default_pager_wait_read++;
210 vs->vs_waiting_read = TRUE;
211 assert_wait(&vs->vs_readers, THREAD_UNINT);
212 VS_UNLOCK(vs);
213 thread_block(THREAD_CONTINUE_NULL);
214 VS_LOCK(vs);
215 }
216 }
217
218 /*
219 * Finish a read. Pager is unlocked and returns unlocked.
220 */
221 __private_extern__ void
222 vs_finish_read(
223 vstruct_t vs)
224 {
225 VS_LOCK(vs);
226 if (--vs->vs_readers == 0 && vs->vs_waiting_read) {
227 vs->vs_waiting_read = FALSE;
228 VS_UNLOCK(vs);
229 thread_wakeup(&vs->vs_readers);
230 return;
231 }
232 VS_UNLOCK(vs);
233 }
234
235 /*
236 * Start a write - one more writer. Pager must be locked.
237 */
238 __private_extern__ void
239 vs_start_write(
240 vstruct_t vs)
241 {
242 vs->vs_writers++;
243 }
244
245 /*
246 * Wait for writers. Unlocks and relocks pager if wait needed.
247 */
248 __private_extern__ void
249 vs_wait_for_writers(
250 vstruct_t vs)
251 {
252 while (vs->vs_writers != 0) {
253 default_pager_wait_write++;
254 vs->vs_waiting_write = TRUE;
255 assert_wait(&vs->vs_writers, THREAD_UNINT);
256 VS_UNLOCK(vs);
257 thread_block(THREAD_CONTINUE_NULL);
258 VS_LOCK(vs);
259 }
260 vs_async_wait(vs);
261 }
262
263 /* This is to be used for the transfer from segment code ONLY */
264 /* The transfer code holds off vs destruction by keeping the */
265 /* vs_async_wait count non-zero. It will not ocnflict with */
266 /* other writers on an async basis because it only writes on */
267 /* a cluster basis into fresh (as of sync time) cluster locations */
268
269 __private_extern__ void
270 vs_wait_for_sync_writers(
271 vstruct_t vs)
272 {
273 while (vs->vs_writers != 0) {
274 default_pager_wait_write++;
275 vs->vs_waiting_write = TRUE;
276 assert_wait(&vs->vs_writers, THREAD_UNINT);
277 VS_UNLOCK(vs);
278 thread_block(THREAD_CONTINUE_NULL);
279 VS_LOCK(vs);
280 }
281 }
282
283
284 /*
285 * Finish a write. Pager is unlocked and returns unlocked.
286 */
287 __private_extern__ void
288 vs_finish_write(
289 vstruct_t vs)
290 {
291 VS_LOCK(vs);
292 if (--vs->vs_writers == 0 && vs->vs_waiting_write) {
293 vs->vs_waiting_write = FALSE;
294 VS_UNLOCK(vs);
295 thread_wakeup(&vs->vs_writers);
296 return;
297 }
298 VS_UNLOCK(vs);
299 }
300 #endif /* PARALLEL */
301
302 vstruct_t
303 vs_object_create(
304 vm_size_t size)
305 {
306 vstruct_t vs;
307
308 /*
309 * Allocate a vstruct. If there are any problems, then report them
310 * to the console.
311 */
312 vs = ps_vstruct_create(size);
313 if (vs == VSTRUCT_NULL) {
314 dprintf(("vs_object_create: unable to allocate %s\n",
315 "-- either run swapon command or reboot"));
316 return VSTRUCT_NULL;
317 }
318
319 return vs;
320 }
321
322 #if 0
323 void default_pager_add(vstruct_t, boolean_t); /* forward */
324
325 void
326 default_pager_add(
327 vstruct_t vs,
328 boolean_t internal)
329 {
330 memory_object_t mem_obj = vs->vs_mem_obj;
331 mach_port_t pset;
332 mach_port_mscount_t sync;
333 mach_port_t previous;
334 kern_return_t kr;
335 static char here[] = "default_pager_add";
336
337 /*
338 * The port currently has a make-send count of zero,
339 * because either we just created the port or we just
340 * received the port in a memory_object_create request.
341 */
342
343 if (internal) {
344 /* possibly generate an immediate no-senders notification */
345 sync = 0;
346 pset = default_pager_internal_set;
347 } else {
348 /* delay notification till send right is created */
349 sync = 1;
350 pset = default_pager_external_set;
351 }
352
353 ipc_port_make_sonce(mem_obj);
354 ip_lock(mem_obj); /* unlocked in nsrequest below */
355 ipc_port_nsrequest(mem_obj, sync, mem_obj, &previous);
356 }
357
358 #endif
359
360 kern_return_t
361 dp_memory_object_init(
362 memory_object_t mem_obj,
363 memory_object_control_t control,
364 __unused vm_size_t pager_page_size)
365 {
366 vstruct_t vs;
367
368 assert(pager_page_size == vm_page_size);
369
370 memory_object_control_reference(control);
371
372 vs_lookup(mem_obj, vs);
373 vs_lock(vs);
374
375 if (vs->vs_control != MEMORY_OBJECT_CONTROL_NULL)
376 Panic("bad request");
377
378 vs->vs_control = control;
379 vs_unlock(vs);
380
381 return KERN_SUCCESS;
382 }
383
384 kern_return_t
385 dp_memory_object_synchronize(
386 memory_object_t mem_obj,
387 memory_object_offset_t offset,
388 vm_size_t length,
389 __unused vm_sync_t flags)
390 {
391 vstruct_t vs;
392
393 vs_lookup(mem_obj, vs);
394 vs_lock(vs);
395 vs_unlock(vs);
396
397 memory_object_synchronize_completed(vs->vs_control, offset, length);
398
399 return KERN_SUCCESS;
400 }
401
402 kern_return_t
403 dp_memory_object_unmap(
404 __unused memory_object_t mem_obj)
405 {
406 panic("dp_memory_object_unmap");
407
408 return KERN_FAILURE;
409 }
410
411 kern_return_t
412 dp_memory_object_terminate(
413 memory_object_t mem_obj)
414 {
415 memory_object_control_t control;
416 vstruct_t vs;
417
418 /*
419 * control port is a receive right, not a send right.
420 */
421
422 vs_lookup(mem_obj, vs);
423 vs_lock(vs);
424
425 /*
426 * Wait for read and write requests to terminate.
427 */
428
429 vs_wait_for_readers(vs);
430 vs_wait_for_writers(vs);
431
432 /*
433 * After memory_object_terminate both memory_object_init
434 * and a no-senders notification are possible, so we need
435 * to clean up our reference to the memory_object_control
436 * to prepare for a new init.
437 */
438
439 control = vs->vs_control;
440 vs->vs_control = MEMORY_OBJECT_CONTROL_NULL;
441
442 /* a bit of special case ugliness here. Wakeup any waiting reads */
443 /* these data requests had to be removed from the seqno traffic */
444 /* based on a performance bottleneck with large memory objects */
445 /* the problem will right itself with the new component based */
446 /* synchronous interface. The new async will be able to return */
447 /* failure during its sync phase. In the mean time ... */
448
449 thread_wakeup(&vs->vs_writers);
450 thread_wakeup(&vs->vs_async_pending);
451
452 vs_unlock(vs);
453
454 /*
455 * Now we deallocate our reference on the control.
456 */
457 memory_object_control_deallocate(control);
458 return KERN_SUCCESS;
459 }
460
461 void
462 dp_memory_object_reference(
463 memory_object_t mem_obj)
464 {
465 vstruct_t vs;
466
467 vs_lookup_safe(mem_obj, vs);
468 if (vs == VSTRUCT_NULL)
469 return;
470
471 VS_LOCK(vs);
472 assert(vs->vs_references > 0);
473 vs->vs_references++;
474 VS_UNLOCK(vs);
475 }
476
477 void
478 dp_memory_object_deallocate(
479 memory_object_t mem_obj)
480 {
481 vstruct_t vs;
482 mach_port_seqno_t seqno;
483
484 /*
485 * Because we don't give out multiple first references
486 * for a memory object, there can't be a race
487 * between getting a deallocate call and creating
488 * a new reference for the object.
489 */
490
491 vs_lookup_safe(mem_obj, vs);
492 if (vs == VSTRUCT_NULL)
493 return;
494
495 VS_LOCK(vs);
496 if (--vs->vs_references > 0) {
497 VS_UNLOCK(vs);
498 return;
499 }
500
501 seqno = vs->vs_next_seqno++;
502 while (vs->vs_seqno != seqno) {
503 default_pager_wait_seqno++;
504 vs->vs_waiting_seqno = TRUE;
505 assert_wait(&vs->vs_seqno, THREAD_UNINT);
506 VS_UNLOCK(vs);
507 thread_block(THREAD_CONTINUE_NULL);
508 VS_LOCK(vs);
509 }
510
511 vs_async_wait(vs); /* wait for pending async IO */
512
513 /* do not delete the vs structure until the referencing pointers */
514 /* in the vstruct list have been expunged */
515
516 /* get VSL_LOCK out of order by using TRY mechanism */
517 while(!VSL_LOCK_TRY()) {
518 VS_UNLOCK(vs);
519 VSL_LOCK();
520 VSL_UNLOCK();
521 VS_LOCK(vs);
522 vs_async_wait(vs); /* wait for pending async IO */
523 }
524
525
526 /*
527 * We shouldn't get a deallocation call
528 * when the kernel has the object cached.
529 */
530 if (vs->vs_control != MEMORY_OBJECT_CONTROL_NULL)
531 Panic("bad request");
532
533 /*
534 * Unlock the pager (though there should be no one
535 * waiting for it).
536 */
537 VS_UNLOCK(vs);
538
539 /* Lock out paging segment removal for the duration of this */
540 /* call. We are vulnerable to losing a paging segment we rely */
541 /* on as soon as we remove ourselves from the VSL and unlock */
542
543 /* Keep our thread from blocking on attempt to trigger backing */
544 /* store release */
545 backing_store_release_trigger_disable += 1;
546
547 /*
548 * Remove the memory object port association, and then
549 * the destroy the port itself. We must remove the object
550 * from the port list before deallocating the pager,
551 * because of default_pager_objects.
552 */
553 vstruct_list_delete(vs);
554 VSL_UNLOCK();
555
556 ps_vstruct_dealloc(vs);
557
558 VSL_LOCK();
559 backing_store_release_trigger_disable -= 1;
560 if(backing_store_release_trigger_disable == 0) {
561 thread_wakeup((event_t)&backing_store_release_trigger_disable);
562 }
563 VSL_UNLOCK();
564 }
565
566 kern_return_t
567 dp_memory_object_data_request(
568 memory_object_t mem_obj,
569 memory_object_offset_t offset,
570 vm_size_t length,
571 __unused vm_prot_t protection_required)
572 {
573 vstruct_t vs;
574
575 GSTAT(global_stats.gs_pagein_calls++);
576
577
578 /* CDY at this moment vs_lookup panics when presented with the wrong */
579 /* port. As we are expanding this pager to support user interfaces */
580 /* this should be changed to return kern_failure */
581 vs_lookup(mem_obj, vs);
582 vs_lock(vs);
583
584 /* We are going to relax the strict sequencing here for performance */
585 /* reasons. We can do this because we know that the read and */
586 /* write threads are different and we rely on synchronization */
587 /* of read and write requests at the cache memory_object level */
588 /* break out wait_for_writers, all of this goes away when */
589 /* we get real control of seqno with the new component interface */
590
591 if (vs->vs_writers != 0) {
592 /* you can't hold on to the seqno and go */
593 /* to sleep like that */
594 vs_unlock(vs); /* bump internal count of seqno */
595 VS_LOCK(vs);
596 while (vs->vs_writers != 0) {
597 default_pager_wait_write++;
598 vs->vs_waiting_write = TRUE;
599 assert_wait(&vs->vs_writers, THREAD_UNINT);
600 VS_UNLOCK(vs);
601 thread_block(THREAD_CONTINUE_NULL);
602 VS_LOCK(vs);
603 vs_async_wait(vs);
604 }
605 if(vs->vs_control == MEMORY_OBJECT_CONTROL_NULL) {
606 VS_UNLOCK(vs);
607 return KERN_FAILURE;
608 }
609 vs_start_read(vs);
610 VS_UNLOCK(vs);
611 } else {
612 vs_start_read(vs);
613 vs_unlock(vs);
614 }
615
616 /*
617 * Request must be on a page boundary and a multiple of pages.
618 */
619 if ((offset & vm_page_mask) != 0 || (length & vm_page_mask) != 0)
620 Panic("bad alignment");
621
622 pvs_cluster_read(vs, (vm_offset_t)offset, length);
623
624 vs_finish_read(vs);
625
626 return KERN_SUCCESS;
627 }
628
629 /*
630 * memory_object_data_initialize: check whether we already have each page, and
631 * write it if we do not. The implementation is far from optimized, and
632 * also assumes that the default_pager is single-threaded.
633 */
634 /* It is questionable whether or not a pager should decide what is relevant */
635 /* and what is not in data sent from the kernel. Data initialize has been */
636 /* changed to copy back all data sent to it in preparation for its eventual */
637 /* merge with data return. It is the kernel that should decide what pages */
638 /* to write back. As of the writing of this note, this is indeed the case */
639 /* the kernel writes back one page at a time through this interface */
640
641 kern_return_t
642 dp_memory_object_data_initialize(
643 memory_object_t mem_obj,
644 memory_object_offset_t offset,
645 vm_size_t size)
646 {
647 vstruct_t vs;
648
649 DP_DEBUG(DEBUG_MO_EXTERNAL,
650 ("mem_obj=0x%x,offset=0x%x,cnt=0x%x\n",
651 (int)mem_obj, (int)offset, (int)size));
652 GSTAT(global_stats.gs_pages_init += atop_32(size));
653
654 vs_lookup(mem_obj, vs);
655 vs_lock(vs);
656 vs_start_write(vs);
657 vs_unlock(vs);
658
659 /*
660 * Write the data via clustered writes. vs_cluster_write will
661 * loop if the address range specified crosses cluster
662 * boundaries.
663 */
664 vs_cluster_write(vs, 0, (vm_offset_t)offset, size, FALSE, 0);
665
666 vs_finish_write(vs);
667
668 return KERN_SUCCESS;
669 }
670
671 kern_return_t
672 dp_memory_object_data_unlock(
673 __unused memory_object_t mem_obj,
674 __unused memory_object_offset_t offset,
675 __unused vm_size_t size,
676 __unused vm_prot_t desired_access)
677 {
678 Panic("dp_memory_object_data_unlock: illegal");
679 return KERN_FAILURE;
680 }
681
682
683 /*ARGSUSED8*/
684 kern_return_t
685 dp_memory_object_data_return(
686 memory_object_t mem_obj,
687 memory_object_offset_t offset,
688 vm_size_t size,
689 __unused memory_object_offset_t *resid_offset,
690 __unused int *io_error,
691 __unused boolean_t dirty,
692 __unused boolean_t kernel_copy,
693 __unused int upl_flags)
694 {
695 vstruct_t vs;
696
697 DP_DEBUG(DEBUG_MO_EXTERNAL,
698 ("mem_obj=0x%x,offset=0x%x,size=0x%x\n",
699 (int)mem_obj, (int)offset, (int)size));
700 GSTAT(global_stats.gs_pageout_calls++);
701
702 /* This routine is called by the pageout thread. The pageout thread */
703 /* cannot be blocked by read activities unless the read activities */
704 /* Therefore the grant of vs lock must be done on a try versus a */
705 /* blocking basis. The code below relies on the fact that the */
706 /* interface is synchronous. Should this interface be again async */
707 /* for some type of pager in the future the pages will have to be */
708 /* returned through a separate, asynchronous path. */
709
710 vs_lookup(mem_obj, vs);
711
712 default_pager_total++;
713 if(!VS_TRY_LOCK(vs)) {
714 /* the call below will not be done by caller when we have */
715 /* a synchronous interface */
716 /* return KERN_LOCK_OWNED; */
717 upl_t upl;
718 int page_list_count = 0;
719 memory_object_super_upl_request(vs->vs_control,
720 (memory_object_offset_t)offset,
721 size, size,
722 &upl, NULL, &page_list_count,
723 UPL_NOBLOCK | UPL_CLEAN_IN_PLACE
724 | UPL_NO_SYNC | UPL_COPYOUT_FROM);
725 upl_abort(upl,0);
726 upl_deallocate(upl);
727 return KERN_SUCCESS;
728 }
729
730 if ((vs->vs_seqno != vs->vs_next_seqno++)
731 || (vs->vs_readers)
732 || (vs->vs_xfer_pending)) {
733 upl_t upl;
734 int page_list_count = 0;
735
736 vs->vs_next_seqno--;
737 VS_UNLOCK(vs);
738
739 /* the call below will not be done by caller when we have */
740 /* a synchronous interface */
741 /* return KERN_LOCK_OWNED; */
742 memory_object_super_upl_request(vs->vs_control,
743 (memory_object_offset_t)offset,
744 size, size,
745 &upl, NULL, &page_list_count,
746 UPL_NOBLOCK | UPL_CLEAN_IN_PLACE
747 | UPL_NO_SYNC | UPL_COPYOUT_FROM);
748 upl_abort(upl,0);
749 upl_deallocate(upl);
750 return KERN_SUCCESS;
751 }
752
753 if ((size % vm_page_size) != 0)
754 Panic("bad alignment");
755
756 vs_start_write(vs);
757
758
759 vs->vs_async_pending += 1; /* protect from backing store contraction */
760 vs_unlock(vs);
761
762 /*
763 * Write the data via clustered writes. vs_cluster_write will
764 * loop if the address range specified crosses cluster
765 * boundaries.
766 */
767 vs_cluster_write(vs, 0, (vm_offset_t)offset, size, FALSE, 0);
768
769 vs_finish_write(vs);
770
771 /* temporary, need a finer lock based on cluster */
772
773 VS_LOCK(vs);
774 vs->vs_async_pending -= 1; /* release vs_async_wait */
775 if (vs->vs_async_pending == 0 && vs->vs_waiting_async) {
776 vs->vs_waiting_async = FALSE;
777 VS_UNLOCK(vs);
778 thread_wakeup(&vs->vs_async_pending);
779 } else {
780 VS_UNLOCK(vs);
781 }
782
783
784 return KERN_SUCCESS;
785 }
786
787 /*
788 * Routine: default_pager_memory_object_create
789 * Purpose:
790 * Handle requests for memory objects from the
791 * kernel.
792 * Notes:
793 * Because we only give out the default memory
794 * manager port to the kernel, we don't have to
795 * be so paranoid about the contents.
796 */
797 kern_return_t
798 default_pager_memory_object_create(
799 __unused memory_object_default_t dmm,
800 vm_size_t new_size,
801 memory_object_t *new_mem_obj)
802 {
803 vstruct_t vs;
804
805 assert(dmm == default_pager_object);
806
807 vs = vs_object_create(new_size);
808 if (vs == VSTRUCT_NULL)
809 return KERN_RESOURCE_SHORTAGE;
810
811 vs->vs_next_seqno = 0;
812
813 /*
814 * Set up associations between this memory object
815 * and this default_pager structure
816 */
817
818 vs->vs_mem_obj = ISVS;
819 vs->vs_mem_obj_ikot = IKOT_MEMORY_OBJECT;
820
821 /*
822 * After this, other threads might receive requests
823 * for this memory object or find it in the port list.
824 */
825
826 vstruct_list_insert(vs);
827 *new_mem_obj = vs_to_mem_obj(vs);
828 return KERN_SUCCESS;
829 }
830
831 /*
832 * Create an external object.
833 */
834 kern_return_t
835 default_pager_object_create(
836 default_pager_t default_pager,
837 vm_size_t size,
838 memory_object_t *mem_objp)
839 {
840 vstruct_t vs;
841
842 if (default_pager != default_pager_object)
843 return KERN_INVALID_ARGUMENT;
844
845 vs = vs_object_create(size);
846 if (vs == VSTRUCT_NULL)
847 return KERN_RESOURCE_SHORTAGE;
848
849 /*
850 * Set up associations between the default pager
851 * and this vstruct structure
852 */
853 vs->vs_mem_obj = ISVS;
854 vstruct_list_insert(vs);
855 *mem_objp = vs_to_mem_obj(vs);
856 return KERN_SUCCESS;
857 }
858
859 kern_return_t
860 default_pager_objects(
861 default_pager_t default_pager,
862 default_pager_object_array_t *objectsp,
863 mach_msg_type_number_t *ocountp,
864 mach_port_array_t *portsp,
865 mach_msg_type_number_t *pcountp)
866 {
867 vm_offset_t oaddr = 0; /* memory for objects */
868 vm_size_t osize = 0; /* current size */
869 default_pager_object_t * objects;
870 unsigned int opotential = 0;
871
872 vm_map_copy_t pcopy = 0; /* copy handle for pagers */
873 vm_size_t psize = 0; /* current size */
874 memory_object_t * pagers;
875 unsigned int ppotential = 0;
876
877 unsigned int actual;
878 unsigned int num_objects;
879 kern_return_t kr;
880 vstruct_t entry;
881
882 if (default_pager != default_pager_object)
883 return KERN_INVALID_ARGUMENT;
884
885 /*
886 * We will send no more than this many
887 */
888 actual = vstruct_list.vsl_count;
889
890 /*
891 * Out out-of-line port arrays are simply kalloc'ed.
892 */
893 psize = round_page(actual * sizeof * pagers);
894 ppotential = psize / sizeof * pagers;
895 pagers = (memory_object_t *)kalloc(psize);
896 if (0 == pagers)
897 return KERN_RESOURCE_SHORTAGE;
898
899 /*
900 * returned out of line data must be allocated out
901 * the ipc_kernel_map, wired down, filled in, and
902 * then "copied in" as if it had been sent by a
903 * user process.
904 */
905 osize = round_page(actual * sizeof * objects);
906 opotential = osize / sizeof * objects;
907 kr = kmem_alloc(ipc_kernel_map, &oaddr, osize);
908 if (KERN_SUCCESS != kr) {
909 kfree(pagers, psize);
910 return KERN_RESOURCE_SHORTAGE;
911 }
912 objects = (default_pager_object_t *)oaddr;
913
914
915 /*
916 * Now scan the list.
917 */
918
919 VSL_LOCK();
920
921 num_objects = 0;
922 queue_iterate(&vstruct_list.vsl_queue, entry, vstruct_t, vs_links) {
923
924 memory_object_t pager;
925 vm_size_t size;
926
927 if ((num_objects >= opotential) ||
928 (num_objects >= ppotential)) {
929
930 /*
931 * This should be rare. In any case,
932 * we will only miss recent objects,
933 * because they are added at the end.
934 */
935 break;
936 }
937
938 /*
939 * Avoid interfering with normal operations
940 */
941 if (!VS_MAP_TRY_LOCK(entry))
942 goto not_this_one;
943 size = ps_vstruct_allocated_size(entry);
944 VS_MAP_UNLOCK(entry);
945
946 VS_LOCK(entry);
947
948 /*
949 * We need a reference for our caller. Adding this
950 * reference through the linked list could race with
951 * destruction of the object. If we find the object
952 * has no references, just give up on it.
953 */
954 VS_LOCK(entry);
955 if (entry->vs_references == 0) {
956 VS_UNLOCK(entry);
957 goto not_this_one;
958 }
959 pager = vs_to_mem_obj(entry);
960 dp_memory_object_reference(pager);
961 VS_UNLOCK(entry);
962
963 /* the arrays are wired, so no deadlock worries */
964
965 objects[num_objects].dpo_object = (vm_offset_t) entry;
966 objects[num_objects].dpo_size = size;
967 pagers [num_objects++] = pager;
968 continue;
969
970 not_this_one:
971 /*
972 * Do not return garbage
973 */
974 objects[num_objects].dpo_object = (vm_offset_t) 0;
975 objects[num_objects].dpo_size = 0;
976 pagers[num_objects++] = MEMORY_OBJECT_NULL;
977
978 }
979
980 VSL_UNLOCK();
981
982 /* clear out any excess allocation */
983 while (num_objects < opotential) {
984 objects[--opotential].dpo_object = (vm_offset_t) 0;
985 objects[opotential].dpo_size = 0;
986 }
987 while (num_objects < ppotential) {
988 pagers[--ppotential] = MEMORY_OBJECT_NULL;
989 }
990
991 kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(oaddr),
992 vm_map_round_page(oaddr + osize), FALSE);
993 assert(KERN_SUCCESS == kr);
994 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)oaddr,
995 (vm_map_size_t)osize, TRUE, &pcopy);
996 assert(KERN_SUCCESS == kr);
997
998 *objectsp = (default_pager_object_array_t)objects;
999 *ocountp = num_objects;
1000 *portsp = (mach_port_array_t)pcopy;
1001 *pcountp = num_objects;
1002
1003 return KERN_SUCCESS;
1004 }
1005
1006 kern_return_t
1007 default_pager_object_pages(
1008 default_pager_t default_pager,
1009 mach_port_t memory_object,
1010 default_pager_page_array_t *pagesp,
1011 mach_msg_type_number_t *countp)
1012 {
1013 vm_offset_t addr = 0; /* memory for page offsets */
1014 vm_size_t size = 0; /* current memory size */
1015 vm_map_copy_t copy;
1016 default_pager_page_t * pages = 0;
1017 unsigned int potential;
1018 unsigned int actual;
1019 kern_return_t kr;
1020 memory_object_t object;
1021
1022 if (default_pager != default_pager_object)
1023 return KERN_INVALID_ARGUMENT;
1024
1025 object = (memory_object_t) memory_object;
1026
1027 potential = 0;
1028 for (;;) {
1029 vstruct_t entry;
1030
1031 VSL_LOCK();
1032 queue_iterate(&vstruct_list.vsl_queue, entry, vstruct_t,
1033 vs_links) {
1034 VS_LOCK(entry);
1035 if (vs_to_mem_obj(entry) == object) {
1036 VSL_UNLOCK();
1037 goto found_object;
1038 }
1039 VS_UNLOCK(entry);
1040 }
1041 VSL_UNLOCK();
1042
1043 /* did not find the object */
1044 if (0 != addr)
1045 kmem_free(ipc_kernel_map, addr, size);
1046
1047 return KERN_INVALID_ARGUMENT;
1048
1049 found_object:
1050
1051 if (!VS_MAP_TRY_LOCK(entry)) {
1052 /* oh well bad luck */
1053 int wresult;
1054
1055 VS_UNLOCK(entry);
1056
1057 assert_wait_timeout((event_t)assert_wait_timeout, THREAD_UNINT, 1, 1000*NSEC_PER_USEC);
1058 wresult = thread_block(THREAD_CONTINUE_NULL);
1059 assert(wresult == THREAD_TIMED_OUT);
1060 continue;
1061 }
1062
1063 actual = ps_vstruct_allocated_pages(entry, pages, potential);
1064 VS_MAP_UNLOCK(entry);
1065 VS_UNLOCK(entry);
1066
1067 if (actual <= potential)
1068 break;
1069
1070 /* allocate more memory */
1071 if (0 != addr)
1072 kmem_free(ipc_kernel_map, addr, size);
1073
1074 size = round_page(actual * sizeof * pages);
1075 kr = kmem_alloc(ipc_kernel_map, &addr, size);
1076 if (KERN_SUCCESS != kr)
1077 return KERN_RESOURCE_SHORTAGE;
1078
1079 pages = (default_pager_page_t *)addr;
1080 potential = size / sizeof * pages;
1081 }
1082
1083 /*
1084 * Clear unused memory.
1085 */
1086 while (actual < potential)
1087 pages[--potential].dpp_offset = 0;
1088
1089 kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(addr),
1090 vm_map_round_page(addr + size), FALSE);
1091 assert(KERN_SUCCESS == kr);
1092 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr,
1093 (vm_map_size_t)size, TRUE, &copy);
1094 assert(KERN_SUCCESS == kr);
1095
1096
1097 *pagesp = (default_pager_page_array_t)copy;
1098 *countp = actual;
1099 return KERN_SUCCESS;
1100 }