|
|
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: * Paging File Management.
54: */
55:
56: #include <mach/memory_object_server.h>
57: #include "default_pager_internal.h"
58: #include <default_pager/default_pager_alerts.h>
59: #include <ipc/ipc_port.h>
60: #include <ipc/ipc_space.h>
61: #include <kern/queue.h>
62: #include <kern/counters.h>
63: #include <kern/sched_prim.h>
64: #include <vm/vm_kern.h>
65: #include <vm/vm_pageout.h>
66: /* CDY CDY */
67: #include <vm/vm_map.h>
68:
69: /* MAXPHYS derived from bsd/bsd/ppc/param.h, we need a */
70: /* universal originating in the kernel, or a formal means of exporting */
71: /* from the bsd component */
72:
73: #define MAXPHYS (64 * 1024)
74: int physical_transfer_cluster_count = 0;
75:
76: #define VM_SUPER_CLUSTER 0x10000
77:
78: /*
79: * 0 means no shift to pages, so == 1 page/cluster. 1 would mean
80: * 2 pages/cluster, 2 means 4 pages/cluster, and so on.
81: */
82: #define VSTRUCT_DEF_CLSHIFT 2
83: int vstruct_def_clshift = VSTRUCT_DEF_CLSHIFT;
84: int default_pager_clsize = 0;
85:
86: /* statistics */
87: unsigned int clustered_writes[MAX_CLUSTER_SIZE+1];
88: unsigned int clustered_reads[MAX_CLUSTER_SIZE+1];
89:
90: /*
91: * Globals used for asynchronous paging operations:
92: * vs_async_list: head of list of to-be-completed I/O ops
93: * async_num_queued: number of pages completed, but not yet
94: * processed by async thread.
95: * async_requests_out: number of pages of requests not completed.
96: */
97:
98: #if 0
99: struct vs_async *vs_async_list;
100: int async_num_queued;
101: int async_requests_out;
102: #endif
103:
104:
105: #define VS_ASYNC_REUSE 1
106: struct vs_async *vs_async_free_list;
107:
108: mutex_t default_pager_async_lock; /* Protects globals above */
109:
110:
111: int vs_alloc_async_failed = 0; /* statistics */
112: int vs_alloc_async_count = 0; /* statistics */
113: struct vs_async *vs_alloc_async(void); /* forward */
114: void vs_free_async(struct vs_async *vsa); /* forward */
115:
116:
117: #define VS_ALLOC_ASYNC() vs_alloc_async()
118: #define VS_FREE_ASYNC(vsa) vs_free_async(vsa)
119:
120: #define VS_ASYNC_LOCK() mutex_lock(&default_pager_async_lock)
121: #define VS_ASYNC_UNLOCK() mutex_unlock(&default_pager_async_lock)
122: #define VS_ASYNC_LOCK_INIT() mutex_init(&default_pager_async_lock, \
123: ETAP_IO_DEV_PAGEH)
124: #define VS_ASYNC_LOCK_ADDR() (&default_pager_async_lock)
125: /*
126: * Paging Space Hysteresis triggers and the target notification port
127: *
128: */
129:
130: unsigned int minimum_pages_remaining = 0;
131: unsigned int maximum_pages_free = 0;
132: ipc_port_t min_pages_trigger_port = NULL;
133: ipc_port_t max_pages_trigger_port = NULL;
134:
135: boolean_t bs_low = FALSE;
136:
137:
138:
139: /*
140: * Object sizes are rounded up to the next power of 2,
141: * unless they are bigger than a given maximum size.
142: */
143: vm_size_t max_doubled_size = 4 * 1024 * 1024; /* 4 meg */
144:
145: /*
146: * List of all backing store and segments.
147: */
148: struct backing_store_list_head backing_store_list;
149: paging_segment_t paging_segments[MAX_NUM_PAGING_SEGMENTS];
150: mutex_t paging_segments_lock;
151: int paging_segment_max = 0;
152: int paging_segment_count = 0;
153: int ps_select_array[BS_MAXPRI+1] = { -1,-1,-1,-1,-1 };
154:
155:
156: /*
157: * Total pages free in system
158: * This differs from clusters committed/avail which is a measure of the
159: * over commitment of paging segments to backing store. An idea which is
160: * likely to be deprecated.
161: */
162: unsigned int dp_pages_free = 0;
163: unsigned int cluster_transfer_minimum = 100;
164:
165: kern_return_t ps_write_file(paging_segment_t, vm_offset_t, vm_offset_t, unsigned int); /* forward */
166:
167: default_pager_thread_t *
168: get_read_buffer()
169: {
170: int i;
171:
172: DPT_LOCK(dpt_lock);
173: while(TRUE) {
174: for (i=0; i<default_pager_internal_count; i++) {
175: if(dpt_array[i]->checked_out == FALSE) {
176: dpt_array[i]->checked_out = TRUE;
177: DPT_UNLOCK(dpt_lock);
178: return dpt_array[i];
179: }
180: }
181: assert_wait(&dpt_array, THREAD_UNINT);
182: DPT_UNLOCK(dpt_lock);
183: thread_block((void(*)(void))0);
184: }
185: }
186:
187: void
188: bs_initialize(void)
189: {
190: int i;
191:
192: /*
193: * List of all backing store.
194: */
195: BSL_LOCK_INIT();
196: queue_init(&backing_store_list.bsl_queue);
197: PSL_LOCK_INIT();
198:
199: VS_ASYNC_LOCK_INIT();
200: #if VS_ASYNC_REUSE
201: vs_async_free_list = NULL;
202: #endif /* VS_ASYNC_REUSE */
203:
204: for (i = 0; i < MAX_CLUSTER_SIZE+1; i++) {
205: clustered_writes[i] = 0;
206: clustered_reads[i] = 0;
207: }
208:
209: }
210:
211: /*
212: * When things do not quite workout...
213: */
214: void bs_no_paging_space(boolean_t); /* forward */
215:
216: void
217: bs_no_paging_space(
218: boolean_t out_of_memory)
219: {
220: static char here[] = "bs_no_paging_space";
221:
222: if (out_of_memory)
223: dprintf(("*** OUT OF MEMORY ***\n"));
224: panic("bs_no_paging_space: NOT ENOUGH PAGING SPACE");
225: }
226:
227: void bs_more_space(int); /* forward */
228: void bs_commit(int); /* forward */
229:
230: boolean_t user_warned = FALSE;
231: unsigned int clusters_committed = 0;
232: unsigned int clusters_available = 0;
233: unsigned int clusters_committed_peak = 0;
234:
235: void
236: bs_more_space(
237: int nclusters)
238: {
239: BSL_LOCK();
240: /*
241: * Account for new paging space.
242: */
243: clusters_available += nclusters;
244:
245: if (clusters_available >= clusters_committed) {
246: if (verbose && user_warned) {
247: printf("%s%s - %d excess clusters now.\n",
248: my_name,
249: "paging space is OK now",
250: clusters_available - clusters_committed);
251: user_warned = FALSE;
252: clusters_committed_peak = 0;
253: }
254: } else {
255: if (verbose && user_warned) {
256: printf("%s%s - still short of %d clusters.\n",
257: my_name,
258: "WARNING: paging space over-committed",
259: clusters_committed - clusters_available);
260: clusters_committed_peak -= nclusters;
261: }
262: }
263: BSL_UNLOCK();
264:
265: return;
266: }
267:
268: void
269: bs_commit(
270: int nclusters)
271: {
272: BSL_LOCK();
273: clusters_committed += nclusters;
274: if (clusters_committed > clusters_available) {
275: if (verbose && !user_warned) {
276: user_warned = TRUE;
277: printf("%s%s - short of %d clusters.\n",
278: my_name,
279: "WARNING: paging space over-committed",
280: clusters_committed - clusters_available);
281: }
282: if (clusters_committed > clusters_committed_peak) {
283: clusters_committed_peak = clusters_committed;
284: }
285: } else {
286: if (verbose && user_warned) {
287: printf("%s%s - was short of up to %d clusters.\n",
288: my_name,
289: "paging space is OK now",
290: clusters_committed_peak - clusters_available);
291: user_warned = FALSE;
292: clusters_committed_peak = 0;
293: }
294: }
295: BSL_UNLOCK();
296:
297: return;
298: }
299:
300: int default_pager_info_verbose = 1;
301:
302: void
303: bs_global_info(
304: vm_size_t *totalp,
305: vm_size_t *freep)
306: {
307: vm_size_t pages_total, pages_free;
308: paging_segment_t ps;
309: int i;
310: static char here[] = "bs_global_info";
311:
312: PSL_LOCK();
313: pages_total = pages_free = 0;
314: for (i = 0; i <= paging_segment_max; i++) {
315: ps = paging_segments[i];
316: if (ps == PAGING_SEGMENT_NULL)
317: continue;
318:
319: /*
320: * no need to lock: by the time this data
321: * gets back to any remote requestor it
322: * will be obsolete anyways
323: */
324: pages_total += ps->ps_pgnum;
325: pages_free += ps->ps_clcount << ps->ps_clshift;
326: DEBUG(DEBUG_BS_INTERNAL,
327: ("segment #%d: %d total, %d free\n",
328: i, ps->ps_pgnum, ps->ps_clcount << ps->ps_clshift));
329: }
330: *totalp = pages_total;
331: *freep = pages_free;
332: if (verbose && user_warned && default_pager_info_verbose) {
333: if (clusters_available < clusters_committed) {
334: printf("%s %d clusters committed, %d available.\n",
335: my_name,
336: clusters_committed,
337: clusters_available);
338: }
339: }
340: PSL_UNLOCK();
341: }
342:
343: backing_store_t backing_store_alloc(void); /* forward */
344:
345: backing_store_t
346: backing_store_alloc(void)
347: {
348: backing_store_t bs;
349: static char here[] = "backing_store_alloc";
350:
351: bs = (backing_store_t) kalloc(sizeof (struct backing_store));
352: if (bs == BACKING_STORE_NULL)
353: panic("backing_store_alloc: no memory");
354:
355: BS_LOCK_INIT(bs);
356: bs->bs_port = MACH_PORT_NULL;
357: bs->bs_priority = 0;
358: bs->bs_clsize = 0;
359: bs->bs_pages_total = 0;
360: bs->bs_pages_in = 0;
361: bs->bs_pages_in_fail = 0;
362: bs->bs_pages_out = 0;
363: bs->bs_pages_out_fail = 0;
364:
365: return bs;
366: }
367:
368: backing_store_t backing_store_lookup(MACH_PORT_FACE); /* forward */
369:
370: /* Even in both the component space and external versions of this pager, */
371: /* backing_store_lookup will be called from tasks in the application space */
372: backing_store_t
373: backing_store_lookup(
374: MACH_PORT_FACE port)
375: {
376: backing_store_t bs;
377:
378: /*
379: port is currently backed with a vs structure in the alias field
380: we could create an ISBS alias and a port_is_bs call but frankly
381: I see no reason for the test, the bs->port == port check below
382: will work properly on junk entries.
383:
384: if ((port == MACH_PORT_NULL) || port_is_vs(port))
385: */
386: if ((port == MACH_PORT_NULL))
387: return BACKING_STORE_NULL;
388:
389: BSL_LOCK();
390: queue_iterate(&backing_store_list.bsl_queue, bs, backing_store_t,
391: bs_links) {
392: BS_LOCK(bs);
393: if (bs->bs_port == port) {
394: BSL_UNLOCK();
395: /* Success, return it locked. */
396: return bs;
397: }
398: BS_UNLOCK(bs);
399: }
400: BSL_UNLOCK();
401: return BACKING_STORE_NULL;
402: }
403:
404: void backing_store_add(backing_store_t); /* forward */
405:
406: void
407: backing_store_add(
408: backing_store_t bs)
409: {
410: MACH_PORT_FACE port = bs->bs_port;
411: MACH_PORT_FACE pset = default_pager_default_set;
412: kern_return_t kr = KERN_SUCCESS;
413: static char here[] = "backing_store_add";
414:
415: if (kr != KERN_SUCCESS)
416: panic("backing_store_add: add to set");
417:
418: }
419:
420: /*
421: * Set up default page shift, but only if not already
422: * set and argument is within range.
423: */
424: boolean_t
425: bs_set_default_clsize(unsigned int npages)
426: {
427: switch(npages){
428: case 1:
429: case 2:
430: case 4:
431: case 8:
432: if (default_pager_clsize == 0) /* if not yet set */
433: vstruct_def_clshift = local_log2(npages);
434: return(TRUE);
435: }
436: return(FALSE);
437: }
438:
439: int bs_get_global_clsize(int clsize); /* forward */
440:
441: int
442: bs_get_global_clsize(
443: int clsize)
444: {
445: int i;
446: MACH_PORT_FACE DMM;
447: kern_return_t kr;
448: static char here[] = "bs_get_global_clsize";
449:
450: /*
451: * Only allow setting of cluster size once. If called
452: * with no cluster size (default), we use the compiled-in default
453: * for the duration. The same cluster size is used for all
454: * paging segments.
455: */
456: if (default_pager_clsize == 0) {
457: if (norma_mk) {
458: /*
459: * On NORMA, don't use clustered paging because
460: * XMM can't handle it.
461: */
462: vstruct_def_clshift = 0;
463: }
464: /*
465: * Keep cluster size in bit shift because it's quicker
466: * arithmetic, and easier to keep at a power of 2.
467: */
468: if (clsize != NO_CLSIZE) {
469: for (i = 0; (1 << i) < clsize; i++);
470: if (i > MAX_CLUSTER_SHIFT)
471: i = MAX_CLUSTER_SHIFT;
472: vstruct_def_clshift = i;
473: }
474: default_pager_clsize = (1 << vstruct_def_clshift);
475:
476: /*
477: * Let the user know the new (and definitive) cluster size.
478: */
479: if (verbose)
480: printf("%scluster size = %d page%s\n",
481: my_name, default_pager_clsize,
482: (default_pager_clsize == 1) ? "" : "s");
483: /*
484: * Let the kernel know too, in case it hasn't used the
485: * default value provided in main() yet.
486: */
487: DMM = default_pager_default_port;
488: clsize = default_pager_clsize * vm_page_size; /* in bytes */
489: kr = host_default_memory_manager(default_pager_host_port,
490: &DMM,
491: clsize);
492: if (kr != KERN_SUCCESS) {
493: panic("bs_get_global_cl_size:host_default_memory_manager");
494: }
495: if (DMM != default_pager_default_port) {
496: panic("bs_get_global_cl_size:there is another default pager");
497: }
498: }
499: ASSERT(default_pager_clsize > 0 &&
500: (default_pager_clsize & (default_pager_clsize - 1)) == 0);
501:
502: return default_pager_clsize;
503: }
504:
505: kern_return_t
506: default_pager_backing_store_create(
507: MACH_PORT_FACE pager,
508: int priority,
509: int clsize, /* in bytes */
510: MACH_PORT_FACE *backing_store)
511: {
512: backing_store_t bs;
513: MACH_PORT_FACE port;
514: kern_return_t kr;
515: struct vstruct_alias *alias_struct;
516: static char here[] = "default_pager_backing_store_create";
517:
518: if (pager != default_pager_default_port)
519: return KERN_INVALID_ARGUMENT;
520:
521: bs = backing_store_alloc();
522: port = ipc_port_alloc_kernel();
523: ipc_port_make_send(port);
524: assert (port != IP_NULL);
525:
526: DEBUG(DEBUG_BS_EXTERNAL,
527: ("priority=%d clsize=%d bs_port=0x%x\n",
528: priority, clsize, (int) backing_store));
529:
530: alias_struct = (struct vstruct_alias *)
531: kalloc(sizeof (struct vstruct_alias));
532: if(alias_struct != NULL) {
533: alias_struct->vs = (struct vstruct *)bs;
534: alias_struct->name = ISVS;
535: port->alias = (int) alias_struct;
536: }
537: else {
538: ipc_port_dealloc_kernel((MACH_PORT_FACE)(port));
539: kfree((vm_offset_t)bs, sizeof (struct backing_store));
540: return KERN_RESOURCE_SHORTAGE;
541: }
542:
543: bs->bs_port = port;
544: if (priority == DEFAULT_PAGER_BACKING_STORE_MAXPRI)
545: priority = BS_MAXPRI;
546: else if (priority == BS_NOPRI)
547: priority = BS_MAXPRI;
548: else
549: priority = BS_MINPRI;
550: bs->bs_priority = priority;
551:
552: bs->bs_clsize = bs_get_global_clsize(atop(clsize));
553:
554: BSL_LOCK();
555: queue_enter(&backing_store_list.bsl_queue, bs, backing_store_t,
556: bs_links);
557: BSL_UNLOCK();
558:
559: backing_store_add(bs);
560:
561: *backing_store = port;
562: return KERN_SUCCESS;
563: }
564:
565: kern_return_t
566: default_pager_backing_store_info(
567: MACH_PORT_FACE backing_store,
568: backing_store_flavor_t flavour,
569: backing_store_info_t info,
570: mach_msg_type_number_t *size)
571: {
572: backing_store_t bs;
573: backing_store_basic_info_t basic;
574: int i;
575: paging_segment_t ps;
576:
577: if (flavour != BACKING_STORE_BASIC_INFO ||
578: *size < BACKING_STORE_BASIC_INFO_COUNT)
579: return KERN_INVALID_ARGUMENT;
580:
581: basic = (backing_store_basic_info_t)info;
582: *size = BACKING_STORE_BASIC_INFO_COUNT;
583:
584: VSTATS_LOCK(&global_stats.gs_lock);
585: basic->pageout_calls = global_stats.gs_pageout_calls;
586: basic->pagein_calls = global_stats.gs_pagein_calls;
587: basic->pages_in = global_stats.gs_pages_in;
588: basic->pages_out = global_stats.gs_pages_out;
589: basic->pages_unavail = global_stats.gs_pages_unavail;
590: basic->pages_init = global_stats.gs_pages_init;
591: basic->pages_init_writes= global_stats.gs_pages_init_writes;
592: VSTATS_UNLOCK(&global_stats.gs_lock);
593:
594: if ((bs = backing_store_lookup(backing_store)) == BACKING_STORE_NULL)
595: return KERN_INVALID_ARGUMENT;
596:
597: basic->bs_pages_total = bs->bs_pages_total;
598: PSL_LOCK();
599: bs->bs_pages_free = 0;
600: for (i = 0; i <= paging_segment_max; i++) {
601: ps = paging_segments[i];
602: if (ps != PAGING_SEGMENT_NULL && ps->ps_bs == bs) {
603: PS_LOCK(ps);
604: bs->bs_pages_free += ps->ps_clcount << ps->ps_clshift;
605: PS_UNLOCK(ps);
606: }
607: }
608: PSL_UNLOCK();
609: basic->bs_pages_free = bs->bs_pages_free;
610: basic->bs_pages_in = bs->bs_pages_in;
611: basic->bs_pages_in_fail = bs->bs_pages_in_fail;
612: basic->bs_pages_out = bs->bs_pages_out;
613: basic->bs_pages_out_fail= bs->bs_pages_out_fail;
614:
615: basic->bs_priority = bs->bs_priority;
616: basic->bs_clsize = ptoa(bs->bs_clsize); /* in bytes */
617:
618: BS_UNLOCK(bs);
619:
620: return KERN_SUCCESS;
621: }
622:
623: int ps_delete(paging_segment_t); /* forward */
624:
625: int
626: ps_delete(
627: paging_segment_t ps)
628: {
629: vstruct_t vs;
630: kern_return_t error = KERN_SUCCESS;
631: int vs_count;
632:
633: VSL_LOCK(); /* get the lock on the list of vs's */
634:
635: /* The lock relationship and sequence is farily complicated */
636: /* this code looks at a live list, locking and unlocking the list */
637: /* as it traverses it. It depends on the locking behavior of */
638: /* default_pager_no_senders. no_senders always locks the vstruct */
639: /* targeted for removal before locking the vstruct list. However */
640: /* it will remove that member of the list without locking its */
641: /* neighbors. We can be sure when we hold a lock on a vstruct */
642: /* it cannot be removed from the list but we must hold the list */
643: /* lock to be sure that its pointers to its neighbors are valid. */
644: /* Also, we can hold off destruction of a vstruct when the list */
645: /* lock and the vs locks are not being held by bumping the */
646: /* vs_async_pending count. */
647:
648: /* we will choose instead to hold a send right */
649: vs_count = vstruct_list.vsl_count;
650: vs = (vstruct_t) queue_first((queue_entry_t)&(vstruct_list.vsl_queue));
651: if(vs == (vstruct_t)&vstruct_list) {
652: VSL_UNLOCK();
653: return KERN_SUCCESS;
654: }
655: VS_LOCK(vs);
656: vs_async_wait(vs); /* wait for any pending async writes */
657: if ((vs_count != 0) && (vs != NULL))
658: vs->vs_async_pending += 1; /* hold parties calling */
659: /* vs_async_wait */
660: VS_UNLOCK(vs);
661: VSL_UNLOCK();
662: while((vs_count != 0) && (vs != NULL)) {
663: /* We take the count of AMO's before beginning the */
664: /* transfer of of the target segment. */
665: /* We are guaranteed that the target segment cannot get */
666: /* more users. We also know that queue entries are */
667: /* made at the back of the list. If some of the entries */
668: /* we would check disappear while we are traversing the */
669: /* list then we will either check new entries which */
670: /* do not have any backing store in the target segment */
671: /* or re-check old entries. This might not be optimal */
672: /* but it will always be correct. The alternative is to */
673: /* take a snapshot of the list. */
674: vstruct_t next_vs;
675:
676: if(dp_pages_free < cluster_transfer_minimum)
677: error = KERN_FAILURE;
678: else {
679: vm_object_t transfer_object;
680: upl_t page_list;
681:
682: transfer_object = vm_object_allocate(VM_SUPER_CLUSTER);
683: error = vm_fault_list_request(transfer_object,
684: 0, VM_SUPER_CLUSTER, &page_list, NULL,
685: 0, UPL_NO_SYNC | UPL_CLEAN_IN_PLACE);
686: if(error == KERN_SUCCESS)
687: error = ps_vstruct_transfer_from_segment(
688: vs, ps, page_list);
689: upl_commit(page_list, NULL);
690: vm_object_deallocate(transfer_object);
691: }
692: if(error) {
693: VS_LOCK(vs);
694: vs->vs_async_pending -= 1; /* release vs_async_wait */
695: if (vs->vs_async_pending == 0) {
696: VS_UNLOCK(vs);
697: thread_wakeup(&vs->vs_waiting_async);
698: } else {
699: VS_UNLOCK(vs);
700: }
701: return KERN_FAILURE;
702: }
703:
704: VSL_LOCK();
705: next_vs = (vstruct_t) queue_next(&(vs->vs_links));
706: if((next_vs != (vstruct_t)&vstruct_list) &&
707: (vs != next_vs) && (vs_count != 1)) {
708: VS_LOCK(next_vs);
709: next_vs->vs_async_pending += 1; /* hold parties */
710: /* calling vs_async_wait */
711: VS_UNLOCK(next_vs);
712: }
713: VSL_UNLOCK();
714: VS_LOCK(vs);
715: vs->vs_async_pending -= 1;
716: if (vs->vs_async_pending == 0) {
717: VS_UNLOCK(vs);
718: thread_wakeup(&vs->vs_waiting_async);
719: } else {
720: VS_UNLOCK(vs);
721: }
722: if((vs == next_vs) || (next_vs == (vstruct_t)&vstruct_list))
723: vs = NULL;
724: else
725: vs = next_vs;
726: vs_count--;
727: }
728: return KERN_SUCCESS;
729: }
730:
731:
732: kern_return_t
733: default_pager_backing_store_delete(
734: MACH_PORT_FACE backing_store)
735: {
736: backing_store_t bs;
737: int i;
738: paging_segment_t ps;
739: int error;
740: int interim_pages_removed = 0;
741: kern_return_t kr;
742: static char here[] = "default_pager_backing_store_delete";
743:
744: if ((bs = backing_store_lookup(backing_store)) == BACKING_STORE_NULL)
745: return KERN_INVALID_ARGUMENT;
746:
747: #if 0
748: /* not implemented */
749: BS_UNLOCK(bs);
750: return KERN_FAILURE;
751: #endif
752:
753: restart:
754: PSL_LOCK();
755: error = KERN_SUCCESS;
756: for (i = 0; i <= paging_segment_max; i++) {
757: ps = paging_segments[i];
758: if (ps != PAGING_SEGMENT_NULL &&
759: ps->ps_bs == bs &&
760: ! ps->ps_going_away) {
761: PS_LOCK(ps);
762: /* disable access to this segment */
763: ps->ps_going_away = TRUE;
764: PS_UNLOCK(ps);
765: /*
766: * The "ps" segment is "off-line" now,
767: * we can try and delete it...
768: */
769: if(dp_pages_free < (cluster_transfer_minimum
770: + (ps->ps_clcount << ps->ps_clshift))) {
771: error = KERN_FAILURE;
772: PSL_UNLOCK();
773: }
774: else {
775: dp_pages_free -=
776: ps->ps_clcount << ps->ps_clshift;
777: interim_pages_removed +=
778: ps->ps_clcount << ps->ps_clshift;
779: PSL_UNLOCK();
780: error = ps_delete(ps);
781: }
782: if (error != KERN_SUCCESS) {
783: /*
784: * We couldn't delete the segment,
785: * probably because there's not enough
786: * virtual memory left.
787: * Re-enable all the segments.
788: */
789: PSL_LOCK();
790: break;
791: }
792: goto restart;
793: }
794: }
795:
796: if (error != KERN_SUCCESS) {
797: for (i = 0; i <= paging_segment_max; i++) {
798: ps = paging_segments[i];
799: if (ps != PAGING_SEGMENT_NULL &&
800: ps->ps_bs == bs &&
801: ps->ps_going_away) {
802: PS_LOCK(ps);
803: /* re-enable access to this segment */
804: ps->ps_going_away = FALSE;
805: PS_UNLOCK(ps);
806: }
807: }
808: dp_pages_free += interim_pages_removed;
809: PSL_UNLOCK();
810: BS_UNLOCK(bs);
811: return error;
812: }
813:
814: for (i = 0; i <= paging_segment_max; i++) {
815: ps = paging_segments[i];
816: if (ps != PAGING_SEGMENT_NULL &&
817: ps->ps_bs == bs) {
818: if(ps->ps_going_away) {
819: paging_segments[i] = PAGING_SEGMENT_NULL;
820: paging_segment_count--;
821: PS_LOCK(ps);
822: kfree((vm_offset_t)ps->ps_bmap,
823: RMAPSIZE(ps->ps_ncls));
824: kfree((vm_offset_t)ps, sizeof *ps);
825: }
826: }
827: }
828:
829: /* Scan the entire ps array separately to make certain we find the */
830: /* proper paging_segment_max */
831: for (i = 0; i < MAX_NUM_PAGING_SEGMENTS; i++) {
832: if(paging_segments[i] != PAGING_SEGMENT_NULL)
833: paging_segment_max = i;
834: }
835:
836: PSL_UNLOCK();
837:
838: /*
839: * All the segments have been deleted.
840: * We can remove the backing store.
841: */
842:
843: /*
844: * Disable lookups of this backing store.
845: */
846: if((void *)bs->bs_port->alias != NULL)
847: kfree((vm_offset_t) bs->bs_port->alias,
848: sizeof (struct vstruct_alias));
849: pager_mux_hash_delete((ipc_port_t) (bs->bs_port));
850: ipc_port_dealloc_kernel((ipc_port_t) (bs->bs_port));
851: bs->bs_port = MACH_PORT_NULL;
852: BS_UNLOCK(bs);
853:
854: /*
855: * Remove backing store from backing_store list.
856: */
857: BSL_LOCK();
858: queue_remove(&backing_store_list.bsl_queue, bs, backing_store_t,
859: bs_links);
860: BSL_UNLOCK();
861:
862: /*
863: * Free the backing store structure.
864: */
865: kfree((vm_offset_t)bs, sizeof *bs);
866:
867: return KERN_SUCCESS;
868: }
869:
870: int ps_enter(paging_segment_t); /* forward */
871:
872: int
873: ps_enter(
874: paging_segment_t ps)
875: {
876: int i;
877:
878: PSL_LOCK();
879:
880: for (i = 0; i < MAX_NUM_PAGING_SEGMENTS; i++) {
881: if (paging_segments[i] == PAGING_SEGMENT_NULL)
882: break;
883: }
884:
885: if (i < MAX_NUM_PAGING_SEGMENTS) {
886: paging_segments[i] = ps;
887: if (i > paging_segment_max)
888: paging_segment_max = i;
889: paging_segment_count++;
890: if ((ps_select_array[ps->ps_bs->bs_priority] == BS_NOPRI) ||
891: (ps_select_array[ps->ps_bs->bs_priority] == BS_FULLPRI))
892: ps_select_array[ps->ps_bs->bs_priority] = 0;
893: i = 0;
894: } else {
895: PSL_UNLOCK();
896: return KERN_RESOURCE_SHORTAGE;
897: }
898:
899: PSL_UNLOCK();
900: return i;
901: }
902:
903: #ifdef DEVICE_PAGING
904: kern_return_t
905: default_pager_add_segment(
906: MACH_PORT_FACE backing_store,
907: MACH_PORT_FACE device,
908: recnum_t offset,
909: recnum_t count,
910: int record_size)
911: {
912: backing_store_t bs;
913: paging_segment_t ps;
914: int i;
915: int error;
916: static char here[] = "default_pager_add_segment";
917:
918: if ((bs = backing_store_lookup(backing_store))
919: == BACKING_STORE_NULL)
920: return KERN_INVALID_ARGUMENT;
921:
922: PSL_LOCK();
923: for (i = 0; i <= paging_segment_max; i++) {
924: ps = paging_segments[i];
925: if (ps == PAGING_SEGMENT_NULL)
926: continue;
927:
928: /*
929: * Check for overlap on same device.
930: */
931: if (!(ps->ps_device != device
932: || offset >= ps->ps_offset + ps->ps_recnum
933: || offset + count <= ps->ps_offset)) {
934: PSL_UNLOCK();
935: BS_UNLOCK(bs);
936: return KERN_INVALID_ARGUMENT;
937: }
938: }
939: PSL_UNLOCK();
940:
941: /*
942: * Set up the paging segment
943: */
944: ps = (paging_segment_t) kalloc(sizeof (struct paging_segment));
945: if (ps == PAGING_SEGMENT_NULL) {
946: BS_UNLOCK(bs);
947: return KERN_RESOURCE_SHORTAGE;
948: }
949:
950: ps->ps_segtype = PS_PARTITION;
951: ps->ps_device = device;
952: ps->ps_offset = offset;
953: ps->ps_record_shift = local_log2(vm_page_size / record_size);
954: ps->ps_recnum = count;
955: ps->ps_pgnum = count >> ps->ps_record_shift;
956:
957: ps->ps_pgcount = ps->ps_pgnum;
958: ps->ps_clshift = local_log2(bs->bs_clsize);
959: ps->ps_clcount = ps->ps_ncls = ps->ps_pgcount >> ps->ps_clshift;
960: ps->ps_hint = 0;
961:
962: PS_LOCK_INIT(ps);
963: ps->ps_bmap = (unsigned char *) kalloc(RMAPSIZE(ps->ps_ncls));
964: if (!ps->ps_bmap) {
965: kfree((vm_offset_t)ps, sizeof *ps);
966: BS_UNLOCK(bs);
967: return KERN_RESOURCE_SHORTAGE;
968: }
969: for (i = 0; i < ps->ps_ncls; i++) {
970: clrbit(ps->ps_bmap, i);
971: }
972:
973: ps->ps_going_away = FALSE;
974: ps->ps_bs = bs;
975:
976: if ((error = ps_enter(ps)) != 0) {
977: kfree((vm_offset_t)ps->ps_bmap, RMAPSIZE(ps->ps_ncls));
978: kfree((vm_offset_t)ps, sizeof *ps);
979: BS_UNLOCK(bs);
980: return KERN_RESOURCE_SHORTAGE;
981: }
982:
983: bs->bs_pages_free += ps->ps_clcount << ps->ps_clshift;
984: bs->bs_pages_total += ps->ps_clcount << ps->ps_clshift;
985: BS_UNLOCK(bs);
986:
987: PSL_LOCK();
988: dp_pages_free += ps->ps_pgcount;
989: PSL_UNLOCK();
990:
991: bs_more_space(ps->ps_clcount);
992:
993: DEBUG(DEBUG_BS_INTERNAL,
994: ("device=0x%x,offset=0x%x,count=0x%x,record_size=0x%x,shift=%d,total_size=0x%x\n",
995: device, offset, count, record_size,
996: ps->ps_record_shift, ps->ps_pgnum));
997:
998: return KERN_SUCCESS;
999: }
1000:
1001: boolean_t
1002: bs_add_device(
1003: char *dev_name,
1004: MACH_PORT_FACE master)
1005: {
1006: security_token_t null_security_token = {
1007: { 0, 0 }
1008: };
1009: MACH_PORT_FACE device;
1010: int info[DEV_GET_SIZE_COUNT];
1011: mach_msg_type_number_t info_count;
1012: MACH_PORT_FACE bs = MACH_PORT_NULL;
1013: unsigned int rec_size;
1014: recnum_t count;
1015: int clsize;
1016: MACH_PORT_FACE reply_port;
1017:
1018: if (ds_device_open_sync(master, MACH_PORT_NULL, D_READ | D_WRITE,
1019: null_security_token, dev_name, &device))
1020: return FALSE;
1021:
1022: info_count = DEV_GET_SIZE_COUNT;
1023: if (!ds_device_get_status(device, DEV_GET_SIZE, info, &info_count)) {
1024: rec_size = info[DEV_GET_SIZE_RECORD_SIZE];
1025: count = info[DEV_GET_SIZE_DEVICE_SIZE] / rec_size;
1026: clsize = bs_get_global_clsize(0);
1027: if (!default_pager_backing_store_create(
1028: default_pager_default_port,
1029: DEFAULT_PAGER_BACKING_STORE_MAXPRI,
1030: (clsize * vm_page_size),
1031: &bs)) {
1032: if (!default_pager_add_segment(bs, device,
1033: 0, count, rec_size)) {
1034: return TRUE;
1035: }
1036: ipc_port_release_receive(bs);
1037: }
1038: }
1039:
1040: ipc_port_release_send(device);
1041: return FALSE;
1042: }
1043: #endif /* DEVICE_PAGING */
1044:
1045: #if VS_ASYNC_REUSE
1046:
1047: struct vs_async *
1048: vs_alloc_async(void)
1049: {
1050: struct vs_async *vsa;
1051: MACH_PORT_FACE reply_port;
1052: kern_return_t kr;
1053:
1054: VS_ASYNC_LOCK();
1055: if (vs_async_free_list == NULL) {
1056: VS_ASYNC_UNLOCK();
1057: vsa = (struct vs_async *) kalloc(sizeof (struct vs_async));
1058: if (vsa != NULL) {
1059: /*
1060: * Try allocating a reply port named after the
1061: * address of the vs_async structure.
1062: */
1063: struct vstruct_alias *alias_struct;
1064:
1065: reply_port = ipc_port_alloc_kernel();
1066: alias_struct = (struct vstruct_alias *)
1067: kalloc(sizeof (struct vstruct_alias));
1068: if(alias_struct != NULL) {
1069: alias_struct->vs = (struct vstruct *)vsa;
1070: alias_struct->name = ISVS;
1071: reply_port->alias = (int) alias_struct;
1072: vsa->reply_port = reply_port;
1073: vs_alloc_async_count++;
1074: }
1075: else {
1076: vs_alloc_async_failed++;
1077: ipc_port_dealloc_kernel((MACH_PORT_FACE)
1078: (reply_port));
1079: kfree((vm_offset_t)vsa,
1080: sizeof (struct vs_async));
1081: vsa = NULL;
1082: }
1083: }
1084: } else {
1085: vsa = vs_async_free_list;
1086: vs_async_free_list = vs_async_free_list->vsa_next;
1087: VS_ASYNC_UNLOCK();
1088: }
1089:
1090: return vsa;
1091: }
1092:
1093: void
1094: vs_free_async(
1095: struct vs_async *vsa)
1096: {
1097: VS_ASYNC_LOCK();
1098: vsa->vsa_next = vs_async_free_list;
1099: vs_async_free_list = vsa;
1100: VS_ASYNC_UNLOCK();
1101: }
1102:
1103: #else /* VS_ASYNC_REUSE */
1104:
1105: struct vs_async *
1106: vs_alloc_async(void)
1107: {
1108: struct vs_async *vsa;
1109: MACH_PORT_FACE reply_port;
1110: kern_return_t kr;
1111:
1112: vsa = (struct vs_async *) kalloc(sizeof (struct vs_async));
1113: if (vsa != NULL) {
1114: /*
1115: * Try allocating a reply port named after the
1116: * address of the vs_async structure.
1117: */
1118: reply_port = ipc_port_alloc_kernel();
1119: alias_struct = (vstruct_alias *)
1120: kalloc(sizeof (struct vstruct_alias));
1121: if(alias_struct != NULL) {
1122: alias_struct->vs = reply_port;
1123: alias_struct->name = ISVS;
1124: reply_port->alias = (int) vsa;
1125: vsa->reply_port = reply_port;
1126: vs_alloc_async_count++;
1127: }
1128: else {
1129: vs_alloc_async_failed++;
1130: ipc_port_dealloc_kernel((MACH_PORT_FACE)
1131: (reply_port));
1132: kfree((vm_offset_t) vsa,
1133: sizeof (struct vs_async));
1134: vsa = NULL;
1135: }
1136: }
1137:
1138: return vsa;
1139: }
1140:
1141: void
1142: vs_free_async(
1143: struct vs_async *vsa)
1144: {
1145: static char here[] = "vs_free_async";
1146: MACH_PORT_FACE reply_port;
1147: kern_return_t kr;
1148:
1149: reply_port = vsa->reply_port;
1150: kfree((vm_offset_t) reply_port->alias, sizeof (struct vstuct_alias));
1151: kfree((vm_offset_t) vsa, sizeof (struct vs_async));
1152: pager_mux_hash_delete(reply_port);
1153: ipc_port_dealloc_kernel((MACH_PORT_FACE) (reply_port));
1154: #if 0
1155: VS_ASYNC_LOCK();
1156: vs_alloc_async_count--;
1157: VS_ASYNC_UNLOCK();
1158: #endif
1159: }
1160:
1161: #endif /* VS_ASYNC_REUSE */
1162:
1163: vstruct_t
1164: ps_vstruct_create(
1165: vm_size_t size)
1166: {
1167: vstruct_t vs;
1168: int i;
1169: static char here[] = "ps_vstruct_create";
1170:
1171: vs = (vstruct_t) kalloc(sizeof (struct vstruct));
1172: if (vs == VSTRUCT_NULL) {
1173: return VSTRUCT_NULL;
1174: }
1175:
1176: VS_LOCK_INIT(vs);
1177:
1178: /*
1179: * The following fields will be provided later.
1180: */
1181: vs->vs_mem_obj_port = MACH_PORT_NULL;
1182: vs->vs_seqno = 0;
1183: vs->vs_control_port = MACH_PORT_NULL;
1184: vs->vs_control_refs = 0;
1185: vs->vs_object_name = MACH_PORT_NULL;
1186: vs->vs_name_refs = 0;
1187:
1188: #ifdef MACH_KERNEL
1189: vs->vs_waiting_seqno = FALSE;
1190: vs->vs_waiting_read = FALSE;
1191: vs->vs_waiting_write = FALSE;
1192: vs->vs_waiting_refs = FALSE;
1193: vs->vs_waiting_async = FALSE;
1194: #else
1195: mutex_init(&vs->vs_waiting_seqno, ETAP_DPAGE_VSSEQNO);
1196: mutex_init(&vs->vs_waiting_read, ETAP_DPAGE_VSREAD);
1197: mutex_init(&vs->vs_waiting_write, ETAP_DPAGE_VSWRITE);
1198: mutex_init(&vs->vs_waiting_refs, ETAP_DPAGE_VSREFS);
1199: mutex_init(&vs->vs_waiting_async, ETAP_DPAGE_VSASYNC);
1200: #endif
1201:
1202: vs->vs_readers = 0;
1203: vs->vs_writers = 0;
1204:
1205: vs->vs_errors = 0;
1206:
1207: vs->vs_clshift = local_log2(bs_get_global_clsize(0));
1208: vs->vs_size = ((atop(round_page(size)) - 1) >> vs->vs_clshift) + 1;
1209: vs->vs_async_pending = 0;
1210:
1211: /*
1212: * Allocate the pmap, either CLMAP_SIZE or INDIRECT_CLMAP_SIZE
1213: * depending on the size of the memory object.
1214: */
1215: if (INDIRECT_CLMAP(vs->vs_size)) {
1216: vs->vs_imap = (struct vs_map **)
1217: kalloc(INDIRECT_CLMAP_SIZE(vs->vs_size));
1218: vs->vs_indirect = TRUE;
1219: } else {
1220: vs->vs_dmap = (struct vs_map *)
1221: kalloc(CLMAP_SIZE(vs->vs_size));
1222: vs->vs_indirect = FALSE;
1223: }
1224: vs->vs_xfer_pending = FALSE;
1225: DEBUG(DEBUG_VS_INTERNAL,
1226: ("map=0x%x, indirect=%d\n", (int) vs->vs_dmap, vs->vs_indirect));
1227:
1228: /*
1229: * Check to see that we got the space.
1230: */
1231: if (!vs->vs_dmap) {
1232: kfree((vm_offset_t)vs, sizeof *vs);
1233: return VSTRUCT_NULL;
1234: }
1235:
1236: /*
1237: * Zero the indirect pointers, or clear the direct pointers.
1238: */
1239: if (vs->vs_indirect)
1240: memset(vs->vs_imap, 0,
1241: INDIRECT_CLMAP_SIZE(vs->vs_size));
1242: else
1243: for (i = 0; i < vs->vs_size; i++)
1244: VSM_CLR(vs->vs_dmap[i]);
1245:
1246: VS_MAP_LOCK_INIT(vs);
1247:
1248: bs_commit(vs->vs_size);
1249:
1250: return vs;
1251: }
1252:
1253: paging_segment_t ps_select_segment(int, int *); /* forward */
1254:
1255: paging_segment_t
1256: ps_select_segment(
1257: int shift,
1258: int *psindex)
1259: {
1260: paging_segment_t ps;
1261: int i;
1262: int j;
1263: static char here[] = "ps_select_segment";
1264:
1265: /*
1266: * Optimize case where there's only one segment.
1267: * paging_segment_max will index the one and only segment.
1268: */
1269:
1270: PSL_LOCK();
1271: if (paging_segment_count == 1) {
1272: paging_segment_t lps; /* used to avoid extra PS_UNLOCK */
1273:
1274: ps = paging_segments[paging_segment_max];
1275: *psindex = paging_segment_max;
1276: PS_LOCK(ps);
1277: if (ps->ps_going_away) {
1278: /* this segment is being turned off */
1279: lps = PAGING_SEGMENT_NULL;
1280: } else {
1281: ASSERT(ps->ps_clshift >= shift);
1282: if (ps->ps_clcount) {
1283: ps->ps_clcount--;
1284: dp_pages_free -= 1 << ps->ps_clshift;
1285: if(min_pages_trigger_port &&
1286: (dp_pages_free < minimum_pages_remaining)) {
1287: default_pager_space_alert(
1288: min_pages_trigger_port,
1289: HI_WAT_ALERT);
1290: min_pages_trigger_port = NULL;
1291: bs_low = TRUE;
1292: }
1293: lps = ps;
1294: } else
1295: lps = PAGING_SEGMENT_NULL;
1296: }
1297: PS_UNLOCK(ps);
1298: PSL_UNLOCK();
1299: return lps;
1300: }
1301:
1302: if (paging_segment_count == 0) {
1303: PSL_UNLOCK();
1304: return PAGING_SEGMENT_NULL;
1305: }
1306:
1307: for (i = BS_MAXPRI;
1308: i >= BS_MINPRI; i--) {
1309: int start_index;
1310:
1311: if ((ps_select_array[i] == BS_NOPRI) ||
1312: (ps_select_array[i] == BS_FULLPRI))
1313: continue;
1314: start_index = ps_select_array[i];
1315:
1316: if(!(paging_segments[start_index])) {
1317: j = start_index+1;
1318: physical_transfer_cluster_count = 0;
1319: }
1320: else if ((physical_transfer_cluster_count+1) == (MAXPHYS >>
1321: (((paging_segments[start_index])->ps_clshift)
1322: + page_shift))) {
1323: physical_transfer_cluster_count = 0;
1324: j = start_index + 1;
1325: } else {
1326: physical_transfer_cluster_count+=1;
1327: j = start_index;
1328: if(start_index == 0)
1329: start_index = paging_segment_max;
1330: else
1331: start_index = start_index - 1;
1332: }
1333:
1334: while (1) {
1335: if (j > paging_segment_max)
1336: j = 0;
1337: if ((ps = paging_segments[j]) &&
1338: (ps->ps_bs->bs_priority == i)) {
1339: /*
1340: * Force the ps cluster size to be
1341: * >= that of the vstruct.
1342: */
1343: PS_LOCK(ps);
1344: if (ps->ps_going_away) {
1345: /* this segment is being turned off */
1346: } else if ((ps->ps_clcount) &&
1347: (ps->ps_clshift >= shift)) {
1348: ps->ps_clcount--;
1349: dp_pages_free -= 1 << ps->ps_clshift;
1350: if(min_pages_trigger_port &&
1351: (dp_pages_free <
1352: minimum_pages_remaining)) {
1353: default_pager_space_alert(
1354: min_pages_trigger_port,
1355: HI_WAT_ALERT);
1356: min_pages_trigger_port = NULL;
1357: }
1358: PS_UNLOCK(ps);
1359: /*
1360: * found one, quit looking.
1361: */
1362: ps_select_array[i] = j;
1363: PSL_UNLOCK();
1364: *psindex = j;
1365: return ps;
1366: }
1367: PS_UNLOCK(ps);
1368: }
1369: if (j == start_index) {
1370: /*
1371: * none at this priority -- mark it full
1372: */
1373: ps_select_array[i] = BS_FULLPRI;
1374: break;
1375: }
1376: j++;
1377: }
1378: }
1379: PSL_UNLOCK();
1380: return PAGING_SEGMENT_NULL;
1381: }
1382:
1383: vm_offset_t ps_allocate_cluster(vstruct_t, int *, paging_segment_t); /*forward*/
1384:
1385: vm_offset_t
1386: ps_allocate_cluster(
1387: vstruct_t vs,
1388: int *psindex,
1389: paging_segment_t use_ps)
1390: {
1391: int byte_num;
1392: int bit_num = 0;
1393: paging_segment_t ps;
1394: vm_offset_t cluster;
1395: static char here[] = "ps_allocate_cluster";
1396:
1397: /*
1398: * Find best paging segment.
1399: * ps_select_segment will decrement cluster count on ps.
1400: * Must pass cluster shift to find the most appropriate segment.
1401: */
1402: /* NOTE: The addition of paging segment delete capability threatened
1403: * to seriously complicate the treatment of paging segments in this
1404: * module and the ones that call it (notably ps_clmap), because of the
1405: * difficulty in assuring that the paging segment would continue to
1406: * exist between being unlocked and locked. This was
1407: * avoided because all calls to this module are based in either
1408: * dp_memory_object calls which rely on the vs lock, or by
1409: * the transfer function which is part of the segment delete path.
1410: * The transfer function which is part of paging segment delete is
1411: * protected from multiple callers by the backing store lock.
1412: * The paging segment delete function treats mappings to a paging
1413: * segment on a vstruct by vstruct basis, locking the vstruct targeted
1414: * while data is transferred to the remaining segments. This is in
1415: * line with the view that incomplete or in-transition mappings between
1416: * data, a vstruct, and backing store are protected by the vs lock.
1417: * This and the ordering of the paging segment "going_away" bit setting
1418: * protects us.
1419: */
1420: if (use_ps != PAGING_SEGMENT_NULL) {
1421: ps = use_ps;
1422: PSL_LOCK();
1423: PS_LOCK(ps);
1424: ps->ps_clcount--;
1425: dp_pages_free -= 1 << ps->ps_clshift;
1426: PSL_UNLOCK();
1427: if(min_pages_trigger_port &&
1428: (dp_pages_free < minimum_pages_remaining)) {
1429: default_pager_space_alert(
1430: min_pages_trigger_port,
1431: HI_WAT_ALERT);
1432: min_pages_trigger_port = NULL;
1433: }
1434: PS_UNLOCK(ps);
1435: } else if ((ps = ps_select_segment(vs->vs_clshift, psindex)) ==
1436: PAGING_SEGMENT_NULL) {
1437: #if 0
1438: bs_no_paging_space(TRUE);
1439: #endif
1440: #if 0
1441: if (verbose)
1442: #endif
1443: dprintf(("no space in available paging segments; "
1444: "swapon suggested\n"));
1445: return (vm_offset_t) -1;
1446: }
1447: ASSERT(ps->ps_clcount != 0);
1448:
1449: /*
1450: * Look for an available cluster. At the end of the loop,
1451: * byte_num is the byte offset and bit_num is the bit offset of the
1452: * first zero bit in the paging segment bitmap.
1453: */
1454: PS_LOCK(ps);
1455: byte_num = ps->ps_hint;
1456: for (; byte_num < howmany(ps->ps_ncls, NBBY); byte_num++) {
1457: if (*(ps->ps_bmap + byte_num) != BYTEMASK) {
1458: for (bit_num = 0; bit_num < NBBY; bit_num++) {
1459: if (isclr((ps->ps_bmap + byte_num), bit_num))
1460: break;
1461: }
1462: ASSERT(bit_num != NBBY);
1463: break;
1464: }
1465: }
1466: ps->ps_hint = byte_num;
1467: cluster = (byte_num*NBBY) + bit_num;
1468:
1469: /* Space was reserved, so this must be true */
1470: ASSERT(cluster < ps->ps_ncls);
1471:
1472: setbit(ps->ps_bmap, cluster);
1473: PS_UNLOCK(ps);
1474:
1475: return cluster;
1476: }
1477:
1478: void ps_deallocate_cluster(paging_segment_t, vm_offset_t); /* forward */
1479:
1480: void
1481: ps_deallocate_cluster(
1482: paging_segment_t ps,
1483: vm_offset_t cluster)
1484: {
1485:
1486: if (cluster >= (vm_offset_t) ps->ps_ncls)
1487: panic("ps_deallocate_cluster: Invalid cluster number");
1488:
1489: /*
1490: * Lock the paging segment, clear the cluster's bitmap and increment the
1491: * number of free cluster.
1492: */
1493: PSL_LOCK();
1494: PS_LOCK(ps);
1495: clrbit(ps->ps_bmap, cluster);
1496: ++ps->ps_clcount;
1497: dp_pages_free += 1 << ps->ps_clshift;
1498: PSL_UNLOCK();
1499: if(max_pages_trigger_port && (dp_pages_free > maximum_pages_free)) {
1500: default_pager_space_alert(max_pages_trigger_port, LO_WAT_ALERT);
1501: max_pages_trigger_port = NULL;
1502: }
1503:
1504: /*
1505: * Move the hint down to the freed cluster if it is
1506: * less than the current hint.
1507: */
1508: if ((cluster/NBBY) < ps->ps_hint) {
1509: ps->ps_hint = (cluster/NBBY);
1510: }
1511:
1512: PS_UNLOCK(ps);
1513:
1514: /*
1515: * If we're freeing space on a full priority, reset the array.
1516: */
1517: PSL_LOCK();
1518: if (ps_select_array[ps->ps_bs->bs_priority] == BS_FULLPRI)
1519: ps_select_array[ps->ps_bs->bs_priority] = 0;
1520: PSL_UNLOCK();
1521:
1522: return;
1523: }
1524:
1525: void ps_dealloc_vsmap(struct vs_map *, vm_size_t); /* forward */
1526:
1527: void
1528: ps_dealloc_vsmap(
1529: struct vs_map *vsmap,
1530: vm_size_t size)
1531: {
1532: int i;
1533: for (i = 0; i < size; i++)
1534: if (!VSM_ISCLR(vsmap[i]) && !VSM_ISERR(vsmap[i]))
1535: ps_deallocate_cluster(VSM_PS(vsmap[i]),
1536: VSM_CLOFF(vsmap[i]));
1537: }
1538:
1539: void
1540: ps_vstruct_dealloc(
1541: vstruct_t vs)
1542: {
1543: int i;
1544: static char here[] = "ps_vstruct_dealloc";
1545:
1546: VS_MAP_LOCK(vs);
1547:
1548: /*
1549: * If this is an indirect structure, then we walk through the valid
1550: * (non-zero) indirect pointers and deallocate the clusters
1551: * associated with each used map entry (via ps_dealloc_vsmap).
1552: * When all of the clusters in an indirect block have been
1553: * freed, we deallocate the block. When all of the indirect
1554: * blocks have been deallocated we deallocate the memory
1555: * holding the indirect pointers.
1556: */
1557: if (vs->vs_indirect) {
1558: for (i = 0; i < INDIRECT_CLMAP_ENTRIES(vs->vs_size); i++) {
1559: if (vs->vs_imap[i] != NULL) {
1560: ps_dealloc_vsmap(vs->vs_imap[i], CLMAP_ENTRIES);
1561: kfree((vm_offset_t)vs->vs_imap[i],
1562: CLMAP_THRESHOLD);
1563: }
1564: }
1565: kfree((vm_offset_t)vs->vs_imap,
1566: INDIRECT_CLMAP_SIZE(vs->vs_size));
1567: } else {
1568: /*
1569: * Direct map. Free used clusters, then memory.
1570: */
1571: ps_dealloc_vsmap(vs->vs_dmap, vs->vs_size);
1572: kfree((vm_offset_t)vs->vs_dmap, CLMAP_SIZE(vs->vs_size));
1573: }
1574: VS_MAP_UNLOCK(vs);
1575:
1576: bs_commit(- vs->vs_size);
1577:
1578: ip_lock(vs_to_port(vs));
1579: (vs_to_port(vs))->ip_destination = 0;
1580: (vs_to_port(vs))->ip_receiver_name = MACH_PORT_NULL;
1581: imq_lock(&vs_to_port(vs)->ip_messages);
1582: (vs_to_port(vs))->ip_mscount = 0;
1583: (vs_to_port(vs))->ip_messages.imq_seqno = 0;
1584: imq_unlock(&vs_to_port(vs)->ip_messages);
1585: ip_unlock(vs_to_port(vs));
1586: pager_mux_hash_delete((ipc_port_t) vs_to_port(vs));
1587: ipc_port_release_receive(vs_to_port(vs));
1588: /*
1589: * Do this *after* deallocating the port name
1590: */
1591: kfree((vm_offset_t)vs, sizeof *vs);
1592: }
1593:
1594: int ps_map_extend(vstruct_t, int); /* forward */
1595:
1596: int ps_map_extend(
1597: vstruct_t vs,
1598: int new_size)
1599: {
1600: struct vs_map **new_imap;
1601: struct vs_map *new_dmap = NULL;
1602: int newdsize;
1603: int i;
1604: void *old_map = NULL;
1605: int old_map_size = 0;
1606:
1607: if (vs->vs_size >= new_size) {
1608: /*
1609: * Someone has already done the work.
1610: */
1611: return 0;
1612: }
1613:
1614: /*
1615: * If the new size extends into the indirect range, then we have one
1616: * of two cases: we are going from indirect to indirect, or we are
1617: * going from direct to indirect. If we are going from indirect to
1618: * indirect, then it is possible that the new size will fit in the old
1619: * indirect map. If this is the case, then just reset the size of the
1620: * vstruct map and we are done. If the new size will not
1621: * fit into the old indirect map, then we have to allocate a new
1622: * indirect map and copy the old map pointers into this new map.
1623: *
1624: * If we are going from direct to indirect, then we have to allocate a
1625: * new indirect map and copy the old direct pages into the first
1626: * indirect page of the new map.
1627: * NOTE: allocating memory here is dangerous, as we're in the
1628: * pageout path.
1629: */
1630: if (INDIRECT_CLMAP(new_size)) {
1631: int new_map_size = INDIRECT_CLMAP_SIZE(new_size);
1632:
1633: /*
1634: * Get a new indirect map and zero it.
1635: */
1636: old_map_size = INDIRECT_CLMAP_SIZE(vs->vs_size);
1637: if (vs->vs_indirect &&
1638: (new_map_size == old_map_size)) {
1639: bs_commit(new_size - vs->vs_size);
1640: vs->vs_size = new_size;
1641: return 0;
1642: }
1643:
1644: new_imap = (struct vs_map **)kalloc(new_map_size);
1645: if (new_imap == NULL) {
1646: return -1;
1647: }
1648: memset(new_imap, 0, new_map_size);
1649:
1650: if (vs->vs_indirect) {
1651: /* Copy old entries into new map */
1652: memcpy(new_imap, vs->vs_imap, old_map_size);
1653: /* Arrange to free the old map */
1654: old_map = (void *) vs->vs_imap;
1655: newdsize = 0;
1656: } else { /* Old map was a direct map */
1657: /* Allocate an indirect page */
1658: if ((new_imap[0] = (struct vs_map *)
1659: kalloc(CLMAP_THRESHOLD)) == NULL) {
1660: kfree((vm_offset_t)new_imap, new_map_size);
1661: return -1;
1662: }
1663: new_dmap = new_imap[0];
1664: newdsize = CLMAP_ENTRIES;
1665: }
1666: } else {
1667: new_imap = NULL;
1668: newdsize = new_size;
1669: /*
1670: * If the new map is a direct map, then the old map must
1671: * also have been a direct map. All we have to do is
1672: * to allocate a new direct map, copy the old entries
1673: * into it and free the old map.
1674: */
1675: if ((new_dmap = (struct vs_map *)
1676: kalloc(CLMAP_SIZE(new_size))) == NULL) {
1677: return -1;
1678: }
1679: }
1680: if (newdsize) {
1681:
1682: /* Free the old map */
1683: old_map = (void *) vs->vs_dmap;
1684: old_map_size = CLMAP_SIZE(vs->vs_size);
1685:
1686: /* Copy info from the old map into the new map */
1687: memcpy(new_dmap, vs->vs_dmap, old_map_size);
1688:
1689: /* Initialize the rest of the new map */
1690: for (i = vs->vs_size; i < newdsize; i++)
1691: VSM_CLR(new_dmap[i]);
1692: }
1693: if (new_imap) {
1694: vs->vs_imap = new_imap;
1695: vs->vs_indirect = TRUE;
1696: } else
1697: vs->vs_dmap = new_dmap;
1698: bs_commit(new_size - vs->vs_size);
1699: vs->vs_size = new_size;
1700: if (old_map)
1701: kfree((vm_offset_t)old_map, old_map_size);
1702: return 0;
1703: }
1704:
1705: vm_offset_t
1706: ps_clmap(
1707: vstruct_t vs,
1708: vm_offset_t offset,
1709: struct clmap *clmap,
1710: int flag,
1711: vm_size_t size,
1712: int error)
1713: {
1714: vm_offset_t cluster; /* The cluster of offset. */
1715: vm_offset_t newcl; /* The new cluster allocated. */
1716: vm_offset_t newoff;
1717: int i;
1718: struct vs_map *vsmap;
1719: static char here[] = "ps_clmap";
1720:
1721: VS_MAP_LOCK(vs);
1722:
1723: ASSERT(vs->vs_dmap);
1724: cluster = atop(offset) >> vs->vs_clshift;
1725:
1726: /*
1727: * Initialize cluster error value
1728: */
1729: clmap->cl_error = 0;
1730:
1731: /*
1732: * If the object has grown, extend the page map.
1733: */
1734: if (cluster >= vs->vs_size) {
1735: if (flag == CL_FIND) {
1736: /* Do not allocate if just doing a lookup */
1737: VS_MAP_UNLOCK(vs);
1738: return (vm_offset_t) -1;
1739: }
1740: if (ps_map_extend(vs, cluster + 1)) {
1741: VS_MAP_UNLOCK(vs);
1742: return (vm_offset_t) -1;
1743: }
1744: }
1745:
1746: /*
1747: * Look for the desired cluster. If the map is indirect, then we
1748: * have a two level lookup. First find the indirect block, then
1749: * find the actual cluster. If the indirect block has not yet
1750: * been allocated, then do so. If the cluster has not yet been
1751: * allocated, then do so.
1752: *
1753: * If any of the allocations fail, then return an error.
1754: * Don't allocate if just doing a lookup.
1755: */
1756: if (vs->vs_indirect) {
1757: long ind_block = cluster/CLMAP_ENTRIES;
1758:
1759: /* Is the indirect block allocated? */
1760: vsmap = vs->vs_imap[ind_block];
1761: if (vsmap == NULL) {
1762: if (flag == CL_FIND) {
1763: VS_MAP_UNLOCK(vs);
1764: return (vm_offset_t) -1;
1765: }
1766:
1767: /* Allocate the indirect block */
1768: vsmap = (struct vs_map *) kalloc(CLMAP_THRESHOLD);
1769: if (vsmap == NULL) {
1770: VS_MAP_UNLOCK(vs);
1771: return (vm_offset_t) -1;
1772: }
1773: /* Initialize the cluster offsets */
1774: for (i = 0; i < CLMAP_ENTRIES; i++)
1775: VSM_CLR(vsmap[i]);
1776: vs->vs_imap[ind_block] = vsmap;
1777: }
1778: } else
1779: vsmap = vs->vs_dmap;
1780:
1781: ASSERT(vsmap);
1782: vsmap += cluster%CLMAP_ENTRIES;
1783:
1784: /*
1785: * At this point, vsmap points to the struct vs_map desired.
1786: *
1787: * Look in the map for the cluster, if there was an error on a
1788: * previous write, flag it and return. If it is not yet
1789: * allocated, then allocate it, if we're writing; if we're
1790: * doing a lookup and the cluster's not allocated, return error.
1791: */
1792: if (VSM_ISERR(*vsmap)) {
1793: clmap->cl_error = VSM_GETERR(*vsmap);
1794: VS_MAP_UNLOCK(vs);
1795: return (vm_offset_t) -1;
1796: } else if (VSM_ISCLR(*vsmap)) {
1797: int psindex;
1798:
1799: if (flag == CL_FIND) {
1800: /*
1801: * If there's an error and the entry is clear, then
1802: * we've run out of swap space. Record the error
1803: * here and return.
1804: */
1805: if (error) {
1806: VSM_SETERR(*vsmap, error);
1807: }
1808: VS_MAP_UNLOCK(vs);
1809: return (vm_offset_t) -1;
1810: } else {
1811: /*
1812: * Attempt to allocate a cluster from the paging segment
1813: */
1814: newcl = ps_allocate_cluster(vs, &psindex,
1815: PAGING_SEGMENT_NULL);
1816: if (newcl == -1) {
1817: VS_MAP_UNLOCK(vs);
1818: return (vm_offset_t) -1;
1819: }
1820: VSM_CLR(*vsmap);
1821: VSM_SETCLOFF(*vsmap, newcl);
1822: VSM_SETPS(*vsmap, psindex);
1823: }
1824: } else
1825: newcl = VSM_CLOFF(*vsmap);
1826:
1827: /*
1828: * Fill in pertinent fields of the clmap
1829: */
1830: clmap->cl_ps = VSM_PS(*vsmap);
1831: clmap->cl_numpages = VSCLSIZE(vs);
1832: clmap->cl_bmap.clb_map = (unsigned int) VSM_BMAP(*vsmap);
1833:
1834: /*
1835: * Byte offset in paging segment is byte offset to cluster plus
1836: * byte offset within cluster. It looks ugly, but should be
1837: * relatively quick.
1838: */
1839: ASSERT(trunc_page(offset) == offset);
1840: newcl = ptoa(newcl) << vs->vs_clshift;
1841: newoff = offset & ((1<<(vm_page_shift + vs->vs_clshift)) - 1);
1842: if (flag == CL_ALLOC) {
1843: /*
1844: * set bits in the allocation bitmap according to which
1845: * pages were requested. size is in bytes.
1846: */
1847: i = atop(newoff);
1848: while ((size > 0) && (i < VSCLSIZE(vs))) {
1849: VSM_SETALLOC(*vsmap, i);
1850: i++;
1851: size -= vm_page_size;
1852: }
1853: }
1854: clmap->cl_alloc.clb_map = (unsigned int) VSM_ALLOC(*vsmap);
1855: if (newoff) {
1856: /*
1857: * Offset is not cluster aligned, so number of pages
1858: * and bitmaps must be adjusted
1859: */
1860: clmap->cl_numpages -= atop(newoff);
1861: CLMAP_SHIFT(clmap, vs);
1862: CLMAP_SHIFTALLOC(clmap, vs);
1863: }
1864:
1865: /*
1866: *
1867: * The setting of valid bits and handling of write errors
1868: * must be done here, while we hold the lock on the map.
1869: * It logically should be done in ps_vs_write_complete().
1870: * The size and error information has been passed from
1871: * ps_vs_write_complete(). If the size parameter is non-zero,
1872: * then there is work to be done. If error is also non-zero,
1873: * then the error number is recorded in the cluster and the
1874: * entire cluster is in error.
1875: */
1876: if (size && flag == CL_FIND) {
1877: vm_offset_t off = (vm_offset_t) 0;
1878:
1879: if (!error) {
1880: for (i = VSCLSIZE(vs) - clmap->cl_numpages; size > 0;
1881: i++) {
1882: VSM_SETPG(*vsmap, i);
1883: size -= vm_page_size;
1884: }
1885: ASSERT(i <= VSCLSIZE(vs));
1886: } else {
1887: BS_STAT(clmap->cl_ps->ps_bs,
1888: clmap->cl_ps->ps_bs->bs_pages_out_fail +=
1889: atop(size));
1890: off = VSM_CLOFF(*vsmap);
1891: VSM_SETERR(*vsmap, error);
1892: }
1893: /*
1894: * Deallocate cluster if error, and no valid pages
1895: * already present.
1896: */
1897: if (off != (vm_offset_t) 0)
1898: ps_deallocate_cluster(clmap->cl_ps, off);
1899: VS_MAP_UNLOCK(vs);
1900: return (vm_offset_t) 0;
1901: } else
1902: VS_MAP_UNLOCK(vs);
1903:
1904: DEBUG(DEBUG_VS_INTERNAL,
1905: ("returning 0x%X,vs=0x%X,vsmap=0x%X,flag=%d\n",
1906: newcl+newoff, (int) vs, (int) vsmap, flag));
1907: DEBUG(DEBUG_VS_INTERNAL,
1908: (" clmap->cl_ps=0x%X,cl_numpages=%d,clbmap=0x%x,cl_alloc=%x\n",
1909: (int) clmap->cl_ps, clmap->cl_numpages,
1910: (int) clmap->cl_bmap.clb_map, (int) clmap->cl_alloc.clb_map));
1911:
1912: return (newcl + newoff);
1913: }
1914:
1915: void ps_clunmap(vstruct_t, vm_offset_t, vm_size_t); /* forward */
1916:
1917: void
1918: ps_clunmap(
1919: vstruct_t vs,
1920: vm_offset_t offset,
1921: vm_size_t length)
1922: {
1923: vm_offset_t cluster; /* The cluster number of offset */
1924: struct vs_map *vsmap;
1925: static char here[] = "ps_clunmap";
1926:
1927: VS_MAP_LOCK(vs);
1928:
1929: /*
1930: * Loop through all clusters in this range, freeing paging segment
1931: * clusters and map entries as encountered.
1932: */
1933: while (length > 0) {
1934: vm_offset_t newoff;
1935: int i;
1936:
1937: cluster = atop(offset) >> vs->vs_clshift;
1938: if (vs->vs_indirect) /* indirect map */
1939: vsmap = vs->vs_imap[cluster/CLMAP_ENTRIES];
1940: else
1941: vsmap = vs->vs_dmap;
1942: if (vsmap == NULL) {
1943: VS_MAP_UNLOCK(vs);
1944: return;
1945: }
1946: vsmap += cluster%CLMAP_ENTRIES;
1947: if (VSM_ISCLR(*vsmap)) {
1948: length -= vm_page_size;
1949: offset += vm_page_size;
1950: continue;
1951: }
1952: /*
1953: * We've got a valid mapping. Clear it and deallocate
1954: * paging segment cluster pages.
1955: * Optimize for entire cluster cleraing.
1956: */
1957: if (newoff = (offset&((1<<(vm_page_shift+vs->vs_clshift))-1))) {
1958: /*
1959: * Not cluster aligned.
1960: */
1961: ASSERT(trunc_page(newoff) == newoff);
1962: i = atop(newoff);
1963: } else
1964: i = 0;
1965: while ((i < VSCLSIZE(vs)) && (length > 0)) {
1966: VSM_CLRPG(*vsmap, i);
1967: VSM_CLRALLOC(*vsmap, i);
1968: length -= vm_page_size;
1969: offset += vm_page_size;
1970: i++;
1971: }
1972:
1973: /*
1974: * If map entry is empty, clear and deallocate cluster.
1975: */
1976: if (!VSM_ALLOC(*vsmap)) {
1977: ps_deallocate_cluster(VSM_PS(*vsmap),
1978: VSM_CLOFF(*vsmap));
1979: VSM_CLR(*vsmap);
1980: }
1981: }
1982:
1983: VS_MAP_UNLOCK(vs);
1984: }
1985:
1986: void ps_vs_write_complete(vstruct_t, vm_offset_t, vm_size_t, int); /* forward */
1987:
1988: void
1989: ps_vs_write_complete(
1990: vstruct_t vs,
1991: vm_offset_t offset,
1992: vm_size_t size,
1993: int error)
1994: {
1995: struct clmap clmap;
1996:
1997: /*
1998: * Get the struct vsmap for this cluster.
1999: * Use READ, even though it was written, because the
2000: * cluster MUST be present, unless there was an error
2001: * in the original ps_clmap (e.g. no space), in which
2002: * case, nothing happens.
2003: *
2004: * Must pass enough information to ps_clmap to allow it
2005: * to set the vs_map structure bitmap under lock.
2006: */
2007: (void) ps_clmap(vs, offset, &clmap, CL_FIND, size, error);
2008: }
2009:
2010: void vs_cl_write_complete(vstruct_t, paging_segment_t, vm_offset_t, vm_offset_t, vm_size_t, boolean_t, int); /* forward */
2011:
2012: void
2013: vs_cl_write_complete(
2014: vstruct_t vs,
2015: paging_segment_t ps,
2016: vm_offset_t offset,
2017: vm_offset_t addr,
2018: vm_size_t size,
2019: boolean_t async,
2020: int error)
2021: {
2022: static char here[] = "vs_cl_write_complete";
2023: kern_return_t kr;
2024:
2025: if (error) {
2026: /*
2027: * For internal objects, the error is recorded on a
2028: * per-cluster basis by ps_clmap() which is called
2029: * by ps_vs_write_complete() below.
2030: */
2031: dprintf(("write failed error = 0x%x\n", error));
2032: /* add upl_abort code here */
2033: } else
2034: GSTAT(global_stats.gs_pages_out += atop(size));
2035: /*
2036: * Notify the vstruct mapping code, so it can do its accounting.
2037: */
2038: ps_vs_write_complete(vs, offset, size, error);
2039:
2040: if (async) {
2041: VS_LOCK(vs);
2042: ASSERT(vs->vs_async_pending > 0);
2043: vs->vs_async_pending -= size;
2044: if (vs->vs_async_pending == 0) {
2045: VS_UNLOCK(vs);
2046: /* mutex_unlock(&vs->vs_waiting_async); */
2047: thread_wakeup(&vs->vs_waiting_async);
2048: } else {
2049: VS_UNLOCK(vs);
2050: }
2051: }
2052: }
2053:
2054: #ifdef DEVICE_PAGING
2055: kern_return_t device_write_reply(MACH_PORT_FACE, kern_return_t, io_buf_len_t);
2056:
2057: kern_return_t
2058: device_write_reply(
2059: MACH_PORT_FACE reply_port,
2060: kern_return_t device_code,
2061: io_buf_len_t bytes_written)
2062: {
2063: struct vs_async *vsa;
2064: static char here[] = "device_write_reply";
2065:
2066: vsa = (struct vs_async *)
2067: ((struct vstruct_alias *)(reply_port->alias))->vs;
2068:
2069: if (device_code == KERN_SUCCESS && bytes_written != vsa->vsa_size) {
2070: device_code = KERN_FAILURE;
2071: }
2072:
2073: vsa->vsa_error = device_code;
2074:
2075:
2076: ASSERT(vsa->vsa_vs != VSTRUCT_NULL);
2077: if(vsa->vsa_flags & VSA_TRANSFER) {
2078: /* revisit when async disk segments redone */
2079: if(vsa->vsa_error) {
2080: /* need to consider error condition. re-write data or */
2081: /* throw it away here. */
2082: vm_offset_t ioaddr;
2083: if(vm_map_copyout(kernel_map, &ioaddr,
2084: (vm_map_copy_t)vsa->vsa_addr) != KERN_SUCCESS)
2085: panic("vs_cluster_write: unable to copy source list\n");
2086: vm_deallocate(kernel_map, ioaddr, vsa->vsa_size);
2087: }
2088: ps_vs_write_complete(vsa->vsa_vs, vsa->vsa_offset,
2089: vsa->vsa_size, vsa->vsa_error);
2090: } else {
2091: vs_cl_write_complete(vsa->vsa_vs, vsa->vsa_ps, vsa->vsa_offset,
2092: vsa->vsa_addr, vsa->vsa_size, TRUE,
2093: vsa->vsa_error);
2094: }
2095: VS_FREE_ASYNC(vsa);
2096:
2097: return KERN_SUCCESS;
2098: }
2099:
2100: kern_return_t device_write_reply_inband(MACH_PORT_FACE, kern_return_t, io_buf_len_t);
2101: kern_return_t
2102: device_write_reply_inband(
2103: MACH_PORT_FACE reply_port,
2104: kern_return_t return_code,
2105: io_buf_len_t bytes_written)
2106: {
2107: panic("device_write_reply_inband: illegal");
2108: return KERN_SUCCESS;
2109: }
2110:
2111: kern_return_t device_read_reply(MACH_PORT_FACE, kern_return_t, io_buf_ptr_t, mach_msg_type_number_t);
2112: kern_return_t
2113: device_read_reply(
2114: MACH_PORT_FACE reply_port,
2115: kern_return_t return_code,
2116: io_buf_ptr_t data,
2117: mach_msg_type_number_t dataCnt)
2118: {
2119: struct vs_async *vsa;
2120: vsa = (struct vs_async *)
2121: ((struct vstruct_alias *)(reply_port->alias))->vs;
2122: vsa->vsa_addr = (vm_offset_t)data;
2123: vsa->vsa_size = (vm_size_t)dataCnt;
2124: vsa->vsa_error = return_code;
2125: thread_wakeup(&vsa->vsa_lock);
2126: return KERN_SUCCESS;
2127: }
2128:
2129: kern_return_t device_read_reply_inband(MACH_PORT_FACE, kern_return_t, io_buf_ptr_inband_t, mach_msg_type_number_t);
2130: kern_return_t
2131: device_read_reply_inband(
2132: MACH_PORT_FACE reply_port,
2133: kern_return_t return_code,
2134: io_buf_ptr_inband_t data,
2135: mach_msg_type_number_t dataCnt)
2136: {
2137: panic("device_read_reply_inband: illegal");
2138: return KERN_SUCCESS;
2139: }
2140:
2141: kern_return_t device_read_reply_overwrite(MACH_PORT_FACE, kern_return_t, io_buf_len_t);
2142: kern_return_t
2143: device_read_reply_overwrite(
2144: MACH_PORT_FACE reply_port,
2145: kern_return_t return_code,
2146: io_buf_len_t bytes_read)
2147: {
2148: panic("device_read_reply_overwrite: illegal\n");
2149: return KERN_SUCCESS;
2150: }
2151:
2152: kern_return_t device_open_reply(MACH_PORT_FACE, kern_return_t, MACH_PORT_FACE);
2153: kern_return_t
2154: device_open_reply(
2155: MACH_PORT_FACE reply_port,
2156: kern_return_t return_code,
2157: MACH_PORT_FACE device_port)
2158: {
2159: panic("device_open_reply: illegal\n");
2160: return KERN_SUCCESS;
2161: }
2162:
2163: kern_return_t ps_read_device(paging_segment_t, vm_offset_t, vm_offset_t *, unsigned int, unsigned int *); /* forward */
2164:
2165: kern_return_t
2166: ps_read_device(
2167: paging_segment_t ps,
2168: vm_offset_t offset,
2169: vm_offset_t *bufferp,
2170: unsigned int size,
2171: unsigned int *residualp)
2172: {
2173: kern_return_t kr;
2174: recnum_t dev_offset;
2175: unsigned int bytes_wanted;
2176: unsigned int bytes_read;
2177: unsigned int total_read;
2178: vm_offset_t dev_buffer;
2179: vm_offset_t buf_ptr;
2180: unsigned int records_read;
2181: static char here[] = "ps_read_device";
2182: struct vs_async *vsa;
2183: mutex_t vs_waiting_read_reply;
2184:
2185: device_t device;
2186: vm_map_copy_t device_data = NULL;
2187: default_pager_thread_t *dpt = NULL;
2188:
2189: device = dev_port_lookup(ps->ps_device);
2190: clustered_reads[atop(size)]++;
2191:
2192: dev_offset = (ps->ps_offset +
2193: (offset >> (vm_page_shift - ps->ps_record_shift)));
2194: bytes_wanted = size;
2195: total_read = 0;
2196: *bufferp = (vm_offset_t)NULL;
2197:
2198: do {
2199: vsa = VS_ALLOC_ASYNC();
2200: if (vsa) {
2201: vsa->vsa_vs = NULL;
2202: vsa->vsa_addr = 0;
2203: vsa->vsa_offset = 0;
2204: vsa->vsa_size = 0;
2205: vsa->vsa_ps = NULL;
2206: }
2207: mutex_init(&vsa->vsa_lock, ETAP_DPAGE_VSSEQNO);
2208: ip_lock(vsa->reply_port);
2209: vsa->reply_port->ip_sorights++;
2210: ip_reference(vsa->reply_port);
2211: ip_unlock(vsa->reply_port);
2212: kr = ds_device_read_common(device,
2213: vsa->reply_port,
2214: (mach_msg_type_name_t)
2215: MACH_MSG_TYPE_MOVE_SEND_ONCE,
2216: (dev_mode_t) 0,
2217: dev_offset,
2218: bytes_wanted,
2219: (IO_READ | IO_CALL),
2220: (io_buf_ptr_t *) &dev_buffer,
2221: (mach_msg_type_number_t *) &bytes_read);
2222: if(kr == MIG_NO_REPLY) {
2223: assert_wait(&vsa->vsa_lock, THREAD_UNINT);
2224: thread_block((void(*)(void))0);
2225:
2226: dev_buffer = vsa->vsa_addr;
2227: bytes_read = (unsigned int)vsa->vsa_size;
2228: kr = vsa->vsa_error;
2229: }
2230: VS_FREE_ASYNC(vsa);
2231: if (kr != KERN_SUCCESS || bytes_read == 0) {
2232: break;
2233: }
2234: total_read += bytes_read;
2235:
2236: /*
2237: * If we got the entire range, use the returned dev_buffer.
2238: */
2239: if (bytes_read == size) {
2240: *bufferp = (vm_offset_t)dev_buffer;
2241: break;
2242: }
2243:
2244: #if 1
2245: dprintf(("read only %d bytes out of %d\n",
2246: bytes_read, bytes_wanted));
2247: #endif
2248: if(dpt == NULL) {
2249: dpt = get_read_buffer();
2250: buf_ptr = dpt->dpt_buffer;
2251: *bufferp = (vm_offset_t)buf_ptr;
2252: }
2253: /*
2254: * Otherwise, copy the data into the provided buffer (*bufferp)
2255: * and append the rest of the range as it comes in.
2256: */
2257: memcpy((void *) buf_ptr, (void *) dev_buffer, bytes_read);
2258: buf_ptr += bytes_read;
2259: bytes_wanted -= bytes_read;
2260: records_read = (bytes_read >>
2261: (vm_page_shift - ps->ps_record_shift));
2262: dev_offset += records_read;
2263: DEBUG(DEBUG_VS_INTERNAL,
2264: ("calling vm_deallocate(addr=0x%X,size=0x%X)\n",
2265: dev_buffer, bytes_read));
2266: if (vm_deallocate(kernel_map, dev_buffer, bytes_read)
2267: != KERN_SUCCESS)
2268: Panic("dealloc buf");
2269: } while (bytes_wanted);
2270:
2271: *residualp = size - total_read;
2272: if((dev_buffer != *bufferp) && (total_read != 0)) {
2273: vm_offset_t temp_buffer;
2274: vm_allocate(kernel_map, &temp_buffer, total_read, TRUE);
2275: memcpy((void *) temp_buffer, (void *) *bufferp, total_read);
2276: if(vm_map_copyin_page_list(kernel_map, temp_buffer, total_read,
2277: VM_MAP_COPYIN_OPT_SRC_DESTROY |
2278: VM_MAP_COPYIN_OPT_STEAL_PAGES |
2279: VM_MAP_COPYIN_OPT_PMAP_ENTER,
2280: (vm_map_copy_t *)&device_data, FALSE))
2281: panic("ps_read_device: cannot copyin locally provided buffer\n");
2282: }
2283: else if((kr == KERN_SUCCESS) && (total_read != 0) && (dev_buffer != 0)){
2284: if(vm_map_copyin_page_list(kernel_map, dev_buffer, bytes_read,
2285: VM_MAP_COPYIN_OPT_SRC_DESTROY |
2286: VM_MAP_COPYIN_OPT_STEAL_PAGES |
2287: VM_MAP_COPYIN_OPT_PMAP_ENTER,
2288: (vm_map_copy_t *)&device_data, FALSE))
2289: panic("ps_read_device: cannot copyin backing store provided buffer\n");
2290: }
2291: else {
2292: device_data = NULL;
2293: }
2294: *bufferp = (vm_offset_t)device_data;
2295:
2296: if(dpt != NULL) {
2297: /* Free the receive buffer */
2298: dpt->checked_out = 0;
2299: thread_wakeup(&dpt_array);
2300: }
2301: return KERN_SUCCESS;
2302: }
2303:
2304: kern_return_t ps_write_device(paging_segment_t, vm_offset_t, vm_offset_t, unsigned int, struct vs_async *); /* forward */
2305:
2306: kern_return_t
2307: ps_write_device(
2308: paging_segment_t ps,
2309: vm_offset_t offset,
2310: vm_offset_t addr,
2311: unsigned int size,
2312: struct vs_async *vsa)
2313: {
2314: recnum_t dev_offset;
2315: io_buf_len_t bytes_to_write, bytes_written;
2316: recnum_t records_written;
2317: kern_return_t kr;
2318: MACH_PORT_FACE reply_port;
2319: static char here[] = "ps_write_device";
2320:
2321:
2322:
2323: clustered_writes[atop(size)]++;
2324:
2325: dev_offset = (ps->ps_offset +
2326: (offset >> (vm_page_shift - ps->ps_record_shift)));
2327: bytes_to_write = size;
2328:
2329: if (vsa) {
2330: /*
2331: * Asynchronous write.
2332: */
2333: reply_port = vsa->reply_port;
2334: ip_lock(reply_port);
2335: reply_port->ip_sorights++;
2336: ip_reference(reply_port);
2337: ip_unlock(reply_port);
2338: {
2339: device_t device;
2340: device = dev_port_lookup(ps->ps_device);
2341:
2342: vsa->vsa_addr = addr;
2343: kr=ds_device_write_common(device,
2344: reply_port,
2345: (mach_msg_type_name_t) MACH_MSG_TYPE_MOVE_SEND_ONCE,
2346: (dev_mode_t) 0,
2347: dev_offset,
2348: (io_buf_ptr_t) addr,
2349: size,
2350: (IO_WRITE | IO_CALL),
2351: &bytes_written);
2352: }
2353: if ((kr != KERN_SUCCESS) && (kr != MIG_NO_REPLY)) {
2354: if (verbose)
2355: dprintf(("%s0x%x, addr=0x%x,"
2356: "size=0x%x,offset=0x%x\n",
2357: "device_write_request returned ",
2358: kr, addr, size, offset));
2359: BS_STAT(ps->ps_bs,
2360: ps->ps_bs->bs_pages_out_fail += atop(size));
2361: /* do the completion notification to free resources */
2362: device_write_reply(reply_port, kr, 0);
2363: return PAGER_ERROR;
2364: }
2365: } else do {
2366: /*
2367: * Synchronous write.
2368: */
2369: {
2370: device_t device;
2371: device = dev_port_lookup(ps->ps_device);
2372: kr=ds_device_write_common(device,
2373: IP_NULL, 0,
2374: (dev_mode_t) 0,
2375: dev_offset,
2376: (io_buf_ptr_t) addr,
2377: size,
2378: (IO_WRITE | IO_SYNC | IO_KERNEL_BUF),
2379: &bytes_written);
2380: }
2381: if (kr != KERN_SUCCESS) {
2382: dprintf(("%s0x%x, addr=0x%x,size=0x%x,offset=0x%x\n",
2383: "device_write returned ",
2384: kr, addr, size, offset));
2385: BS_STAT(ps->ps_bs,
2386: ps->ps_bs->bs_pages_out_fail += atop(size));
2387: return PAGER_ERROR;
2388: }
2389: if (bytes_written & ((vm_page_size >> ps->ps_record_shift) - 1))
2390: Panic("fragmented write");
2391: records_written = (bytes_written >>
2392: (vm_page_shift - ps->ps_record_shift));
2393: dev_offset += records_written;
2394: #if 1
2395: if (bytes_written != bytes_to_write) {
2396: dprintf(("wrote only %d bytes out of %d\n",
2397: bytes_written, bytes_to_write));
2398: }
2399: #endif
2400: bytes_to_write -= bytes_written;
2401: addr += bytes_written;
2402: } while (bytes_to_write > 0);
2403:
2404: return PAGER_SUCCESS;
2405: }
2406:
2407:
2408: #else /* !DEVICE_PAGING */
2409:
2410: kern_return_t
2411: ps_read_device(
2412: paging_segment_t ps,
2413: vm_offset_t offset,
2414: vm_offset_t *bufferp,
2415: unsigned int size,
2416: unsigned int *residualp)
2417: {
2418: panic("ps_read_device not supported");
2419: }
2420:
2421: ps_write_device(
2422: paging_segment_t ps,
2423: vm_offset_t offset,
2424: vm_offset_t addr,
2425: unsigned int size,
2426: struct vs_async *vsa)
2427: {
2428: panic("ps_write_device not supported");
2429: }
2430:
2431: #endif /* DEVICE_PAGING */
2432: void pvs_object_data_provided(vstruct_t, upl_t, vm_offset_t, vm_size_t); /* forward */
2433:
2434: void
2435: pvs_object_data_provided(
2436: vstruct_t vs,
2437: upl_t page_list,
2438: vm_offset_t offset,
2439: vm_size_t size)
2440: {
2441: static char here[] = "pvs_object_data_provided";
2442:
2443: DEBUG(DEBUG_VS_INTERNAL,
2444: ("buffer=0x%x,offset=0x%x,size=0x%x\n",
2445: page_list, offset, size));
2446:
2447: ASSERT(size > 0);
2448: GSTAT(global_stats.gs_pages_in += atop(size));
2449:
2450:
2451: #if USE_PRECIOUS
2452: ps_clunmap(vs, offset, size);
2453: #endif /* USE_PRECIOUS */
2454:
2455: if(size < (page_list->size)) {
2456: upl_commit_range(page_list, 0, size, FALSE, NULL);
2457: } else {
2458: upl_commit(page_list, NULL);
2459: }
2460: }
2461:
2462: kern_return_t
2463: pvs_cluster_read(
2464: vstruct_t vs,
2465: vm_offset_t offset,
2466: vm_size_t cnt)
2467: {
2468: vm_offset_t actual_offset;
2469: vm_offset_t buffer;
2470: paging_segment_t ps;
2471: struct clmap clmap;
2472: upl_t page_list;
2473: kern_return_t error = KERN_SUCCESS;
2474: int size, size_wanted, i;
2475: unsigned int residual;
2476: unsigned int request_flags;
2477: int unavail_size;
2478: default_pager_thread_t *dpt;
2479: boolean_t dealloc;
2480: static char here[] = "pvs_cluster_read";
2481:
2482: /*
2483: * This loop will be executed once per cluster referenced.
2484: * Typically this means once, since it's unlikely that the
2485: * VM system will ask for anything spanning cluster boundaries.
2486: *
2487: * If there are holes in a cluster (in a paging segment), we stop
2488: * reading at the hole, inform the VM of any data read, inform
2489: * the VM of an unavailable range, then loop again, hoping to
2490: * find valid pages later in the cluster. This continues until
2491: * the entire range has been examined, and read, if present.
2492: */
2493: #if USE_PRECIOUS
2494: request_flags = UPL_NO_SYNC | UPL_CLEAN_IN_PLACE | UPL_PRECIOUS;
2495: #else
2496: request_flags = UPL_NO_SYNC | UPL_CLEAN_IN_PLACE;
2497: #endif
2498: while (cnt && (error == KERN_SUCCESS)) {
2499: actual_offset = ps_clmap(vs, offset, &clmap, CL_FIND, 0, 0);
2500:
2501: if (actual_offset == (vm_offset_t) -1) {
2502:
2503: /*
2504: * Either a failure due to an error on a previous
2505: * write or a zero fill on demand page. In either case,
2506: * optimize to do one reply for all pages up to next
2507: * cluster boundary.
2508: */
2509: unsigned int local_size, clmask, clsize;
2510:
2511: clmask = (vm_page_size << vs->vs_clshift) - 1;
2512: clsize = vm_page_size << vs->vs_clshift;
2513: clmask = clsize - 1;
2514: local_size = clsize - (offset & clmask);
2515: ASSERT(local_size);
2516: local_size = MIN(local_size, cnt);
2517:
2518: upl_system_list_request((vm_object_t)
2519: vs->vs_control_port->ip_kobject,
2520: offset, local_size, local_size,
2521: &page_list, NULL, 0, request_flags);
2522: if (clmap.cl_error) {
2523: upl_abort(page_list, UPL_ABORT_ERROR);
2524: } else {
2525: upl_abort(page_list, UPL_ABORT_UNAVAILABLE);
2526: }
2527:
2528: cnt -= local_size;
2529: offset += local_size;
2530: continue;
2531: }
2532:
2533: /*
2534: * Count up contiguous available or unavailable
2535: * pages.
2536: */
2537: ps = CLMAP_PS(clmap);
2538: ASSERT(ps);
2539: size = 0;
2540: unavail_size = 0;
2541: for (i = 0;
2542: (size < cnt) && (unavail_size < cnt) &&
2543: (i < CLMAP_NPGS(clmap)); i++) {
2544: if (CLMAP_ISSET(clmap, i)) {
2545: if (unavail_size != 0)
2546: break;
2547: size += vm_page_size;
2548: BS_STAT(ps->ps_bs,
2549: ps->ps_bs->bs_pages_in++);
2550: } else {
2551: if (size != 0)
2552: break;
2553: unavail_size += vm_page_size;
2554: }
2555: }
2556: /*
2557: * Let VM system know about holes in clusters.
2558: */
2559: if (size == 0) {
2560: ASSERT(unavail_size);
2561: GSTAT(global_stats.gs_pages_unavail +=
2562: atop(unavail_size));
2563: upl_system_list_request((vm_object_t)
2564: vs->vs_control_port->ip_kobject,
2565: offset, unavail_size,
2566: unavail_size, &page_list, NULL, 0,
2567: request_flags);
2568: upl_abort(page_list, UPL_ABORT_UNAVAILABLE);
2569: cnt -= unavail_size;
2570: offset += unavail_size;
2571: continue;
2572: }
2573:
2574: upl_system_list_request((vm_object_t)
2575: vs->vs_control_port->ip_kobject,
2576: offset, size, size, &page_list,
2577: NULL, 0, request_flags);
2578: if(ps->ps_segtype == PS_PARTITION) {
2579: /*
2580: error = ps_read_device(ps, actual_offset, page_list,
2581: size, &residual);
2582: */
2583: } else {
2584: vm_offset_t ioaddr;
2585:
2586: upl_map(kernel_map, page_list, &ioaddr);
2587: error = ps_read_file(ps, actual_offset, ioaddr,
2588: size, &residual);
2589: upl_un_map(kernel_map, page_list);
2590: }
2591:
2592: /*
2593: * Adjust counts and send response to VM. Optimize for the
2594: * common case, i.e. no error and/or partial data.
2595: * If there was an error, then we need to error the entire
2596: * range, even if some data was successfully read.
2597: * If there was a partial read we may supply some
2598: * data and may error some as well. In all cases the
2599: * VM must receive some notification for every page in the
2600: * range.
2601: */
2602: if ((error == KERN_SUCCESS) && (residual == 0)) {
2603: /*
2604: * Got everything we asked for, supply the data to
2605: * the VM. Note that as a side effect of supplying
2606: * the data, the buffer holding the supplied data is
2607: * deallocated from the pager's address space.
2608: */
2609: pvs_object_data_provided(vs, page_list, offset, size);
2610: } else {
2611: size_wanted = size;
2612: if (error == KERN_SUCCESS) {
2613: if (residual == size) {
2614: /*
2615: * If a read operation returns no error
2616: * and no data moved, we turn it into
2617: * an error, assuming we're reading at
2618: * or beyong EOF.
2619: * Fall through and error the entire
2620: * range.
2621: */
2622: error = KERN_FAILURE;
2623: } else {
2624: /*
2625: * Otherwise, we have partial read. If
2626: * the part read is a integral number
2627: * of pages supply it. Otherwise round
2628: * it up to a page boundary, zero fill
2629: * the unread part, and supply it.
2630: * Fall through and error the remainder
2631: * of the range, if any.
2632: */
2633: int fill, lsize;
2634:
2635: fill = residual & ~vm_page_size;
2636: lsize = (size - residual) + fill;
2637: pvs_object_data_provided(vs, page_list,
2638: offset, lsize);
2639: cnt -= lsize;
2640: offset += lsize;
2641: if (size -= lsize) {
2642: error = KERN_FAILURE;
2643: }
2644: }
2645: }
2646:
2647: /*
2648: * If there was an error in any part of the range, tell
2649: * the VM. Deallocate the remainder of the buffer.
2650: * Note that error is explicitly checked again since
2651: * it can be modified above.
2652: */
2653: if (error != KERN_SUCCESS) {
2654: BS_STAT(ps->ps_bs,
2655: ps->ps_bs->bs_pages_in_fail +=
2656: atop(size));
2657: upl_abort(page_list, UPL_ABORT_RESTART);
2658: }
2659: }
2660: cnt -= size;
2661: offset += size;
2662:
2663: } /* END while (cnt && (error == 0)) */
2664: return error;
2665: }
2666:
2667: int vs_do_async_write = 1;
2668:
2669: kern_return_t
2670: vs_cluster_write(
2671: vstruct_t vs,
2672: vm_offset_t offset,
2673: vm_offset_t addr,
2674: vm_size_t cnt,
2675: boolean_t dp_internal)
2676: {
2677: vm_offset_t actual_offset; /* Offset within paging segment */
2678: vm_offset_t size;
2679: vm_offset_t transfer_size;
2680: vm_offset_t subx_size;
2681: int error = 0;
2682: struct clmap clmap;
2683: paging_segment_t ps;
2684: struct vs_async *vsa;
2685: vm_map_copy_t copy;
2686: static char here[] = "vs_cluster_write";
2687:
2688:
2689: upl_t upl;
2690:
2691: vm_offset_t mapped_data;
2692: vm_offset_t mobj_base_addr;
2693: vm_offset_t mobj_target_addr;
2694: int mobj_size;
2695: vm_offset_t vs_map_error_addr = 0;
2696: int page_index;
2697: int list_size;
2698: int cl_size;
2699:
2700: upl_page_info_t page_list[20];
2701: upl_page_info_t *pl;
2702:
2703:
2704: ps = PAGING_SEGMENT_NULL;
2705: if(!dp_internal) {
2706: int request_flags;
2707: int super_size;
2708:
2709: cl_size = (1 << vs->vs_clshift) * vm_page_size;
2710: if(bs_low) {
2711: super_size = cl_size;
2712: request_flags = UPL_NOBLOCK |
2713: UPL_RET_ONLY_DIRTY | UPL_COPYOUT_FROM |
2714: UPL_NO_SYNC;
2715: } else {
2716: super_size = VM_SUPER_CLUSTER;
2717: request_flags = UPL_NOBLOCK | UPL_CLEAN_IN_PLACE |
2718: UPL_RET_ONLY_DIRTY | UPL_COPYOUT_FROM |
2719: UPL_NO_SYNC;
2720: }
2721:
2722:
2723: pl = page_list;
2724: upl_system_list_request((vm_object_t)
2725: vs->vs_control_port->ip_kobject,
2726: offset, cnt, super_size,
2727: &upl, &pl,
2728: 20, request_flags);
2729:
2730: mobj_base_addr = upl->offset;
2731: list_size = upl->size;
2732:
2733: upl_map(kernel_map, upl, &mapped_data);
2734:
2735: /* Now parcel up the 64k transfer, do at most cluster size */
2736: /* at a time. */
2737: page_index = 0;
2738: mobj_target_addr = mobj_base_addr;
2739: for(transfer_size = list_size; transfer_size != 0;) {
2740: actual_offset = ps_clmap(vs, mobj_target_addr,
2741: &clmap, CL_ALLOC,
2742: transfer_size < cl_size ?
2743: transfer_size : cl_size, 0);
2744: if(actual_offset == (vm_offset_t) -1) {
2745: vs_map_error_addr = mobj_target_addr;
2746: error = 1;
2747: break;
2748: }
2749: cnt = MIN(transfer_size,
2750: CLMAP_NPGS(clmap) * vm_page_size);
2751: ps = CLMAP_PS(clmap);
2752: while(cnt > 0) {
2753: /* attempt to send entire cluster */
2754: subx_size = 0;
2755: while(cnt > 0) {
2756: /* do the biggest contiguous transfer of dirty */
2757: /* pages */
2758: if(UPL_DIRTY_PAGE(page_list, page_index) ||
2759: ((bs_low) &&
2760: UPL_PRECIOUS_PAGE(page_list, page_index))) {
2761: page_index++;
2762: subx_size += vm_page_size;
2763: cnt -= vm_page_size;
2764: } else {
2765: if(subx_size == 0) {
2766: actual_offset += vm_page_size;
2767: mobj_target_addr += vm_page_size;
2768: mapped_data += vm_page_size;
2769: transfer_size -= vm_page_size;
2770: page_index++;
2771: cnt -= vm_page_size;
2772: } else {
2773: break;
2774: }
2775: }
2776: }
2777: if(subx_size) {
2778: error = ps_write_file(ps, actual_offset,
2779: mapped_data, subx_size);
2780: if(error) {
2781: vs_map_error_addr = mobj_target_addr;
2782: }
2783: ps_vs_write_complete(vs, mobj_target_addr,
2784: subx_size, error);
2785: }
2786: if(error)
2787: break;
2788: actual_offset += subx_size;
2789: mobj_target_addr += subx_size;
2790: mapped_data += subx_size;
2791: transfer_size -= subx_size;
2792: subx_size = 0;
2793: }
2794: if(error)
2795: break;
2796: }
2797: upl_un_map(kernel_map, upl);
2798: if(error) {
2799: if(vs_map_error_addr > mobj_base_addr) {
2800: upl_commit_range(upl, 0,
2801: vs_map_error_addr - mobj_base_addr,
2802: FALSE, page_list);
2803: }
2804: upl_abort(upl, 0);
2805: } else {
2806: upl_commit(upl, page_list);
2807: }
2808: } else {
2809: assert(cnt <= (vm_page_size << vs->vs_clshift));
2810: mapped_data = addr;
2811: list_size = cnt;
2812:
2813: page_index = 0;
2814: /* The caller provides a mapped_data which is derived */
2815: /* from a temporary object. The targeted pages are */
2816: /* guaranteed to be set at offset 0 in the mapped_data */
2817: /* The actual offset however must still be derived */
2818: /* from the offset in the vs in question */
2819: mobj_base_addr = offset;
2820: mobj_target_addr = mobj_base_addr;
2821: for(transfer_size = list_size; transfer_size != 0;) {
2822: actual_offset = ps_clmap(vs, mobj_target_addr,
2823: &clmap, CL_ALLOC,
2824: transfer_size < cl_size ?
2825: transfer_size : cl_size, 0);
2826: if(actual_offset == (vm_offset_t) -1) {
2827: error = KERN_FAILURE;
2828: break;
2829: }
2830: cnt = MIN(transfer_size,
2831: CLMAP_NPGS(clmap) * vm_page_size);
2832: ps = CLMAP_PS(clmap);
2833: /* Assume that the caller has given us contiguous */
2834: /* pages */
2835: if(cnt) {
2836: error = ps_write_file(ps, actual_offset,
2837: mapped_data, cnt);
2838: ps_vs_write_complete(vs, mobj_target_addr,
2839: cnt, error);
2840: }
2841: actual_offset += cnt;
2842: mobj_target_addr += cnt;
2843: mapped_data += cnt;
2844: transfer_size -= cnt;
2845: cnt = 0;
2846:
2847: if(error)
2848: break;
2849: }
2850: }
2851: if(error)
2852: return KERN_FAILURE;
2853: else
2854: return KERN_SUCCESS;
2855: }
2856:
2857: vm_size_t
2858: ps_vstruct_allocated_size(
2859: vstruct_t vs)
2860: {
2861: int num_pages;
2862: struct vs_map *vsmap;
2863: int i, j, k;
2864:
2865: num_pages = 0;
2866: if (vs->vs_indirect) {
2867: /* loop on indirect maps */
2868: for (i = 0; i < INDIRECT_CLMAP_ENTRIES(vs->vs_size); i++) {
2869: vsmap = vs->vs_imap[i];
2870: if (vsmap == NULL)
2871: continue;
2872: /* loop on clusters in this indirect map */
2873: for (j = 0; j < CLMAP_ENTRIES; j++) {
2874: if (VSM_ISCLR(vsmap[j]) ||
2875: VSM_ISERR(vsmap[j]))
2876: continue;
2877: /* loop on pages in this cluster */
2878: for (k = 0; k < VSCLSIZE(vs); k++) {
2879: if ((VSM_BMAP(vsmap[j])) & (1 << k))
2880: num_pages++;
2881: }
2882: }
2883: }
2884: } else {
2885: vsmap = vs->vs_dmap;
2886: if (vsmap == NULL)
2887: return 0;
2888: /* loop on clusters in the direct map */
2889: for (j = 0; j < CLMAP_ENTRIES; j++) {
2890: if (VSM_ISCLR(vsmap[j]) ||
2891: VSM_ISERR(vsmap[j]))
2892: continue;
2893: /* loop on pages in this cluster */
2894: for (k = 0; k < VSCLSIZE(vs); k++) {
2895: if ((VSM_BMAP(vsmap[j])) & (1 << k))
2896: num_pages++;
2897: }
2898: }
2899: }
2900:
2901: return ptoa(num_pages);
2902: }
2903:
2904: size_t
2905: ps_vstruct_allocated_pages(
2906: vstruct_t vs,
2907: default_pager_page_t *pages,
2908: size_t pages_size)
2909: {
2910: int num_pages;
2911: struct vs_map *vsmap;
2912: vm_offset_t offset;
2913: int i, j, k;
2914:
2915: num_pages = 0;
2916: offset = 0;
2917: if (vs->vs_indirect) {
2918: /* loop on indirect maps */
2919: for (i = 0; i < INDIRECT_CLMAP_ENTRIES(vs->vs_size); i++) {
2920: vsmap = vs->vs_imap[i];
2921: if (vsmap == NULL) {
2922: offset += (vm_page_size * CLMAP_ENTRIES *
2923: VSCLSIZE(vs));
2924: continue;
2925: }
2926: /* loop on clusters in this indirect map */
2927: for (j = 0; j < CLMAP_ENTRIES; j++) {
2928: if (VSM_ISCLR(vsmap[j]) ||
2929: VSM_ISERR(vsmap[j])) {
2930: offset += vm_page_size * VSCLSIZE(vs);
2931: continue;
2932: }
2933: /* loop on pages in this cluster */
2934: for (k = 0; k < VSCLSIZE(vs); k++) {
2935: if ((VSM_BMAP(vsmap[j])) & (1 << k)) {
2936: num_pages++;
2937: if (num_pages < pages_size)
2938: pages++->dpp_offset =
2939: offset;
2940: }
2941: offset += vm_page_size;
2942: }
2943: }
2944: }
2945: } else {
2946: vsmap = vs->vs_dmap;
2947: if (vsmap == NULL)
2948: return 0;
2949: /* loop on clusters in the direct map */
2950: for (j = 0; j < CLMAP_ENTRIES; j++) {
2951: if (VSM_ISCLR(vsmap[j]) ||
2952: VSM_ISERR(vsmap[j])) {
2953: offset += vm_page_size * VSCLSIZE(vs);
2954: continue;
2955: }
2956: /* loop on pages in this cluster */
2957: for (k = 0; k < VSCLSIZE(vs); k++) {
2958: if ((VSM_BMAP(vsmap[j])) & (1 << k)) {
2959: num_pages++;
2960: if (num_pages < pages_size)
2961: pages++->dpp_offset = offset;
2962: }
2963: offset += vm_page_size;
2964: }
2965: }
2966: }
2967:
2968: return num_pages;
2969: }
2970:
2971:
2972: kern_return_t
2973: ps_vstruct_transfer_from_segment(
2974: vstruct_t vs,
2975: paging_segment_t segment,
2976: upl_t page_list)
2977: {
2978: struct vs_map *vsmap;
2979: struct vs_map old_vsmap;
2980: struct vs_map new_vsmap;
2981: int i, j, k;
2982:
2983: VS_LOCK(vs); /* block all work on this vstruct */
2984: /* can't allow the normal multiple write */
2985: /* semantic because writes may conflict */
2986: vs->vs_xfer_pending = TRUE;
2987: vs_wait_for_sync_writers(vs);
2988: vs_start_write(vs);
2989: vs_wait_for_readers(vs);
2990: /* we will unlock the vs to allow other writes while transferring */
2991: /* and will be guaranteed of the persistance of the vs struct */
2992: /* because the caller of ps_vstruct_transfer_from_segment bumped */
2993: /* vs_async_pending */
2994: /* OK we now have guaranteed no other parties are accessing this */
2995: /* vs. Now that we are also supporting simple lock versions of */
2996: /* vs_lock we cannot hold onto VS_LOCK as we may block below. */
2997: /* our purpose in holding it before was the multiple write case */
2998: /* we now use the boolean xfer_pending to do that. We can use */
2999: /* a boolean instead of a count because we have guaranteed single */
3000: /* file access to this code in its caller */
3001: VS_UNLOCK(vs);
3002: vs_changed:
3003: if (vs->vs_indirect) {
3004: int vsmap_size;
3005: int clmap_off;
3006: /* loop on indirect maps */
3007: for (i = 0; i < INDIRECT_CLMAP_ENTRIES(vs->vs_size); i++) {
3008: vsmap = vs->vs_imap[i];
3009: if (vsmap == NULL)
3010: continue;
3011: /* loop on clusters in this indirect map */
3012: clmap_off = (vm_page_size * CLMAP_ENTRIES *
3013: VSCLSIZE(vs) * i);
3014: if(i+1 == INDIRECT_CLMAP_ENTRIES(vs->vs_size))
3015: vsmap_size = vs->vs_size - (CLMAP_ENTRIES * i);
3016: else
3017: vsmap_size = CLMAP_ENTRIES;
3018: for (j = 0; j < vsmap_size; j++) {
3019: if (VSM_ISCLR(vsmap[j]) ||
3020: VSM_ISERR(vsmap[j]) ||
3021: (VSM_PS(vsmap[j]) != segment))
3022: continue;
3023: if(vs_cluster_transfer(vs,
3024: (vm_page_size * (j << vs->vs_clshift))
3025: + clmap_off,
3026: vm_page_size << vs->vs_clshift,
3027: page_list)
3028: != KERN_SUCCESS) {
3029: VS_LOCK(vs);
3030: vs->vs_xfer_pending = FALSE;
3031: VS_UNLOCK(vs);
3032: vs_finish_write(vs);
3033: return KERN_FAILURE;
3034: }
3035: /* allow other readers/writers during transfer*/
3036: VS_LOCK(vs);
3037: vs->vs_xfer_pending = FALSE;
3038: VS_UNLOCK(vs);
3039: vs_finish_write(vs);
3040: VS_LOCK(vs);
3041: vs->vs_xfer_pending = TRUE;
3042: VS_UNLOCK(vs);
3043: vs_wait_for_sync_writers(vs);
3044: vs_start_write(vs);
3045: vs_wait_for_readers(vs);
3046: if (!(vs->vs_indirect)) {
3047: goto vs_changed;
3048: }
3049: }
3050: }
3051: } else {
3052: vsmap = vs->vs_dmap;
3053: if (vsmap == NULL) {
3054: VS_LOCK(vs);
3055: vs->vs_xfer_pending = FALSE;
3056: VS_UNLOCK(vs);
3057: vs_finish_write(vs);
3058: return KERN_SUCCESS;
3059: }
3060: /* loop on clusters in the direct map */
3061: for (j = 0; j < vs->vs_size; j++) {
3062: if (VSM_ISCLR(vsmap[j]) ||
3063: VSM_ISERR(vsmap[j]) ||
3064: (VSM_PS(vsmap[j]) != segment))
3065: continue;
3066: if(vs_cluster_transfer(vs,
3067: vm_page_size * (j << vs->vs_clshift),
3068: vm_page_size << vs->vs_clshift,
3069: page_list) != KERN_SUCCESS) {
3070: VS_LOCK(vs);
3071: vs->vs_xfer_pending = FALSE;
3072: VS_UNLOCK(vs);
3073: vs_finish_write(vs);
3074: return KERN_FAILURE;
3075: }
3076: /* allow other readers/writers during transfer*/
3077: VS_LOCK(vs);
3078: vs->vs_xfer_pending = FALSE;
3079: VS_UNLOCK(vs);
3080: vs_finish_write(vs);
3081: VS_LOCK(vs);
3082: vs->vs_xfer_pending = TRUE;
3083: VS_UNLOCK(vs);
3084: vs_wait_for_sync_writers(vs);
3085: vs_start_write(vs);
3086: vs_wait_for_readers(vs);
3087: if (vs->vs_indirect) {
3088: goto vs_changed;
3089: }
3090: }
3091: }
3092:
3093: VS_LOCK(vs);
3094: vs->vs_xfer_pending = FALSE;
3095: VS_UNLOCK(vs);
3096: vs_finish_write(vs);
3097: return KERN_SUCCESS;
3098: }
3099:
3100:
3101:
3102: vs_map_t
3103: vs_get_map_entry(
3104: vstruct_t vs,
3105: vm_offset_t offset)
3106: {
3107: struct vs_map *vsmap;
3108: vm_offset_t cluster;
3109:
3110: cluster = atop(offset) >> vs->vs_clshift;
3111: if (vs->vs_indirect) {
3112: long ind_block = cluster/CLMAP_ENTRIES;
3113:
3114: /* Is the indirect block allocated? */
3115: vsmap = vs->vs_imap[ind_block];
3116: if(vsmap == (vs_map_t) NULL)
3117: return vsmap;
3118: } else
3119: vsmap = vs->vs_dmap;
3120: vsmap += cluster%CLMAP_ENTRIES;
3121: return vsmap;
3122: }
3123:
3124:
3125:
3126:
3127:
3128:
3129:
3130: kern_return_t
3131: vs_cluster_transfer(
3132: vstruct_t vs,
3133: vm_offset_t offset,
3134: vm_size_t cnt,
3135: upl_t page_list)
3136: {
3137: vm_offset_t actual_offset;
3138: paging_segment_t ps;
3139: struct clmap clmap;
3140: kern_return_t error = KERN_SUCCESS;
3141: int size, size_wanted, i;
3142: unsigned int residual;
3143: int unavail_size;
3144: default_pager_thread_t *dpt;
3145: boolean_t dealloc;
3146: struct vs_map *vsmap_ptr;
3147: struct vs_map read_vsmap;
3148: struct vs_map original_read_vsmap;
3149: struct vs_map write_vsmap;
3150:
3151: vm_offset_t ioaddr;
3152:
3153: static char here[] = "vs_cluster_transfer";
3154:
3155: /* vs_cluster_transfer reads in the pages of a cluster and
3156: * then writes these pages back to new backing store. The
3157: * segment the pages are being read from is assumed to have
3158: * been taken off-line and is no longer considered for new
3159: * space requests.
3160: */
3161:
3162: /*
3163: * This loop will be executed once per cluster referenced.
3164: * Typically this means once, since it's unlikely that the
3165: * VM system will ask for anything spanning cluster boundaries.
3166: *
3167: * If there are holes in a cluster (in a paging segment), we stop
3168: * reading at the hole, then loop again, hoping to
3169: * find valid pages later in the cluster. This continues until
3170: * the entire range has been examined, and read, if present. The
3171: * pages are written as they are read. If a failure occurs after
3172: * some pages are written the unmap call at the bottom of the loop
3173: * recovers the backing store and the old backing store remains
3174: * in effect.
3175: */
3176:
3177: upl_map(kernel_map, page_list, &ioaddr);
3178:
3179: VSM_CLR(write_vsmap);
3180: VSM_CLR(original_read_vsmap);
3181: while (cnt && (error == KERN_SUCCESS)) {
3182: vsmap_ptr = vs_get_map_entry(vs, offset);
3183: actual_offset = ps_clmap(vs, offset, &clmap, CL_FIND, 0, 0);
3184:
3185: if (actual_offset == (vm_offset_t) -1) {
3186:
3187: /*
3188: * Nothing left to write in this cluster at least
3189: * set write cluster information for any previous
3190: * write, clear for next cluster, if there is one
3191: */
3192: unsigned int local_size, clmask, clsize;
3193:
3194: clsize = vm_page_size << vs->vs_clshift;
3195: clmask = clsize - 1;
3196: local_size = clsize - (offset & clmask);
3197: ASSERT(local_size);
3198: local_size = MIN(local_size, cnt);
3199:
3200: /* This cluster has no data in it beyond what may */
3201: /* have been found on a previous iteration through */
3202: /* the loop "write_vsmap" */
3203: *vsmap_ptr = write_vsmap;
3204: VSM_CLR(write_vsmap);
3205: VSM_CLR(original_read_vsmap);
3206:
3207: cnt -= local_size;
3208: offset += local_size;
3209: continue;
3210: }
3211:
3212: /*
3213: * Count up contiguous available or unavailable
3214: * pages.
3215: */
3216: ps = CLMAP_PS(clmap);
3217: ASSERT(ps);
3218: size = 0;
3219: unavail_size = 0;
3220: for (i = 0;
3221: (size < cnt) && (unavail_size < cnt) &&
3222: (i < CLMAP_NPGS(clmap)); i++) {
3223: if (CLMAP_ISSET(clmap, i)) {
3224: if (unavail_size != 0)
3225: break;
3226: size += vm_page_size;
3227: BS_STAT(ps->ps_bs,
3228: ps->ps_bs->bs_pages_in++);
3229: } else {
3230: if (size != 0)
3231: break;
3232: unavail_size += vm_page_size;
3233: }
3234: }
3235:
3236: if (size == 0) {
3237: ASSERT(unavail_size);
3238: cnt -= unavail_size;
3239: offset += unavail_size;
3240: if((offset & ((vm_page_size << vs->vs_clshift) - 1))
3241: == 0) {
3242: /* There is no more to transfer in this
3243: cluster
3244: */
3245: *vsmap_ptr = write_vsmap;
3246: VSM_CLR(write_vsmap);
3247: VSM_CLR(original_read_vsmap);
3248: }
3249: continue;
3250: }
3251:
3252: if(VSM_ISCLR(original_read_vsmap))
3253: original_read_vsmap = *vsmap_ptr;
3254:
3255: if(ps->ps_segtype == PS_PARTITION) {
3256: /*
3257: error = ps_read_device(ps, actual_offset, &buffer,
3258: size, &residual);
3259: */
3260: } else {
3261: error = ps_read_file(ps, actual_offset, ioaddr,
3262: size, &residual);
3263: }
3264:
3265: read_vsmap = *vsmap_ptr;
3266:
3267:
3268: /*
3269: * Adjust counts and put data in new BS. Optimize for the
3270: * common case, i.e. no error and/or partial data.
3271: * If there was an error, then we need to error the entire
3272: * range, even if some data was successfully read.
3273: *
3274: */
3275: if ((error == KERN_SUCCESS) && (residual == 0)) {
3276: /*
3277: * Got everything we asked for, supply the data to
3278: * the new BS. Note that as a side effect of supplying
3279: * the data, the buffer holding the supplied data is
3280: * deallocated from the pager's address space unless
3281: * the write is unsuccessful.
3282: */
3283:
3284: /* note buffer will be cleaned up in all cases by */
3285: /* internal_cluster_write or if an error on write */
3286: /* the vm_map_copy_page_discard call */
3287: *vsmap_ptr = write_vsmap;
3288: if(vs_cluster_write(vs, offset,
3289: ioaddr, size, TRUE) != KERN_SUCCESS) {
3290: error = KERN_FAILURE;
3291: if(!(VSM_ISCLR(*vsmap_ptr))) {
3292: /* unmap the new backing store object */
3293: ps_clunmap(vs, offset, size);
3294: }
3295: /* original vsmap */
3296: *vsmap_ptr = original_read_vsmap;
3297: VSM_CLR(write_vsmap);
3298: } else {
3299: if((offset + size) &
3300: ((vm_page_size << vs->vs_clshift)
3301: - 1)) {
3302: /* There is more to transfer in this
3303: cluster
3304: */
3305: write_vsmap = *vsmap_ptr;
3306: *vsmap_ptr = read_vsmap;
3307: } else {
3308: /* discard the old backing object */
3309: write_vsmap = *vsmap_ptr;
3310: *vsmap_ptr = read_vsmap;
3311: ps_clunmap(vs, offset, size);
3312: *vsmap_ptr = write_vsmap;
3313: VSM_CLR(write_vsmap);
3314: VSM_CLR(original_read_vsmap);
3315: }
3316: }
3317: } else {
3318: size_wanted = size;
3319: if (error == KERN_SUCCESS) {
3320: if (residual == size) {
3321: /*
3322: * If a read operation returns no error
3323: * and no data moved, we turn it into
3324: * an error, assuming we're reading at
3325: * or beyond EOF.
3326: * Fall through and error the entire
3327: * range.
3328: */
3329: error = KERN_FAILURE;
3330: *vsmap_ptr = original_read_vsmap;
3331: VSM_CLR(write_vsmap);
3332: continue;
3333: } else {
3334: /*
3335: * Otherwise, we have partial read.
3336: * This is also considered an error
3337: * for the purposes of cluster transfer
3338: */
3339: error = KERN_FAILURE;
3340: *vsmap_ptr = original_read_vsmap;
3341: VSM_CLR(write_vsmap);
3342: continue;
3343: }
3344: }
3345:
3346: }
3347: cnt -= size;
3348: offset += size;
3349:
3350: } /* END while (cnt && (error == 0)) */
3351: if(!VSM_ISCLR(write_vsmap))
3352: *vsmap_ptr = write_vsmap;
3353:
3354: upl_un_map(kernel_map, page_list);
3355: return error;
3356: }
3357:
3358: kern_return_t
3359: default_pager_add_file(MACH_PORT_FACE backing_store,
3360: int *vp,
3361: int record_size,
3362: long size)
3363: {
3364: backing_store_t bs;
3365: paging_segment_t ps;
3366: int i;
3367: int error;
3368: static char here[] = "default_pager_add_file";
3369:
3370: if ((bs = backing_store_lookup(backing_store))
3371: == BACKING_STORE_NULL)
3372: return KERN_INVALID_ARGUMENT;
3373:
3374: PSL_LOCK();
3375: for (i = 0; i <= paging_segment_max; i++) {
3376: ps = paging_segments[i];
3377: if (ps == PAGING_SEGMENT_NULL)
3378: continue;
3379: if (ps->ps_segtype != PS_FILE)
3380: continue;
3381:
3382: /*
3383: * Check for overlap on same device.
3384: */
3385: if (ps->ps_vnode == (struct vnode *)vp) {
3386: PSL_UNLOCK();
3387: BS_UNLOCK(bs);
3388: return KERN_INVALID_ARGUMENT;
3389: }
3390: }
3391: PSL_UNLOCK();
3392:
3393: /*
3394: * Set up the paging segment
3395: */
3396: ps = (paging_segment_t) kalloc(sizeof (struct paging_segment));
3397: if (ps == PAGING_SEGMENT_NULL) {
3398: BS_UNLOCK(bs);
3399: return KERN_RESOURCE_SHORTAGE;
3400: }
3401:
3402: ps->ps_segtype = PS_FILE;
3403: ps->ps_vnode = (struct vnode *)vp;
3404: ps->ps_offset = 0;
3405: ps->ps_record_shift = local_log2(vm_page_size / record_size);
3406: ps->ps_recnum = size;
3407: ps->ps_pgnum = size >> ps->ps_record_shift;
3408:
3409: ps->ps_pgcount = ps->ps_pgnum;
3410: ps->ps_clshift = local_log2(bs->bs_clsize);
3411: ps->ps_clcount = ps->ps_ncls = ps->ps_pgcount >> ps->ps_clshift;
3412: ps->ps_hint = 0;
3413:
3414: PS_LOCK_INIT(ps);
3415: ps->ps_bmap = (unsigned char *) kalloc(RMAPSIZE(ps->ps_ncls));
3416: if (!ps->ps_bmap) {
3417: kfree((vm_offset_t)ps, sizeof *ps);
3418: BS_UNLOCK(bs);
3419: return KERN_RESOURCE_SHORTAGE;
3420: }
3421: for (i = 0; i < ps->ps_ncls; i++) {
3422: clrbit(ps->ps_bmap, i);
3423: }
3424:
3425: ps->ps_going_away = FALSE;
3426: ps->ps_bs = bs;
3427:
3428: if ((error = ps_enter(ps)) != 0) {
3429: kfree((vm_offset_t)ps->ps_bmap, RMAPSIZE(ps->ps_ncls));
3430: kfree((vm_offset_t)ps, sizeof *ps);
3431: BS_UNLOCK(bs);
3432: return KERN_RESOURCE_SHORTAGE;
3433: }
3434:
3435: bs->bs_pages_free += ps->ps_clcount << ps->ps_clshift;
3436: bs->bs_pages_total += ps->ps_clcount << ps->ps_clshift;
3437: PSL_LOCK();
3438: dp_pages_free += ps->ps_pgcount;
3439: PSL_UNLOCK();
3440:
3441: BS_UNLOCK(bs);
3442:
3443: bs_more_space(ps->ps_clcount);
3444:
3445: DEBUG(DEBUG_BS_INTERNAL,
3446: ("device=0x%x,offset=0x%x,count=0x%x,record_size=0x%x,shift=%d,total_size=0x%x\n",
3447: device, offset, size, record_size,
3448: ps->ps_record_shift, ps->ps_pgnum));
3449:
3450: return KERN_SUCCESS;
3451: }
3452:
3453:
3454:
3455: kern_return_t ps_read_file(paging_segment_t, vm_offset_t, vm_offset_t, unsigned int, unsigned int *); /* forward */
3456:
3457: kern_return_t
3458: ps_read_file(
3459: paging_segment_t ps,
3460: vm_offset_t offset,
3461: vm_offset_t ioaddr,
3462: unsigned int size,
3463: unsigned int *residualp)
3464: {
3465: kern_return_t kr = KERN_SUCCESS;
3466: vm_offset_t dev_offset;
3467: static char here[] = "ps_read_file";
3468:
3469: vm_map_copy_t device_data = NULL;
3470: int error = 0;
3471: int result;
3472:
3473:
3474: clustered_reads[atop(size)]++;
3475:
3476: dev_offset = ps->ps_offset + offset;
3477:
3478: error = pager_vnode_pagein(ps->ps_vnode,
3479: (vm_offset_t)ioaddr, dev_offset, (vm_size_t)size, NULL);
3480:
3481: /* The vnode_pagein semantic is somewhat at odds with the existing */
3482: /* device_read semantic. Partial reads are not experienced at this */
3483: /* level. It is up to the bit map code and cluster read code to */
3484: /* check that requested data locations are actually backed, and the */
3485: /* pagein code to either read all of the requested data or return an */
3486: /* error. */
3487:
3488: if(error)
3489: result = KERN_FAILURE;
3490: else {
3491: *residualp = 0;
3492: result = KERN_SUCCESS;
3493: }
3494:
3495: return result;
3496:
3497: }
3498:
3499: kern_return_t
3500: ps_write_file(
3501: paging_segment_t ps,
3502: vm_offset_t offset,
3503: vm_offset_t addr,
3504: unsigned int size)
3505: {
3506: vm_offset_t dev_offset;
3507: kern_return_t result;
3508: static char here[] = "ps_write_file";
3509:
3510: vm_offset_t ioaddr;
3511: int error = 0;
3512:
3513:
3514: clustered_writes[atop(size)]++;
3515: dev_offset = ps->ps_offset + offset;
3516:
3517: ioaddr = addr;
3518:
3519:
3520: if (ioaddr) {
3521: if(pager_vnode_pageout(ps->ps_vnode, ioaddr,
3522: (vm_offset_t) dev_offset, (vm_size_t)size, NULL)) {
3523: result = KERN_FAILURE;
3524: }
3525: else {
3526: result = KERN_SUCCESS;
3527: }
3528:
3529: }
3530: else {
3531: panic("ps_write_file: No data to copy out\n");
3532: result = KERN_SUCCESS;
3533: }
3534:
3535:
3536: return result;
3537: }
3538:
3539: kern_return_t
3540: default_pager_triggers(MACH_PORT_FACE default_pager,
3541: int hi_wat,
3542: int lo_wat,
3543: int flags,
3544: MACH_PORT_FACE trigger_port)
3545: {
3546:
3547: if(flags & HI_WAT_ALERT) {
3548: if(min_pages_trigger_port)
3549: ipc_port_release_send(min_pages_trigger_port);
3550: min_pages_trigger_port = trigger_port;
3551: minimum_pages_remaining = hi_wat/vm_page_size;
3552: bs_low = FALSE;
3553: }
3554: if(flags & LO_WAT_ALERT) {
3555: if(max_pages_trigger_port)
3556: ipc_port_release_send(max_pages_trigger_port);
3557: max_pages_trigger_port = trigger_port;
3558: maximum_pages_free = lo_wat/vm_page_size;
3559: }
3560: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.