|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50:
51: /*
52: * Default Pager.
53: * Memory Object Management.
54: */
55:
56: #include "default_pager_internal.h"
57: #include <mach/memory_object_server.h>
58: #include <vm/vm_pageout.h> /* include for upl_t */
59:
60:
61: /*
62: * List of all vstructs. A specific vstruct is
63: * found directly via its port, this list is
64: * only used for monitoring purposes by the
65: * default_pager_object* calls and by ps_delete
66: * when abstract memory objects must be scanned
67: * to remove any live storage on a segment which
68: * is to be removed.
69: */
70: struct vstruct_list_head vstruct_list;
71:
72: void vstruct_list_insert(vstruct_t vs); /* forward */
73:
74: void
75: vstruct_list_insert(
76: vstruct_t vs)
77: {
78: VSL_LOCK();
79: queue_enter(&vstruct_list.vsl_queue, vs, vstruct_t, vs_links);
80: vstruct_list.vsl_count++;
81: VSL_UNLOCK();
82: }
83:
84: void vstruct_list_delete(vstruct_t vs); /* forward */
85:
86: void
87: vstruct_list_delete(
88: vstruct_t vs)
89: {
90: queue_remove(&vstruct_list.vsl_queue, vs, vstruct_t, vs_links);
91: vstruct_list.vsl_count--;
92: }
93:
94: /*
95: * We use the sequence numbers on requests to regulate
96: * our parallelism. In general, we allow multiple reads and writes
97: * to proceed in parallel, with the exception that reads must
98: * wait for previous writes to finish. (Because the kernel might
99: * generate a data-request for a page on the heels of a data-write
100: * for the same page, and we must avoid returning stale data.)
101: * terminate requests wait for proceeding reads and writes to finish.
102: */
103:
104: unsigned int default_pager_total = 0; /* debugging */
105: unsigned int default_pager_wait_seqno = 0; /* debugging */
106: unsigned int default_pager_wait_read = 0; /* debugging */
107: unsigned int default_pager_wait_write = 0; /* debugging */
108: unsigned int default_pager_wait_refs = 0; /* debugging */
109:
110: void vs_async_wait(vstruct_t); /* forward */
111:
112: void
113: vs_async_wait(
114: vstruct_t vs)
115: {
116: static char here[] = "vs_async_wait";
117:
118: ASSERT(vs->vs_async_pending >= 0);
119: while (vs->vs_async_pending > 0) {
120: vs->vs_waiting_async = TRUE;
121: assert_wait(&vs->vs_waiting_async, THREAD_UNINT);
122: VS_UNLOCK(vs);
123: thread_block((void (*)(void))0);
124: VS_LOCK(vs);
125: }
126: ASSERT(vs->vs_async_pending == 0);
127: }
128:
129: #if PARALLEL
130: void vs_lock(vstruct_t, mach_port_seqno_t);
131: void vs_unlock(vstruct_t);
132: void vs_start_read(vstruct_t);
133: void vs_wait_for_readers(vstruct_t);
134: void vs_finish_read(vstruct_t);
135: void vs_start_write(vstruct_t);
136: void vs_wait_for_writers(vstruct_t);
137: void vs_finish_write(vstruct_t);
138: void vs_wait_for_refs(vstruct_t);
139: void vs_finish_refs(vstruct_t);
140:
141: /*
142: * Waits for correct sequence number. Leaves pager locked.
143: * JMM - Sequence numbers guarantee ordering, but in a preemptible
144: * kernel, they are generated without locks, and so their
145: * generation order is undefined (and therefore unreliable).
146: * Since we ned to fix this anyway, and I needed to get rid
147: * rid of asymmetry in the interface definitions, I have
148: * punted this to here.
149: */
150: void
151: vs_lock(
152: vstruct_t vs,
153: mach_port_seqno_t seqno)
154: {
155: default_pager_total++;
156: VS_LOCK(vs);
157:
158: seqno = vs->vs_next_seqno++;
159:
160: while (vs->vs_seqno != seqno) {
161: default_pager_wait_seqno++;
162: vs->vs_waiting_seqno = TRUE;
163: assert_wait(&vs->vs_waiting_seqno, THREAD_UNINT);
164: VS_UNLOCK(vs);
165: thread_block((void (*)(void))0);
166: VS_LOCK(vs);
167: }
168: }
169:
170: /*
171: * Increments sequence number and unlocks pager.
172: */
173: void
174: vs_unlock(vstruct_t vs)
175: {
176: boolean_t need_wakeups = vs->vs_waiting_seqno;
177:
178: vs->vs_waiting_seqno = FALSE;
179: vs->vs_seqno++;
180: VS_UNLOCK(vs);
181: if (need_wakeups)
182: thread_wakeup(&vs->vs_waiting_seqno);
183: }
184:
185: /*
186: * Start a read - one more reader. Pager must be locked.
187: */
188: void
189: vs_start_read(
190: vstruct_t vs)
191: {
192: vs->vs_readers++;
193: }
194:
195: /*
196: * Wait for readers. Unlocks and relocks pager if wait needed.
197: */
198: void
199: vs_wait_for_readers(
200: vstruct_t vs)
201: {
202: while (vs->vs_readers != 0) {
203: default_pager_wait_read++;
204: vs->vs_waiting_read = TRUE;
205: assert_wait(&vs->vs_waiting_read, THREAD_UNINT);
206: VS_UNLOCK(vs);
207: thread_block((void (*)(void))0);
208: VS_LOCK(vs);
209: }
210: }
211:
212: /*
213: * Finish a read. Pager is unlocked and returns unlocked.
214: */
215: void
216: vs_finish_read(
217: vstruct_t vs)
218: {
219: VS_LOCK(vs);
220: if (--vs->vs_readers == 0) {
221: boolean_t need_wakeups = vs->vs_waiting_read;
222:
223: vs->vs_waiting_read = FALSE;
224: VS_UNLOCK(vs);
225: if (need_wakeups)
226: thread_wakeup(&vs->vs_waiting_read);
227: } else
228: VS_UNLOCK(vs);
229: }
230:
231: /*
232: * Start a write - one more writer. Pager must be locked.
233: */
234: void
235: vs_start_write(
236: vstruct_t vs)
237: {
238: vs->vs_writers++;
239: }
240:
241: /*
242: * Wait for writers. Unlocks and relocks pager if wait needed.
243: */
244: void
245: vs_wait_for_writers(
246: vstruct_t vs)
247: {
248: while (vs->vs_writers != 0) {
249: default_pager_wait_write++;
250: vs->vs_waiting_write = TRUE;
251: assert_wait(&vs->vs_waiting_write, THREAD_UNINT);
252: VS_UNLOCK(vs);
253: thread_block((void (*)(void))0);
254: VS_LOCK(vs);
255: }
256: vs_async_wait(vs);
257: }
258:
259: /* This is to be used for the transfer from segment code ONLY */
260: /* The transfer code holds off vs destruction by keeping the */
261: /* vs_async_wait count non-zero. It will not ocnflict with */
262: /* other writers on an async basis because it only writes on */
263: /* a cluster basis into fresh (as of sync time) cluster locations */
264: void
265: vs_wait_for_sync_writers(
266: vstruct_t vs)
267: {
268: while (vs->vs_writers != 0) {
269: default_pager_wait_write++;
270: vs->vs_waiting_write = TRUE;
271: assert_wait(&vs->vs_waiting_write, THREAD_UNINT);
272: VS_UNLOCK(vs);
273: thread_block((void (*)(void))0);
274: VS_LOCK(vs);
275: }
276: }
277:
278:
279: /*
280: * Finish a write. Pager is unlocked and returns unlocked.
281: */
282: void
283: vs_finish_write(
284: vstruct_t vs)
285: {
286: VS_LOCK(vs);
287: if (--vs->vs_writers == 0) {
288: boolean_t need_wakeups = vs->vs_waiting_write;
289:
290: vs->vs_waiting_write = FALSE;
291: VS_UNLOCK(vs);
292: if (need_wakeups)
293: thread_wakeup(&vs->vs_waiting_write);
294: } else
295: VS_UNLOCK(vs);
296: }
297:
298: /*
299: * Wait for concurrent default_pager_objects.
300: * Unlocks and relocks pager if wait needed.
301: */
302: void
303: vs_wait_for_refs(
304: vstruct_t vs)
305: {
306: while (vs->vs_name_refs == 0) {
307: default_pager_wait_refs++;
308: vs->vs_waiting_refs = TRUE;
309: assert_wait(&vs->vs_waiting_refs, THREAD_UNINT);
310: VS_UNLOCK(vs);
311: thread_block((void (*)(void))0);
312: VS_LOCK(vs);
313: }
314: }
315:
316: /*
317: * Finished creating name refs - wake up waiters.
318: */
319: void
320: vs_finish_refs(
321: vstruct_t vs)
322: {
323: boolean_t need_wakeups = vs->vs_waiting_refs;
324: vs->vs_waiting_refs = FALSE;
325: if (need_wakeups)
326: thread_wakeup(&vs->vs_waiting_refs);
327: }
328:
329: #else /* PARALLEL */
330:
331: #define vs_lock(vs,seqno)
332: #define vs_unlock(vs)
333: #define vs_start_read(vs)
334: #define vs_wait_for_readers(vs)
335: #define vs_finish_read(vs)
336: #define vs_start_write(vs)
337: #define vs_wait_for_writers(vs)
338: #define vs_wait_for_sync_writers(vs)
339: #define vs_finish_write(vs)
340: #define vs_wait_for_refs(vs)
341: #define vs_finish_refs(vs)
342:
343: #endif /* PARALLEL */
344:
345: vstruct_t vs_object_create(vm_size_t); /* forward */
346:
347: vstruct_t
348: vs_object_create(
349: vm_size_t size)
350: {
351: vstruct_t vs;
352: static char here[] = "vs_object_create";
353:
354: /*
355: * Allocate a vstruct. If there are any problems, then report them
356: * to the console.
357: */
358: vs = ps_vstruct_create(size);
359: if (vs == VSTRUCT_NULL) {
360: dprintf(("vs_object_create: unable to allocate %s\n",
361: "-- either run swapon command or reboot"));
362: return VSTRUCT_NULL;
363: }
364:
365: return vs;
366: }
367:
368: mach_port_urefs_t default_pager_max_urefs = 10000;
369:
370: /*
371: * Check user reference count on memory object control port.
372: * Vstruct must be locked.
373: * Unlocks and re-locks vstruct if needs to call kernel.
374: */
375: void vs_check_request(vstruct_t, MACH_PORT_FACE); /* forward */
376:
377: void
378: vs_check_request(
379: vstruct_t vs,
380: MACH_PORT_FACE control_port)
381: {
382: mach_port_delta_t delta;
383: kern_return_t kr;
384: static char here[] = "vs_check_request";
385:
386: if (++vs->vs_control_refs > default_pager_max_urefs) {
387: delta = 1 - vs->vs_control_refs;
388: vs->vs_control_refs = 1;
389:
390: VS_UNLOCK(vs);
391:
392: /*
393: * Deallocate excess user references.
394: */
395:
396: {
397: /* find a better interface for this, what will we use as a component */
398: int i;
399: delta = -delta;
400: for(i=0; i<delta; i++)
401: ipc_port_release_send(control_port);
402: }
403:
404: VS_LOCK(vs);
405: }
406: }
407:
408: void default_pager_add(vstruct_t, boolean_t); /* forward */
409:
410: void
411: default_pager_add(
412: vstruct_t vs,
413: boolean_t internal)
414: {
415: MACH_PORT_FACE mem_obj = vs->vs_mem_obj_port;
416: MACH_PORT_FACE pset;
417: mach_port_mscount_t sync;
418: MACH_PORT_FACE previous;
419: kern_return_t kr;
420: static char here[] = "default_pager_add";
421:
422: /*
423: * The port currently has a make-send count of zero,
424: * because either we just created the port or we just
425: * received the port in a memory_object_create request.
426: */
427:
428: if (internal) {
429: /* possibly generate an immediate no-senders notification */
430: sync = 0;
431: pset = default_pager_internal_set;
432: } else {
433: /* delay notification till send right is created */
434: sync = 1;
435: pset = default_pager_external_set;
436: }
437:
438: ipc_port_make_sonce(mem_obj);
439: ip_lock(mem_obj); /* unlocked in nsrequest below */
440: ipc_port_nsrequest(mem_obj, sync, mem_obj, &previous);
441: }
442:
443:
444: /*
445: * Routine: dp_memory_object_create
446: * Purpose:
447: * Handle requests for memory objects from the
448: * kernel.
449: * Notes:
450: * Because we only give out the default memory
451: * manager port to the kernel, we don't have to
452: * be so paranoid about the contents.
453: */
454: kern_return_t
455: dp_memory_object_create(
456: MACH_PORT_FACE dmm,
457: MACH_PORT_FACE *new_mem_obj,
458: vm_size_t new_size)
459: {
460: mach_port_seqno_t seqno;
461: vstruct_t vs;
462: MACH_PORT_FACE pager;
463: static char here[] = "memory_object_create";
464:
465: assert(dmm == default_pager_default_port);
466:
467: vs = vs_object_create(new_size);
468: if (vs == VSTRUCT_NULL)
469: return KERN_RESOURCE_SHORTAGE;
470:
471: pager = *new_mem_obj = ipc_port_alloc_kernel();
472: assert (pager != IP_NULL);
473: (void) ipc_port_make_send(pager);
474:
475: {
476: struct vstruct_alias *alias_struct;
477:
478: alias_struct = (struct vstruct_alias *)
479: kalloc(sizeof(struct vstruct_alias));
480: if(alias_struct != NULL) {
481: alias_struct->vs = vs;
482: alias_struct->name = ISVS;
483: pager->alias = (int) alias_struct;
484: }
485: else Panic("Out of kernel memory");
486:
487: /* JMM - Add binding to this pager under components */
488: pager_mux_hash_insert(pager, &dp_memory_object_subsystem);
489: vs->vs_next_seqno = 0;
490: pager->ip_receiver = ipc_space_kernel;
491: }
492:
493: /*
494: * Set up associations between this port
495: * and this default_pager structure
496: */
497:
498: vs->vs_mem_obj_port = pager;
499:
500: /*
501: * After this, other threads might receive requests
502: * for this memory object or find it in the port list.
503: */
504:
505: vstruct_list_insert(vs);
506: default_pager_add(vs, TRUE);
507:
508: return KERN_SUCCESS;
509: }
510:
511: kern_return_t
512: dp_memory_object_init(
513: MACH_PORT_FACE mem_obj,
514: MACH_PORT_FACE control_port,
515: vm_size_t pager_page_size)
516: {
517: mach_port_seqno_t seqno;
518: vstruct_t vs;
519: static char here[] = "memory_object_init";
520:
521: assert(pager_page_size == vm_page_size);
522:
523: vs_lookup(mem_obj, vs);
524: vs_lock(vs, seqno);
525:
526: if (vs->vs_control_port != MACH_PORT_NULL)
527: Panic("bad request");
528:
529: vs->vs_control_port = control_port;
530: vs->vs_control_refs = 1;
531: vs->vs_object_name = MACH_PORT_NULL;
532: vs->vs_name_refs = 1;
533:
534: vs_unlock(vs);
535:
536: return KERN_SUCCESS;
537: }
538:
539: kern_return_t
540: dp_memory_object_synchronize(
541: MACH_PORT_FACE mem_obj,
542: MACH_PORT_FACE control_port,
543: vm_offset_t offset,
544: vm_offset_t length,
545: vm_sync_t flags)
546: {
547: mach_port_seqno_t seqno;
548: vstruct_t vs;
549: static char here[] = "memory_object_synchronize";
550:
551: vs_lookup(mem_obj, vs);
552: vs_lock(vs, seqno);
553: vs_check_request(vs, control_port);
554: vs_unlock(vs);
555:
556: memory_object_synchronize_completed(
557: vm_object_lookup(control_port),
558: offset, length);
559:
560: return KERN_SUCCESS;
561: }
562:
563: kern_return_t
564: dp_memory_object_terminate(
565: MACH_PORT_FACE mem_obj,
566: MACH_PORT_FACE control_port)
567: {
568: mach_port_seqno_t seqno;
569: vstruct_t vs;
570: mach_port_urefs_t request_refs;
571: kern_return_t kr;
572: static char here[] = "memory_object_terminate";
573:
574: /*
575: * control port is a receive right, not a send right.
576: */
577:
578: vs_lookup(mem_obj, vs);
579: vs_lock(vs, seqno);
580:
581: /*
582: * Wait for read and write requests to terminate.
583: */
584:
585: vs_wait_for_readers(vs);
586: vs_wait_for_writers(vs);
587:
588: /*
589: * After memory_object_terminate both memory_object_init
590: * and a no-senders notification are possible, so we need
591: * to clean up the request and name ports but leave
592: * the mem_obj port.
593: *
594: * A concurrent default_pager_objects might be allocating
595: * more references for the name port. In this case,
596: * we must first wait for it to finish.
597: */
598:
599: vs_wait_for_refs(vs);
600:
601: vs->vs_control_port = MACH_PORT_NULL;
602:
603: /* a bit of special case ugliness here. Wakeup any waiting reads */
604: /* these data requests had to be removed from the seqno traffic */
605: /* based on a performance bottleneck with large memory objects */
606: /* the problem will right itself with the new component based */
607: /* synchronous interface. The new async will be able to return */
608: /* failure during its sync phase. In the mean time ... */
609:
610: thread_wakeup(&vs->vs_waiting_write);
611: thread_wakeup(&vs->vs_waiting_async);
612:
613: request_refs = vs->vs_control_refs;
614: vs->vs_control_refs = 0;
615:
616: vs->vs_object_name = MACH_PORT_NULL;
617:
618: assert(vs->vs_name_refs != 0);
619: vs->vs_name_refs = 0;
620:
621: vs_unlock(vs);
622:
623: /*
624: * Now we deallocate our various port rights.
625: */
626:
627: {
628: int i;
629: for(i=0; i<request_refs; i++)
630: ipc_port_release_send(control_port);
631: }
632: if(control_port->alias != (int)NULL)
633: kfree((vm_offset_t) (control_port->alias),
634: sizeof(struct vstruct_alias));
635: ipc_port_release_receive(control_port);
636: return KERN_SUCCESS;
637: }
638:
639: void
640: default_pager_no_senders(
641: MACH_PORT_FACE mem_obj,
642: mach_port_seqno_t seqno,
643: mach_port_mscount_t mscount)
644: {
645: vstruct_t vs;
646: static char here[] = "default_pager_no_senders";
647:
648: /*
649: * Because we don't give out multiple send rights
650: * for a memory object, there can't be a race
651: * between getting a no-senders notification
652: * and creating a new send right for the object.
653: * Hence we don't keep track of mscount.
654: */
655:
656: vs_lookup(mem_obj, vs);
657: vs_lock(vs, seqno);
658: vs_async_wait(vs); /* wait for pending async IO */
659:
660: /* do not delete the vs structure until the referencing pointers */
661: /* in the vstruct list have been expunged */
662:
663: /* get VSL_LOCK out of order by using TRY mechanism */
664: while(!VSL_LOCK_TRY()) {
665: VS_UNLOCK(vs);
666: VSL_LOCK();
667: VSL_UNLOCK();
668: VS_LOCK(vs);
669: vs_async_wait(vs); /* wait for pending async IO */
670: }
671: /*
672: * We shouldn't get a no-senders notification
673: * when the kernel has the object cached.
674: */
675: if (vs->vs_control_port != MACH_PORT_NULL)
676: Panic("bad request");
677:
678: /*
679: * Unlock the pager (though there should be no one
680: * waiting for it).
681: */
682: VS_UNLOCK(vs);
683:
684: /*
685: * Remove the memory object port association, and then
686: * the destroy the port itself. We must remove the object
687: * from the port list before deallocating the pager,
688: * because of default_pager_objects.
689: */
690: vstruct_list_delete(vs);
691: ps_vstruct_dealloc(vs);
692:
693: /*
694: * Recover memory that we might have wasted because
695: * of name conflicts
696: */
697: while (!queue_empty(&vstruct_list.vsl_leak_queue)) {
698: vs = (vstruct_t) queue_first(&vstruct_list.vsl_leak_queue);
699: queue_remove_first(&vstruct_list.vsl_leak_queue, vs, vstruct_t,
700: vs_links);
701: kfree((vm_offset_t) vs, sizeof *vs);
702: }
703: VSL_UNLOCK();
704: }
705:
706: kern_return_t
707: dp_memory_object_data_request(
708: MACH_PORT_FACE mem_obj,
709: MACH_PORT_FACE reply_to,
710: vm_offset_t offset,
711: vm_size_t length,
712: vm_prot_t protection_required)
713: {
714: mach_port_seqno_t seqno;
715: vstruct_t vs;
716: static char here[] = "memory_object_data_request";
717:
718: GSTAT(global_stats.gs_pagein_calls++);
719:
720:
721: /* CDY at this moment vs_lookup panics when presented with the wrong */
722: /* port. As we are expanding this pager to support user interfaces */
723: /* this should be changed to return kern_failure */
724: vs_lookup(mem_obj, vs);
725: vs_lock(vs, seqno);
726: vs_check_request(vs, reply_to);
727:
728: /* We are going to relax the strict sequencing here for performance */
729: /* reasons. We can do this because we know that the read and */
730: /* write threads are different and we rely on synchronization */
731: /* of read and write requests at the cache memory_object level */
732: /* break out wait_for_writers, all of this goes away when */
733: /* we get real control of seqno with the new component interface */
734: if (vs->vs_writers != 0) {
735: /* you can't hold on to the seqno and go */
736: /* to sleep like that */
737: vs_unlock(vs); /* bump internal count of seqno */
738: VS_LOCK(vs);
739: while (vs->vs_writers != 0) {
740: default_pager_wait_write++;
741: vs->vs_waiting_write = TRUE;
742: assert_wait(&vs->vs_waiting_write, THREAD_UNINT);
743: VS_UNLOCK(vs);
744: thread_block((void (*)(void))0);
745: VS_LOCK(vs);
746: vs_async_wait(vs);
747: }
748: if(vs->vs_control_port == MACH_PORT_NULL) {
749: VS_UNLOCK(vs);
750: return KERN_FAILURE;
751: }
752: vs_start_read(vs);
753: VS_UNLOCK(vs);
754: } else {
755: vs_start_read(vs);
756: vs_unlock(vs);
757: }
758:
759: /*
760: * Request must be on a page boundary and a multiple of pages.
761: */
762: if ((offset & vm_page_mask) != 0 || (length & vm_page_mask) != 0)
763: Panic("bad alignment");
764:
765: pvs_cluster_read(vs, offset, length);
766:
767: vs_finish_read(vs);
768:
769: return KERN_SUCCESS;
770: }
771:
772: /*
773: * memory_object_data_initialize: check whether we already have each page, and
774: * write it if we do not. The implementation is far from optimized, and
775: * also assumes that the default_pager is single-threaded.
776: */
777: /* It is questionable whether or not a pager should decide what is relevant */
778: /* and what is not in data sent from the kernel. Data initialize has been */
779: /* changed to copy back all data sent to it in preparation for its eventual */
780: /* merge with data return. It is the kernel that should decide what pages */
781: /* to write back. As of the writing of this note, this is indeed the case */
782: /* the kernel writes back one page at a time through this interface */
783:
784: kern_return_t
785: dp_memory_object_data_initialize(
786: MACH_PORT_FACE mem_obj,
787: MACH_PORT_FACE control_port,
788: vm_offset_t offset,
789: pointer_t addr,
790: vm_size_t data_cnt)
791: {
792: mach_port_seqno_t seqno;
793: vstruct_t vs;
794: static char here[] = "memory_object_data_initialize";
795:
796: #ifdef lint
797: control_port++;
798: #endif /* lint */
799:
800: DEBUG(DEBUG_MO_EXTERNAL,
801: ("mem_obj=0x%x,offset=0x%x,cnt=0x%x\n",
802: (int)mem_obj, (int)offset, (int)data_cnt));
803: GSTAT(global_stats.gs_pages_init += atop(data_cnt));
804:
805: vs_lookup(mem_obj, vs);
806: vs_lock(vs, seqno);
807: vs_check_request(vs, control_port);
808: vs_start_write(vs);
809: vs_unlock(vs);
810:
811: /*
812: * Write the data via clustered writes. vs_cluster_write will
813: * loop if the address range specified crosses cluster
814: * boundaries.
815: */
816: vs_cluster_write(vs, offset, addr, data_cnt, FALSE);
817:
818: vs_finish_write(vs);
819:
820: return KERN_SUCCESS;
821: }
822:
823: kern_return_t
824: dp_memory_object_lock_completed(
825: memory_object_t mem_obj,
826: MACH_PORT_FACE control_port,
827: vm_offset_t offset,
828: vm_size_t length)
829: {
830: mach_port_seqno_t seqno;
831: static char here[] = "memory_object_lock_completed";
832:
833: #ifdef lint
834: mem_obj++;
835: seqno++;
836: control_port++;
837: offset++;
838: length++;
839: #endif /* lint */
840:
841: Panic("illegal");
842: return KERN_FAILURE;
843: }
844:
845: kern_return_t
846: dp_memory_object_data_unlock(
847: memory_object_t mem_obj,
848: MACH_PORT_FACE control_port,
849: vm_offset_t offset,
850: vm_size_t data_cnt,
851: vm_prot_t desired_access)
852: {
853: static char here[] = "memory_object_data_unlock";
854:
855: Panic("illegal");
856: return KERN_FAILURE;
857: }
858:
859:
860: kern_return_t
861: dp_memory_object_supply_completed(
862: memory_object_t mem_obj,
863: MACH_PORT_FACE control_port,
864: vm_offset_t offset,
865: vm_size_t length,
866: kern_return_t result,
867: vm_offset_t error_offset)
868: {
869: static char here[] = "memory_object_supply_completed";
870:
871: Panic("illegal");
872: return KERN_FAILURE;
873: }
874:
875: kern_return_t
876: dp_memory_object_data_return(
877: MACH_PORT_FACE mem_obj,
878: MACH_PORT_FACE control_port,
879: vm_offset_t offset,
880: pointer_t addr,
881: vm_size_t data_cnt,
882: boolean_t dirty,
883: boolean_t kernel_copy)
884: {
885: mach_port_seqno_t seqno;
886: vstruct_t vs;
887: vm_offset_t pageout_address;
888: static char here[] = "memory_object_data_return";
889:
890: #ifdef lint
891: control_port++;
892: dirty++;
893: kernel_copy++;
894: #endif /* lint */
895:
896: DEBUG(DEBUG_MO_EXTERNAL,
897: ("mem_obj=0x%x,offset=0x%x,addr=0x%xcnt=0x%x\n",
898: (int)mem_obj, (int)offset, (int)addr, (int)data_cnt));
899: GSTAT(global_stats.gs_pageout_calls++);
900:
901: /* This routine is called by the pageout thread. The pageout thread */
902: /* cannot be blocked by read activities unless the read activities */
903: /* Therefore the grant of vs lock must be done on a try versus a */
904: /* blocking basis. The code below relies on the fact that the */
905: /* interface is synchronous. Should this interface be again async */
906: /* for some type of pager in the future the pages will have to be */
907: /* returned through a separate, asynchronous path. */
908:
909: vs_lookup(mem_obj, vs);
910:
911: default_pager_total++;
912: if(!VS_TRY_LOCK(vs)) {
913: /* the call below will not be done by caller when we have */
914: /* a synchronous interface */
915: /* return KERN_LOCK_OWNED; */
916: upl_t page_list;
917: upl_system_list_request((vm_object_t)
918: vs->vs_control_port->ip_kobject,
919: offset, data_cnt, data_cnt, &page_list, NULL, 0,
920: UPL_NOBLOCK | UPL_CLEAN_IN_PLACE |
921: UPL_NO_SYNC | UPL_COPYOUT_FROM);
922:
923: upl_abort(page_list,0);
924: return KERN_SUCCESS;
925: }
926:
927:
928:
929: if ((vs->vs_seqno != vs->vs_next_seqno++) || (vs->vs_xfer_pending)) {
930: upl_t page_list;
931: vs->vs_next_seqno--;
932: VS_UNLOCK(vs);
933: /* the call below will not be done by caller when we have */
934: /* a synchronous interface */
935: /* return KERN_LOCK_OWNED; */
936: upl_system_list_request((vm_object_t)
937: vs->vs_control_port->ip_kobject,
938: offset, data_cnt, data_cnt, &page_list, NULL, 0,
939: UPL_NOBLOCK | UPL_CLEAN_IN_PLACE |
940: UPL_NO_SYNC | UPL_COPYOUT_FROM);
941: upl_abort(page_list,0);
942: return KERN_SUCCESS;
943: }
944:
945: if ((data_cnt % vm_page_size) != 0)
946: Panic("bad alignment");
947:
948: /*
949: vs_check_request(vs, control_port);
950: */
951: vs_start_write(vs);
952: vs_unlock(vs);
953:
954: /*
955: * Write the data via clustered writes. vs_cluster_write will
956: * loop if the address range specified crosses cluster
957: * boundaries.
958: */
959: vs_cluster_write(vs, offset, addr, data_cnt, FALSE);
960:
961: vs_finish_write(vs);
962:
963: return KERN_SUCCESS;
964: }
965:
966: kern_return_t
967: dp_memory_object_discard_request(
968: memory_object_t mem_obj,
969: memory_object_control_t memory_control,
970: vm_offset_t offset,
971: vm_size_t length)
972: {
973: panic("illegal");
974: return KERN_FAILURE;
975: }
976:
977: kern_return_t
978: dp_memory_object_change_completed(
979: memory_object_t mem_obj,
980: memory_object_control_t memory_control,
981: memory_object_flavor_t flavor)
982: {
983: static char here[] = "memory_object_change_completed";
984:
985: Panic("illegal");
986: return KERN_FAILURE;
987: }
988:
989: /*
990: * Create an external object.
991: */
992: kern_return_t
993: default_pager_object_create(
994: MACH_PORT_FACE pager,
995: MACH_PORT_FACE *mem_obj,
996: vm_size_t size)
997: {
998: vstruct_t vs;
999: MACH_PORT_FACE port;
1000: kern_return_t result;
1001: struct vstruct_alias *alias_struct;
1002: static char here[] = "default_pager_object_create";
1003:
1004:
1005: if (pager != default_pager_default_port)
1006: return KERN_INVALID_ARGUMENT;
1007:
1008: vs = vs_object_create(size);
1009:
1010: port = ipc_port_alloc_kernel();
1011: ipc_port_make_send(port);
1012: /* register abstract memory object port with pager mux routine */
1013: /* (directs kernel internal calls to the right pager). */
1014: alias_struct = (struct vstruct_alias *)
1015: kalloc(sizeof(struct vstruct_alias));
1016: if(alias_struct != NULL) {
1017: alias_struct->vs = vs;
1018: alias_struct->name = ISVS;
1019: port->alias = (int) alias_struct;
1020: }
1021: else Panic("Out of kernel memory");
1022:
1023: /*
1024: * Set up associations between these ports
1025: * and this vstruct structure
1026: */
1027:
1028: vs->vs_mem_obj_port = port;
1029: vstruct_list_insert(vs);
1030: default_pager_add(vs, FALSE);
1031:
1032: *mem_obj = port;
1033:
1034: return KERN_SUCCESS;
1035: }
1036:
1037: kern_return_t
1038: default_pager_objects(
1039: MACH_PORT_FACE pager,
1040: default_pager_object_array_t *objectsp,
1041: mach_msg_type_number_t *ocountp,
1042: mach_port_array_t *portsp,
1043: mach_msg_type_number_t *pcountp)
1044: {
1045: vm_offset_t oaddr = 0; /* memory for objects */
1046: vm_size_t osize = 0; /* current size */
1047: default_pager_object_t * objects;
1048: unsigned int opotential;
1049:
1050: vm_offset_t paddr = 0; /* memory for ports */
1051: vm_size_t psize = 0; /* current size */
1052: MACH_PORT_FACE * ports;
1053: unsigned int ppotential;
1054:
1055: unsigned int actual;
1056: unsigned int num_objects;
1057: kern_return_t kr;
1058: vstruct_t entry;
1059: static char here[] = "default_pager_objects";
1060: /*
1061: if (pager != default_pager_default_port)
1062: return KERN_INVALID_ARGUMENT;
1063: */
1064:
1065: /* start with the inline memory */
1066:
1067: kr = vm_map_copyout(ipc_kernel_map, (vm_offset_t *)&objects,
1068: (vm_map_copy_t) *objectsp);
1069:
1070: if (kr != KERN_SUCCESS)
1071: return kr;
1072:
1073: osize = round_page(*ocountp * sizeof * objects);
1074: kr = vm_map_wire(ipc_kernel_map,
1075: trunc_page((vm_offset_t)objects),
1076: round_page(((vm_offset_t)objects) + osize),
1077: VM_PROT_READ|VM_PROT_WRITE, FALSE);
1078: osize=0;
1079:
1080: *objectsp = objects;
1081: /* we start with the inline space */
1082:
1083:
1084: num_objects = 0;
1085: opotential = *ocountp;
1086:
1087: ports = (MACH_PORT_FACE *) *portsp;
1088: ppotential = *pcountp;
1089:
1090: VSL_LOCK();
1091:
1092: /*
1093: * We will send no more than this many
1094: */
1095: actual = vstruct_list.vsl_count;
1096: VSL_UNLOCK();
1097:
1098: if (opotential < actual) {
1099: vm_offset_t newaddr;
1100: vm_size_t newsize;
1101:
1102: newsize = 2 * round_page(actual * sizeof * objects);
1103:
1104: kr = vm_allocate(kernel_map, &newaddr, newsize, TRUE);
1105: if (kr != KERN_SUCCESS)
1106: goto nomemory;
1107:
1108: oaddr = newaddr;
1109: osize = newsize;
1110: opotential = osize / sizeof * objects;
1111: objects = (default_pager_object_t *)oaddr;
1112: }
1113:
1114: if (ppotential < actual) {
1115: vm_offset_t newaddr;
1116: vm_size_t newsize;
1117:
1118: newsize = 2 * round_page(actual * sizeof * ports);
1119:
1120: kr = vm_allocate(kernel_map, &newaddr, newsize, TRUE);
1121: if (kr != KERN_SUCCESS)
1122: goto nomemory;
1123:
1124: paddr = newaddr;
1125: psize = newsize;
1126: ppotential = psize / sizeof * ports;
1127: ports = (MACH_PORT_FACE *)paddr;
1128: }
1129:
1130: /*
1131: * Now scan the list.
1132: */
1133:
1134: VSL_LOCK();
1135:
1136: num_objects = 0;
1137: queue_iterate(&vstruct_list.vsl_queue, entry, vstruct_t, vs_links) {
1138:
1139: MACH_PORT_FACE port;
1140: vm_size_t size;
1141:
1142: if ((num_objects >= opotential) ||
1143: (num_objects >= ppotential)) {
1144:
1145: /*
1146: * This should be rare. In any case,
1147: * we will only miss recent objects,
1148: * because they are added at the end.
1149: */
1150: break;
1151: }
1152:
1153: /*
1154: * Avoid interfering with normal operations
1155: */
1156: if (!VS_MAP_TRY_LOCK(entry))
1157: goto not_this_one;
1158: size = ps_vstruct_allocated_size(entry);
1159: VS_MAP_UNLOCK(entry);
1160:
1161: VS_LOCK(entry);
1162:
1163: port = entry->vs_object_name;
1164: if (port == MACH_PORT_NULL) {
1165:
1166: /*
1167: * The object is waiting for no-senders
1168: * or memory_object_init.
1169: */
1170: VS_UNLOCK(entry);
1171: goto not_this_one;
1172: }
1173:
1174: /*
1175: * We need a reference for the reply message.
1176: * While we are unlocked, the bucket queue
1177: * can change and the object might be terminated.
1178: * memory_object_terminate will wait for us,
1179: * preventing deallocation of the entry.
1180: */
1181:
1182: if (--entry->vs_name_refs == 0) {
1183: VS_UNLOCK(entry);
1184:
1185: /* keep the list locked, wont take long */
1186:
1187: {
1188: int i;
1189: for(i=0; i<default_pager_max_urefs; i++)
1190: ipc_port_make_send(port);
1191: }
1192: VS_LOCK(entry);
1193:
1194: entry->vs_name_refs += default_pager_max_urefs;
1195: vs_finish_refs(entry);
1196: }
1197: VS_UNLOCK(entry);
1198:
1199: /* the arrays are wired, so no deadlock worries */
1200:
1201: objects[num_objects].dpo_object = (vm_offset_t) entry;
1202: objects[num_objects].dpo_size = size;
1203: ports [num_objects++] = port;
1204: continue;
1205:
1206: not_this_one:
1207: /*
1208: * Do not return garbage
1209: */
1210: objects[num_objects].dpo_object = (vm_offset_t) 0;
1211: objects[num_objects].dpo_size = 0;
1212: ports [num_objects++] = MACH_PORT_NULL;
1213:
1214: }
1215:
1216: VSL_UNLOCK();
1217:
1218: /*
1219: * Deallocate and clear unused memory.
1220: * (Returned memory will automagically become pageable.)
1221: */
1222:
1223: if (objects == *objectsp) {
1224:
1225: /*
1226: * Our returned information fit inline.
1227: * Nothing to deallocate.
1228: */
1229: *ocountp = num_objects;
1230: } else if (actual == 0) {
1231: (void) vm_deallocate(kernel_map, oaddr, osize);
1232:
1233: /* return zero items inline */
1234: *ocountp = 0;
1235: } else {
1236: vm_offset_t used;
1237:
1238: used = round_page(actual * sizeof * objects);
1239:
1240: if (used != osize)
1241: (void) vm_deallocate(kernel_map,
1242: oaddr + used, osize - used);
1243:
1244: *objectsp = objects;
1245: *ocountp = num_objects;
1246: }
1247:
1248: if (ports == (MACH_PORT_FACE *)*portsp) {
1249:
1250: /*
1251: * Our returned information fit inline.
1252: * Nothing to deallocate.
1253: */
1254:
1255: *pcountp = num_objects;
1256: } else if (actual == 0) {
1257: (void) vm_deallocate(kernel_map, paddr, psize);
1258:
1259: /* return zero items inline */
1260: *pcountp = 0;
1261: } else {
1262: vm_offset_t used;
1263:
1264: used = round_page(actual * sizeof * ports);
1265:
1266: if (used != psize)
1267: (void) vm_deallocate(kernel_map,
1268: paddr + used, psize - used);
1269:
1270: *portsp = (mach_port_array_t)ports;
1271: *pcountp = num_objects;
1272: }
1273: (void) vm_map_unwire(kernel_map, (vm_offset_t)objects,
1274: *ocountp + (vm_offset_t)objects, FALSE);
1275: (void) vm_map_copyin(kernel_map, (vm_offset_t)objects,
1276: *ocountp, TRUE, (vm_map_copy_t *)objectsp);
1277:
1278: return KERN_SUCCESS;
1279:
1280: nomemory:
1281: {
1282: register int i;
1283: for (i = 0; i < num_objects; i++)
1284: ipc_port_dealloc_kernel(ports[i]);
1285: }
1286:
1287: if (objects != *objectsp)
1288: (void) vm_deallocate(kernel_map, oaddr, osize);
1289:
1290: if (ports != (MACH_PORT_FACE *)*portsp)
1291: (void) vm_deallocate(kernel_map, paddr, psize);
1292:
1293: return KERN_RESOURCE_SHORTAGE;
1294: }
1295:
1296: kern_return_t
1297: default_pager_object_pages(
1298: MACH_PORT_FACE pager,
1299: MACH_PORT_FACE object,
1300: default_pager_page_array_t *pagesp,
1301: mach_msg_type_number_t *countp)
1302: {
1303: vm_offset_t addr; /* memory for page offsets */
1304: vm_size_t size = 0; /* current memory size */
1305: default_pager_page_t * pages;
1306: unsigned int potential, actual;
1307: kern_return_t kr;
1308:
1309: /*
1310: if (pager != default_pager_default_port)
1311: return KERN_INVALID_ARGUMENT;
1312: */
1313: kr = vm_map_copyout(ipc_kernel_map, (vm_offset_t *)&pages,
1314: (vm_map_copy_t) *pagesp);
1315:
1316: if (kr != KERN_SUCCESS)
1317: return kr;
1318:
1319: size = round_page(*countp * sizeof * pages);
1320: kr = vm_map_wire(ipc_kernel_map,
1321: trunc_page((vm_offset_t)pages),
1322: round_page(((vm_offset_t)pages) + size),
1323: VM_PROT_READ|VM_PROT_WRITE, FALSE);
1324: size=0;
1325:
1326: *pagesp = pages;
1327: /* we start with the inline space */
1328:
1329: addr = (vm_offset_t)pages;
1330: potential = *countp;
1331:
1332: for (;;) {
1333: vstruct_t entry;
1334:
1335: VSL_LOCK();
1336: queue_iterate(&vstruct_list.vsl_queue, entry, vstruct_t,
1337: vs_links) {
1338: VS_LOCK(entry);
1339: if (entry->vs_object_name == object) {
1340: VSL_UNLOCK();
1341: goto found_object;
1342: }
1343: VS_UNLOCK(entry);
1344: }
1345: VSL_UNLOCK();
1346:
1347: /* did not find the object */
1348:
1349: if (pages != *pagesp)
1350: (void) vm_deallocate(kernel_map, addr, size);
1351: return KERN_INVALID_ARGUMENT;
1352:
1353: found_object:
1354:
1355: if (!VS_MAP_TRY_LOCK(entry)) {
1356: /* oh well bad luck */
1357:
1358: VS_UNLOCK(entry);
1359:
1360: assert_wait_timeout( 1, THREAD_INTERRUPTIBLE);
1361: thread_block((void (*)(void)) 0);
1362: thread_cancel_timer();
1363: continue;
1364: }
1365:
1366: actual = ps_vstruct_allocated_pages(entry, pages, potential);
1367: VS_MAP_UNLOCK(entry);
1368: VS_UNLOCK(entry);
1369:
1370: if (actual <= potential)
1371: break;
1372:
1373: /* allocate more memory */
1374:
1375: if (pages != *pagesp)
1376: (void) vm_deallocate(kernel_map, addr, size);
1377: size = round_page(actual * sizeof * pages);
1378: kr = vm_allocate(kernel_map, &addr, size, TRUE);
1379: if (kr != KERN_SUCCESS)
1380: return kr;
1381: pages = (default_pager_page_t *)addr;
1382: potential = size / sizeof * pages;
1383: }
1384:
1385: /*
1386: * Deallocate and clear unused memory.
1387: * (Returned memory will automagically become pageable.)
1388: */
1389:
1390: if (pages == *pagesp) {
1391:
1392: /*
1393: * Our returned information fit inline.
1394: * Nothing to deallocate.
1395: */
1396:
1397: *countp = actual;
1398: } else if (actual == 0) {
1399: (void) vm_deallocate(kernel_map, addr, size);
1400:
1401: /* return zero items inline */
1402: *countp = 0;
1403: } else {
1404: vm_offset_t used;
1405:
1406: used = round_page(actual * sizeof * pages);
1407:
1408: if (used != size)
1409: (void) vm_deallocate(kernel_map,
1410: addr + used, size - used);
1411:
1412: *pagesp = pages;
1413: *countp = actual;
1414: }
1415: (void) vm_map_unwire(kernel_map, (vm_offset_t)pages,
1416: *countp + (vm_offset_t)pages, FALSE);
1417: (void) vm_map_copyin(kernel_map, (vm_offset_t)pages,
1418: *countp, TRUE, (vm_map_copy_t *)pagesp);
1419: return KERN_SUCCESS;
1420: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.