]> git.saurik.com Git - apple/xnu.git/blame - bsd/vm/vm_unix.c
xnu-792.6.61.tar.gz
[apple/xnu.git] / bsd / vm / vm_unix.c
CommitLineData
1c79356b 1/*
e5568f75 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
37839358
A
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.
1c79356b 11 *
37839358
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
37839358
A
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.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Mach Operating System
24 * Copyright (c) 1987 Carnegie-Mellon University
25 * All rights reserved. The CMU software License Agreement specifies
26 * the terms and conditions for use and redistribution.
27 */
28
29/*
30 */
9bccf70c
A
31
32
1c79356b
A
33#include <meta_features.h>
34
35#include <kern/task.h>
36#include <kern/thread.h>
37#include <kern/debug.h>
38#include <kern/lock.h>
91447636 39#include <mach/mach_traps.h>
1c79356b 40#include <mach/time_value.h>
91447636 41#include <mach/vm_map.h>
1c79356b
A
42#include <mach/vm_param.h>
43#include <mach/vm_prot.h>
44#include <mach/port.h>
45
91447636 46#include <sys/file_internal.h>
1c79356b
A
47#include <sys/param.h>
48#include <sys/systm.h>
49#include <sys/dir.h>
50#include <sys/namei.h>
91447636
A
51#include <sys/proc_internal.h>
52#include <sys/kauth.h>
1c79356b
A
53#include <sys/vm.h>
54#include <sys/file.h>
91447636 55#include <sys/vnode_internal.h>
1c79356b
A
56#include <sys/mount.h>
57#include <sys/trace.h>
58#include <sys/kernel.h>
91447636
A
59#include <sys/ubc_internal.h>
60#include <sys/user.h>
9bccf70c 61#include <sys/stat.h>
91447636
A
62#include <sys/sysproto.h>
63#include <sys/mman.h>
1c79356b 64
e5568f75
A
65#include <bsm/audit_kernel.h>
66#include <bsm/audit_kevents.h>
67
1c79356b 68#include <kern/kalloc.h>
1c79356b
A
69#include <vm/vm_map.h>
70#include <vm/vm_kern.h>
71
72#include <machine/spl.h>
9bccf70c 73
1c79356b 74#include <mach/shared_memory_server.h>
9bccf70c
A
75#include <vm/vm_shared_memory_server.h>
76
91447636 77#include <vm/vm_protos.h>
9bccf70c 78
1c79356b 79
91447636
A
80int
81useracc(
82 user_addr_t addr,
83 user_size_t len,
84 int prot)
1c79356b
A
85{
86 return (vm_map_check_protection(
87 current_map(),
91447636 88 vm_map_trunc_page(addr), vm_map_round_page(addr+len),
1c79356b
A
89 prot == B_READ ? VM_PROT_READ : VM_PROT_WRITE));
90}
91
91447636
A
92int
93vslock(
94 user_addr_t addr,
95 user_size_t len)
1c79356b 96{
91447636
A
97 kern_return_t kret;
98 kret = vm_map_wire(current_map(), vm_map_trunc_page(addr),
99 vm_map_round_page(addr+len),
1c79356b 100 VM_PROT_READ | VM_PROT_WRITE ,FALSE);
0b4e3aa0
A
101
102 switch (kret) {
103 case KERN_SUCCESS:
104 return (0);
105 case KERN_INVALID_ADDRESS:
106 case KERN_NO_SPACE:
107 return (ENOMEM);
108 case KERN_PROTECTION_FAILURE:
109 return (EACCES);
110 default:
111 return (EINVAL);
112 }
1c79356b
A
113}
114
91447636
A
115int
116vsunlock(
117 user_addr_t addr,
118 user_size_t len,
119 __unused int dirtied)
1c79356b 120{
1c79356b 121#if FIXME /* [ */
91447636 122 pmap_t pmap;
1c79356b 123 vm_page_t pg;
91447636
A
124 vm_map_offset_t vaddr;
125 ppnum_t paddr;
1c79356b 126#endif /* FIXME ] */
0b4e3aa0 127 kern_return_t kret;
1c79356b
A
128
129#if FIXME /* [ */
130 if (dirtied) {
131 pmap = get_task_pmap(current_task());
91447636
A
132 for (vaddr = vm_map_trunc_page(addr);
133 vaddr < vm_map_round_page(addr+len);
1c79356b
A
134 vaddr += PAGE_SIZE) {
135 paddr = pmap_extract(pmap, vaddr);
136 pg = PHYS_TO_VM_PAGE(paddr);
137 vm_page_set_modified(pg);
138 }
139 }
140#endif /* FIXME ] */
141#ifdef lint
142 dirtied++;
143#endif /* lint */
91447636
A
144 kret = vm_map_unwire(current_map(), vm_map_trunc_page(addr),
145 vm_map_round_page(addr+len), FALSE);
0b4e3aa0
A
146 switch (kret) {
147 case KERN_SUCCESS:
148 return (0);
149 case KERN_INVALID_ADDRESS:
150 case KERN_NO_SPACE:
151 return (ENOMEM);
152 case KERN_PROTECTION_FAILURE:
153 return (EACCES);
154 default:
155 return (EINVAL);
156 }
1c79356b
A
157}
158
91447636
A
159int
160subyte(
161 user_addr_t addr,
162 int byte)
1c79356b
A
163{
164 char character;
165
166 character = (char)byte;
167 return (copyout((void *)&(character), addr, sizeof(char)) == 0 ? 0 : -1);
168}
169
91447636
A
170int
171suibyte(
172 user_addr_t addr,
173 int byte)
1c79356b
A
174{
175 char character;
176
177 character = (char)byte;
91447636 178 return (copyout((void *)&(character), addr, sizeof(char)) == 0 ? 0 : -1);
1c79356b
A
179}
180
91447636 181int fubyte(user_addr_t addr)
1c79356b
A
182{
183 unsigned char byte;
184
185 if (copyin(addr, (void *) &byte, sizeof(char)))
186 return(-1);
187 return(byte);
188}
189
91447636 190int fuibyte(user_addr_t addr)
1c79356b
A
191{
192 unsigned char byte;
193
194 if (copyin(addr, (void *) &(byte), sizeof(char)))
195 return(-1);
196 return(byte);
197}
198
91447636
A
199int
200suword(
201 user_addr_t addr,
202 long word)
1c79356b
A
203{
204 return (copyout((void *) &word, addr, sizeof(int)) == 0 ? 0 : -1);
205}
206
91447636 207long fuword(user_addr_t addr)
1c79356b
A
208{
209 long word;
210
211 if (copyin(addr, (void *) &word, sizeof(int)))
212 return(-1);
213 return(word);
214}
215
216/* suiword and fuiword are the same as suword and fuword, respectively */
217
91447636
A
218int
219suiword(
220 user_addr_t addr,
221 long word)
1c79356b
A
222{
223 return (copyout((void *) &word, addr, sizeof(int)) == 0 ? 0 : -1);
224}
225
91447636 226long fuiword(user_addr_t addr)
1c79356b
A
227{
228 long word;
229
230 if (copyin(addr, (void *) &word, sizeof(int)))
231 return(-1);
232 return(word);
233}
91447636
A
234
235/*
236 * With a 32-bit kernel and mixed 32/64-bit user tasks, this interface allows the
237 * fetching and setting of process-sized size_t and pointer values.
238 */
239int
240sulong(user_addr_t addr, int64_t word)
241{
242
243 if (IS_64BIT_PROCESS(current_proc())) {
244 return(copyout((void *)&word, addr, sizeof(word)) == 0 ? 0 : -1);
245 } else {
246 return(suiword(addr, (long)word));
247 }
248}
249
250int64_t
251fulong(user_addr_t addr)
252{
253 int64_t longword;
254
255 if (IS_64BIT_PROCESS(current_proc())) {
256 if (copyin(addr, (void *)&longword, sizeof(longword)) != 0)
257 return(-1);
258 return(longword);
259 } else {
260 return((int64_t)fuiword(addr));
261 }
262}
1c79356b
A
263
264int
91447636
A
265suulong(user_addr_t addr, uint64_t uword)
266{
267
268 if (IS_64BIT_PROCESS(current_proc())) {
269 return(copyout((void *)&uword, addr, sizeof(uword)) == 0 ? 0 : -1);
270 } else {
271 return(suiword(addr, (u_long)uword));
272 }
273}
274
275uint64_t
276fuulong(user_addr_t addr)
1c79356b 277{
91447636
A
278 uint64_t ulongword;
279
280 if (IS_64BIT_PROCESS(current_proc())) {
281 if (copyin(addr, (void *)&ulongword, sizeof(ulongword)) != 0)
282 return(-1ULL);
283 return(ulongword);
284 } else {
285 return((uint64_t)fuiword(addr));
286 }
287}
288
289int
290swapon(__unused struct proc *procp, __unused struct swapon_args *uap, __unused int *retval)
291{
292 return(ENOTSUP);
1c79356b
A
293}
294
1c79356b
A
295
296kern_return_t
91447636
A
297pid_for_task(
298 struct pid_for_task_args *args)
1c79356b 299{
91447636
A
300 mach_port_name_t t = args->t;
301 user_addr_t pid_addr = args->pid;
1c79356b
A
302 struct proc * p;
303 task_t t1;
1c79356b 304 int pid = -1;
0b4e3aa0 305 kern_return_t err = KERN_SUCCESS;
1c79356b
A
306 boolean_t funnel_state;
307
e5568f75
A
308 AUDIT_MACH_SYSCALL_ENTER(AUE_PIDFORTASK);
309 AUDIT_ARG(mach_port1, t);
310
1c79356b
A
311 funnel_state = thread_funnel_set(kernel_flock, TRUE);
312 t1 = port_name_to_task(t);
313
314 if (t1 == TASK_NULL) {
315 err = KERN_FAILURE;
0b4e3aa0 316 goto pftout;
1c79356b
A
317 } else {
318 p = get_bsdtask_info(t1);
319 if (p) {
91447636 320 pid = proc_pid(p);
1c79356b
A
321 err = KERN_SUCCESS;
322 } else {
323 err = KERN_FAILURE;
324 }
325 }
326 task_deallocate(t1);
1c79356b 327pftout:
e5568f75 328 AUDIT_ARG(pid, pid);
91447636 329 (void) copyout((char *) &pid, pid_addr, sizeof(int));
1c79356b 330 thread_funnel_set(kernel_flock, funnel_state);
e5568f75 331 AUDIT_MACH_SYSCALL_EXIT(err);
1c79356b
A
332 return(err);
333}
334
335/*
336 * Routine: task_for_pid
337 * Purpose:
338 * Get the task port for another "process", named by its
339 * process ID on the same host as "target_task".
340 *
341 * Only permitted to privileged processes, or processes
342 * with the same user ID.
91447636
A
343 *
344 * XXX This should be a BSD system call, not a Mach trap!!!
1c79356b
A
345 */
346kern_return_t
91447636
A
347task_for_pid(
348 struct task_for_pid_args *args)
1c79356b 349{
91447636
A
350 mach_port_name_t target_tport = args->target_tport;
351 int pid = args->pid;
352 user_addr_t task_addr = args->t;
353 struct uthread *uthread;
1c79356b
A
354 struct proc *p;
355 struct proc *p1;
356 task_t t1;
91447636 357 mach_port_name_t tret;
1c79356b
A
358 void * sright;
359 int error = 0;
360 boolean_t funnel_state;
361
e5568f75
A
362 AUDIT_MACH_SYSCALL_ENTER(AUE_TASKFORPID);
363 AUDIT_ARG(pid, pid);
364 AUDIT_ARG(mach_port1, target_tport);
365
1c79356b
A
366 t1 = port_name_to_task(target_tport);
367 if (t1 == TASK_NULL) {
91447636 368 (void ) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t));
e5568f75 369 AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
0b4e3aa0 370 return(KERN_FAILURE);
1c79356b
A
371 }
372
373 funnel_state = thread_funnel_set(kernel_flock, TRUE);
374
91447636
A
375 p1 = get_bsdtask_info(t1); /* XXX current proc */
376
377 /*
378 * Delayed binding of thread credential to process credential, if we
379 * are not running with an explicitly set thread credential.
380 */
381 uthread = get_bsdthread_info(current_thread());
382 if (uthread->uu_ucred != p1->p_ucred &&
383 (uthread->uu_flag & UT_SETUID) == 0) {
384 kauth_cred_t old = uthread->uu_ucred;
385 proc_lock(p1);
386 uthread->uu_ucred = p1->p_ucred;
387 kauth_cred_ref(uthread->uu_ucred);
388 proc_unlock(p1);
389 if (old != NOCRED)
390 kauth_cred_rele(old);
391 }
392
e5568f75
A
393 p = pfind(pid);
394 AUDIT_ARG(process, p);
91447636 395
1c79356b 396 if (
e5568f75 397 (p != (struct proc *) 0)
1c79356b 398 && (p1 != (struct proc *) 0)
91447636
A
399 && (((kauth_cred_getuid(p->p_ucred) == kauth_cred_getuid(kauth_cred_get())) &&
400 ((p->p_ucred->cr_ruid == kauth_cred_get()->cr_ruid)))
401 || !(suser(kauth_cred_get(), 0)))
1c79356b
A
402 && (p->p_stat != SZOMB)
403 ) {
404 if (p->task != TASK_NULL) {
91447636 405 task_reference(p->task);
9bccf70c 406 sright = (void *)convert_task_to_port(p->task);
91447636
A
407 tret = ipc_port_copyout_send(
408 sright,
409 get_task_ipcspace(current_task()));
1c79356b
A
410 } else
411 tret = MACH_PORT_NULL;
e5568f75 412 AUDIT_ARG(mach_port2, tret);
91447636 413 (void ) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
1c79356b
A
414 task_deallocate(t1);
415 error = KERN_SUCCESS;
416 goto tfpout;
417 }
418 task_deallocate(t1);
419 tret = MACH_PORT_NULL;
91447636 420 (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
1c79356b
A
421 error = KERN_FAILURE;
422tfpout:
423 thread_funnel_set(kernel_flock, funnel_state);
e5568f75 424 AUDIT_MACH_SYSCALL_EXIT(error);
1c79356b
A
425 return(error);
426}
427
428
91447636
A
429/*
430 * shared_region_make_private_np:
431 *
432 * This system call is for "dyld" only.
433 *
434 * It creates a private copy of the current process's "shared region" for
435 * split libraries. "dyld" uses this when the shared region is full or
436 * it needs to load a split library that conflicts with an already loaded one
437 * that this process doesn't need. "dyld" specifies a set of address ranges
438 * that it wants to keep in the now-private "shared region". These cover
439 * the set of split libraries that the process needs so far. The kernel needs
440 * to deallocate the rest of the shared region, so that it's available for
441 * more libraries for this process.
442 */
443int
444shared_region_make_private_np(
445 struct proc *p,
446 struct shared_region_make_private_np_args *uap,
447 __unused int *retvalp)
448{
449 int error;
450 kern_return_t kr;
451 boolean_t using_shared_regions;
452 user_addr_t user_ranges;
453 unsigned int range_count;
454 struct shared_region_range_np *ranges;
455 shared_region_mapping_t shared_region;
456 struct shared_region_task_mappings task_mapping_info;
457 shared_region_mapping_t next;
458
459 ranges = NULL;
460
461 range_count = uap->rangeCount;
462 user_ranges = uap->ranges;
463
464 /* allocate kernel space for the "ranges" */
465 if (range_count != 0) {
466 kr = kmem_alloc(kernel_map,
467 (vm_offset_t *) &ranges,
468 (vm_size_t) (range_count * sizeof (ranges[0])));
469 if (kr != KERN_SUCCESS) {
470 error = ENOMEM;
471 goto done;
472 }
473
474 /* copy "ranges" from user-space */
475 error = copyin(user_ranges,
476 ranges,
477 (range_count * sizeof (ranges[0])));
478 if (error) {
479 goto done;
480 }
481 }
482
483 if (p->p_flag & P_NOSHLIB) {
484 /* no split library has been mapped for this process so far */
485 using_shared_regions = FALSE;
486 } else {
487 /* this process has already mapped some split libraries */
488 using_shared_regions = TRUE;
489 }
490
491 /*
492 * Get a private copy of the current shared region.
493 * Do not chain it to the system-wide shared region, as we'll want
494 * to map other split libraries in place of the old ones. We want
495 * to completely detach from the system-wide shared region and go our
496 * own way after this point, not sharing anything with other processes.
497 */
498 error = clone_system_shared_regions(using_shared_regions,
499 FALSE, /* chain_regions */
500 ENV_DEFAULT_ROOT);
501 if (error) {
502 goto done;
503 }
504
505 /* get info on the newly allocated shared region */
506 vm_get_shared_region(current_task(), &shared_region);
507 task_mapping_info.self = (vm_offset_t) shared_region;
508 shared_region_mapping_info(shared_region,
509 &(task_mapping_info.text_region),
510 &(task_mapping_info.text_size),
511 &(task_mapping_info.data_region),
512 &(task_mapping_info.data_size),
513 &(task_mapping_info.region_mappings),
514 &(task_mapping_info.client_base),
515 &(task_mapping_info.alternate_base),
516 &(task_mapping_info.alternate_next),
517 &(task_mapping_info.fs_base),
518 &(task_mapping_info.system),
519 &(task_mapping_info.flags),
520 &next);
521
522 /*
523 * We now have our private copy of the shared region, as it was before
524 * the call to clone_system_shared_regions(). We now need to clean it
525 * up and keep only the memory areas described by the "ranges" array.
526 */
527 kr = shared_region_cleanup(range_count, ranges, &task_mapping_info);
528 switch (kr) {
529 case KERN_SUCCESS:
530 error = 0;
531 break;
532 default:
533 error = EINVAL;
534 goto done;
535 }
536
537done:
538 if (ranges != NULL) {
539 kmem_free(kernel_map,
540 (vm_offset_t) ranges,
541 range_count * sizeof (ranges[0]));
542 ranges = NULL;
543 }
544
545 return error;
546}
547
548
549/*
550 * shared_region_map_file_np:
551 *
552 * This system call is for "dyld" only.
553 *
554 * "dyld" wants to map parts of a split library in the shared region.
555 * We get a file descriptor on the split library to be mapped and a set
556 * of mapping instructions, describing which parts of the file to map in\
557 * which areas of the shared segment and with what protection.
558 * The "shared region" is split in 2 areas:
559 * 0x90000000 - 0xa0000000 : read-only area (for TEXT and LINKEDIT sections),
560 * 0xa0000000 - 0xb0000000 : writable area (for DATA sections).
561 *
562 */
563int
564shared_region_map_file_np(
565 struct proc *p,
566 struct shared_region_map_file_np_args *uap,
567 __unused int *retvalp)
568{
569 int error;
570 kern_return_t kr;
571 int fd;
572 unsigned int mapping_count;
573 user_addr_t user_mappings; /* 64-bit */
574 user_addr_t user_slide_p; /* 64-bit */
575 struct shared_file_mapping_np *mappings;
576 struct fileproc *fp;
577 mach_vm_offset_t slide;
578 struct vnode *vp;
579 struct vfs_context context;
580 memory_object_control_t file_control;
581 memory_object_size_t file_size;
582 shared_region_mapping_t shared_region;
583 struct shared_region_task_mappings task_mapping_info;
584 shared_region_mapping_t next;
585 shared_region_mapping_t default_shared_region;
586 boolean_t using_default_region;
587 unsigned int j;
588 vm_prot_t max_prot;
589 mach_vm_offset_t base_offset, end_offset;
590 mach_vm_offset_t original_base_offset;
591 boolean_t mappings_in_segment;
592#define SFM_MAX_STACK 6
593 struct shared_file_mapping_np stack_mappings[SFM_MAX_STACK];
594
595 mappings = NULL;
596 mapping_count = 0;
597 fp = NULL;
598 vp = NULL;
599
600 /* get file descriptor for split library from arguments */
601 fd = uap->fd;
602
603 /* get file structure from file descriptor */
604 error = fp_lookup(p, fd, &fp, 0);
605 if (error) {
606 goto done;
607 }
608
609 /* make sure we're attempting to map a vnode */
610 if (fp->f_fglob->fg_type != DTYPE_VNODE) {
611 error = EINVAL;
612 goto done;
613 }
614
615 /* we need at least read permission on the file */
616 if (! (fp->f_fglob->fg_flag & FREAD)) {
617 error = EPERM;
618 goto done;
619 }
620
621 /* get vnode from file structure */
622 error = vnode_getwithref((vnode_t)fp->f_fglob->fg_data);
623 if (error) {
624 goto done;
625 }
626 vp = (struct vnode *) fp->f_fglob->fg_data;
627
628 /* make sure the vnode is a regular file */
629 if (vp->v_type != VREG) {
630 error = EINVAL;
631 goto done;
632 }
633
634 /* get vnode size */
635 {
636 off_t fs;
637
638 context.vc_proc = p;
639 context.vc_ucred = kauth_cred_get();
640 if ((error = vnode_size(vp, &fs, &context)) != 0)
641 goto done;
642 file_size = fs;
643 }
644
645 /*
646 * Get the list of mappings the caller wants us to establish.
647 */
648 mapping_count = uap->mappingCount; /* the number of mappings */
649 if (mapping_count == 0) {
650 error = 0; /* no mappings: we're done ! */
651 goto done;
652 } else if (mapping_count <= SFM_MAX_STACK) {
653 mappings = &stack_mappings[0];
654 } else {
655 kr = kmem_alloc(kernel_map,
656 (vm_offset_t *) &mappings,
657 (vm_size_t) (mapping_count *
658 sizeof (mappings[0])));
659 if (kr != KERN_SUCCESS) {
660 error = ENOMEM;
661 goto done;
662 }
663 }
664
665 user_mappings = uap->mappings; /* the mappings, in user space */
666 error = copyin(user_mappings,
667 mappings,
668 (mapping_count * sizeof (mappings[0])));
669 if (error != 0) {
670 goto done;
671 }
672
673 /*
674 * If the caller provides a "slide" pointer, it means they're OK
675 * with us moving the mappings around to make them fit.
676 */
677 user_slide_p = uap->slide_p;
678
679 /*
680 * Make each mapping address relative to the beginning of the
681 * shared region. Check that all mappings are in the shared region.
682 * Compute the maximum set of protections required to tell the
683 * buffer cache how we mapped the file (see call to ubc_map() below).
684 */
685 max_prot = VM_PROT_NONE;
686 base_offset = -1LL;
687 end_offset = 0;
688 mappings_in_segment = TRUE;
689 for (j = 0; j < mapping_count; j++) {
690 mach_vm_offset_t segment;
691 segment = (mappings[j].sfm_address &
692 GLOBAL_SHARED_SEGMENT_MASK);
693 if (segment != GLOBAL_SHARED_TEXT_SEGMENT &&
694 segment != GLOBAL_SHARED_DATA_SEGMENT) {
695 /* this mapping is not in the shared region... */
696 if (user_slide_p == NULL) {
697 /* ... and we can't slide it in: fail */
698 error = EINVAL;
699 goto done;
700 }
701 if (j == 0) {
702 /* expect all mappings to be outside */
703 mappings_in_segment = FALSE;
704 } else if (mappings_in_segment != FALSE) {
705 /* other mappings were not outside: fail */
706 error = EINVAL;
707 goto done;
708 }
709 /* we'll try and slide that mapping in the segments */
710 } else {
711 if (j == 0) {
712 /* expect all mappings to be inside */
713 mappings_in_segment = TRUE;
714 } else if (mappings_in_segment != TRUE) {
715 /* other mappings were not inside: fail */
716 error = EINVAL;
717 goto done;
718 }
719 /* get a relative offset inside the shared segments */
720 mappings[j].sfm_address -= GLOBAL_SHARED_TEXT_SEGMENT;
721 }
722 if ((mappings[j].sfm_address & SHARED_TEXT_REGION_MASK)
723 < base_offset) {
724 base_offset = (mappings[j].sfm_address &
725 SHARED_TEXT_REGION_MASK);
726 }
727 if ((mappings[j].sfm_address & SHARED_TEXT_REGION_MASK) +
728 mappings[j].sfm_size > end_offset) {
729 end_offset =
730 (mappings[j].sfm_address &
731 SHARED_TEXT_REGION_MASK) +
732 mappings[j].sfm_size;
733 }
734 max_prot |= mappings[j].sfm_max_prot;
735 }
736 /* Make all mappings relative to the base_offset */
737 base_offset = vm_map_trunc_page(base_offset);
738 end_offset = vm_map_round_page(end_offset);
739 for (j = 0; j < mapping_count; j++) {
740 mappings[j].sfm_address -= base_offset;
741 }
742 original_base_offset = base_offset;
743 if (mappings_in_segment == FALSE) {
744 /*
745 * We're trying to map a library that was not pre-bound to
746 * be in the shared segments. We want to try and slide it
747 * back into the shared segments but as far back as possible,
748 * so that it doesn't clash with pre-bound libraries. Set
749 * the base_offset to the end of the region, so that it can't
750 * possibly fit there and will have to be slid.
751 */
752 base_offset = SHARED_TEXT_REGION_SIZE - end_offset;
753 }
754
755 /* get the file's memory object handle */
756 UBCINFOCHECK("shared_region_map_file_np", vp);
757 file_control = ubc_getobject(vp, UBC_HOLDOBJECT);
758 if (file_control == MEMORY_OBJECT_CONTROL_NULL) {
759 error = EINVAL;
760 goto done;
761 }
762
763 /*
764 * Get info about the current process's shared region.
765 * This might change if we decide we need to clone the shared region.
766 */
767 vm_get_shared_region(current_task(), &shared_region);
768 task_mapping_info.self = (vm_offset_t) shared_region;
769 shared_region_mapping_info(shared_region,
770 &(task_mapping_info.text_region),
771 &(task_mapping_info.text_size),
772 &(task_mapping_info.data_region),
773 &(task_mapping_info.data_size),
774 &(task_mapping_info.region_mappings),
775 &(task_mapping_info.client_base),
776 &(task_mapping_info.alternate_base),
777 &(task_mapping_info.alternate_next),
778 &(task_mapping_info.fs_base),
779 &(task_mapping_info.system),
780 &(task_mapping_info.flags),
781 &next);
782
783 /*
784 * Are we using the system's current shared region
785 * for this environment ?
786 */
787 default_shared_region =
788 lookup_default_shared_region(ENV_DEFAULT_ROOT,
789 task_mapping_info.system);
790 if (shared_region == default_shared_region) {
791 using_default_region = TRUE;
792 } else {
793 using_default_region = FALSE;
794 }
795 shared_region_mapping_dealloc(default_shared_region);
796
797 if (vp->v_mount != rootvnode->v_mount &&
798 using_default_region) {
799 /*
800 * The split library is not on the root filesystem. We don't
801 * want to polute the system-wide ("default") shared region
802 * with it.
803 * Reject the mapping. The caller (dyld) should "privatize"
804 * (via shared_region_make_private()) the shared region and
805 * try to establish the mapping privately for this process.
806 */
807 error = EXDEV;
808 goto done;
809 }
810
811
812 /*
813 * Map the split library.
814 */
815 kr = map_shared_file(mapping_count,
816 mappings,
817 file_control,
818 file_size,
819 &task_mapping_info,
820 base_offset,
821 (user_slide_p) ? &slide : NULL);
822
823 switch (kr) {
824 case KERN_SUCCESS:
825 /*
826 * The mapping was successful. Let the buffer cache know
827 * that we've mapped that file with these protections. This
828 * prevents the vnode from getting recycled while it's mapped.
829 */
830 (void) ubc_map(vp, max_prot);
831 error = 0;
832 break;
833 case KERN_INVALID_ADDRESS:
834 error = EFAULT;
835 goto done;
836 case KERN_PROTECTION_FAILURE:
837 error = EPERM;
838 goto done;
839 case KERN_NO_SPACE:
840 error = ENOMEM;
841 goto done;
842 case KERN_FAILURE:
843 case KERN_INVALID_ARGUMENT:
844 default:
845 error = EINVAL;
846 goto done;
847 }
848
849 if (p->p_flag & P_NOSHLIB) {
850 /* signal that this process is now using split libraries */
851 p->p_flag &= ~P_NOSHLIB;
852 }
853
854 if (user_slide_p) {
855 /*
856 * The caller provided a pointer to a "slide" offset. Let
857 * them know by how much we slid the mappings.
858 */
859 if (mappings_in_segment == FALSE) {
860 /*
861 * We faked the base_offset earlier, so undo that
862 * and take into account the real base_offset.
863 */
864 slide += SHARED_TEXT_REGION_SIZE - end_offset;
865 slide -= original_base_offset;
866 /*
867 * The mappings were slid into the shared segments
868 * and "slide" is relative to the beginning of the
869 * shared segments. Adjust it to be absolute.
870 */
871 slide += GLOBAL_SHARED_TEXT_SEGMENT;
872 }
873 error = copyout(&slide,
874 user_slide_p,
875 sizeof (int64_t));
876 }
877
878done:
879 if (vp != NULL) {
880 /*
881 * release the vnode...
882 * ubc_map() still holds it for us in the non-error case
883 */
884 (void) vnode_put(vp);
885 vp = NULL;
886 }
887 if (fp != NULL) {
888 /* release the file descriptor */
889 fp_drop(p, fd, fp, 0);
890 fp = NULL;
891 }
892 if (mappings != NULL &&
893 mappings != &stack_mappings[0]) {
894 kmem_free(kernel_map,
895 (vm_offset_t) mappings,
896 mapping_count * sizeof (mappings[0]));
897 }
898 mappings = NULL;
1c79356b 899
91447636
A
900 return error;
901}
1c79356b
A
902
903int
91447636
A
904load_shared_file(struct proc *p, struct load_shared_file_args *uap,
905 __unused int *retval)
1c79356b
A
906{
907 caddr_t mapped_file_addr=uap->mfa;
908 u_long mapped_file_size=uap->mfs;
909 caddr_t *base_address=uap->ba;
910 int map_cnt=uap->map_cnt;
911 sf_mapping_t *mappings=uap->mappings;
912 char *filename=uap->filename;
913 int *flags=uap->flags;
914 struct vnode *vp = 0;
915 struct nameidata nd, *ndp;
916 char *filename_str;
917 register int error;
918 kern_return_t kr;
919
91447636
A
920 struct vfs_context context;
921 off_t file_size;
0b4e3aa0 922 memory_object_control_t file_control;
1c79356b
A
923 sf_mapping_t *map_list;
924 caddr_t local_base;
925 int local_flags;
926 int caller_flags;
927 int i;
9bccf70c 928 int default_regions = 0;
1c79356b
A
929 vm_size_t dummy;
930 kern_return_t kret;
931
932 shared_region_mapping_t shared_region;
933 struct shared_region_task_mappings task_mapping_info;
934 shared_region_mapping_t next;
935
91447636
A
936 context.vc_proc = p;
937 context.vc_ucred = kauth_cred_get();
938
1c79356b
A
939 ndp = &nd;
940
91447636 941 AUDIT_ARG(addr, CAST_USER_ADDR_T(base_address));
1c79356b 942 /* Retrieve the base address */
91447636
A
943 if ( (error = copyin(CAST_USER_ADDR_T(base_address), &local_base, sizeof (caddr_t))) ) {
944 goto lsf_bailout;
945 }
946 if ( (error = copyin(CAST_USER_ADDR_T(flags), &local_flags, sizeof (int))) ) {
947 goto lsf_bailout;
948 }
9bccf70c
A
949
950 if(local_flags & QUERY_IS_SYSTEM_REGION) {
55e303ae 951 shared_region_mapping_t default_shared_region;
9bccf70c 952 vm_get_shared_region(current_task(), &shared_region);
55e303ae
A
953 task_mapping_info.self = (vm_offset_t)shared_region;
954
955 shared_region_mapping_info(shared_region,
956 &(task_mapping_info.text_region),
957 &(task_mapping_info.text_size),
958 &(task_mapping_info.data_region),
959 &(task_mapping_info.data_size),
960 &(task_mapping_info.region_mappings),
961 &(task_mapping_info.client_base),
962 &(task_mapping_info.alternate_base),
963 &(task_mapping_info.alternate_next),
964 &(task_mapping_info.fs_base),
965 &(task_mapping_info.system),
966 &(task_mapping_info.flags), &next);
967
968 default_shared_region =
969 lookup_default_shared_region(
970 ENV_DEFAULT_ROOT,
971 task_mapping_info.system);
972 if (shared_region == default_shared_region) {
9bccf70c
A
973 local_flags = SYSTEM_REGION_BACKED;
974 } else {
975 local_flags = 0;
976 }
55e303ae 977 shared_region_mapping_dealloc(default_shared_region);
9bccf70c 978 error = 0;
91447636 979 error = copyout(&local_flags, CAST_USER_ADDR_T(flags), sizeof (int));
9bccf70c
A
980 goto lsf_bailout;
981 }
1c79356b
A
982 caller_flags = local_flags;
983 kret = kmem_alloc(kernel_map, (vm_offset_t *)&filename_str,
984 (vm_size_t)(MAXPATHLEN));
985 if (kret != KERN_SUCCESS) {
986 error = ENOMEM;
987 goto lsf_bailout;
988 }
989 kret = kmem_alloc(kernel_map, (vm_offset_t *)&map_list,
990 (vm_size_t)(map_cnt*sizeof(sf_mapping_t)));
991 if (kret != KERN_SUCCESS) {
992 kmem_free(kernel_map, (vm_offset_t)filename_str,
993 (vm_size_t)(MAXPATHLEN));
994 error = ENOMEM;
995 goto lsf_bailout;
996 }
997
91447636 998 if ( (error = copyin(CAST_USER_ADDR_T(mappings), map_list, (map_cnt*sizeof(sf_mapping_t)))) ) {
1c79356b
A
999 goto lsf_bailout_free;
1000 }
1001
91447636
A
1002 if ( (error = copyinstr(CAST_USER_ADDR_T(filename), filename_str,
1003 MAXPATHLEN, (size_t *)&dummy)) ) {
1c79356b
A
1004 goto lsf_bailout_free;
1005 }
1006
1007 /*
1008 * Get a vnode for the target file
1009 */
91447636
A
1010 NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, UIO_SYSSPACE32,
1011 CAST_USER_ADDR_T(filename_str), &context);
1c79356b
A
1012
1013 if ((error = namei(ndp))) {
1014 goto lsf_bailout_free;
1015 }
1c79356b
A
1016 vp = ndp->ni_vp;
1017
91447636
A
1018 nameidone(ndp);
1019
1c79356b
A
1020 if (vp->v_type != VREG) {
1021 error = EINVAL;
1022 goto lsf_bailout_free_vput;
1023 }
1024
1025 UBCINFOCHECK("load_shared_file", vp);
1026
91447636 1027 if ((error = vnode_size(vp, &file_size, &context)) != 0)
1c79356b 1028 goto lsf_bailout_free_vput;
1c79356b 1029
0b4e3aa0
A
1030 file_control = ubc_getobject(vp, UBC_HOLDOBJECT);
1031 if (file_control == MEMORY_OBJECT_CONTROL_NULL) {
1c79356b
A
1032 error = EINVAL;
1033 goto lsf_bailout_free_vput;
1034 }
1035
1036#ifdef notdef
91447636 1037 if(file_size != mapped_file_size) {
1c79356b
A
1038 error = EINVAL;
1039 goto lsf_bailout_free_vput;
1040 }
1041#endif
9bccf70c
A
1042 if(p->p_flag & P_NOSHLIB) {
1043 p->p_flag = p->p_flag & ~P_NOSHLIB;
1044 }
1045
1046 /* load alternate regions if the caller has requested. */
1047 /* Note: the new regions are "clean slates" */
1048 if (local_flags & NEW_LOCAL_SHARED_REGIONS) {
91447636
A
1049 error = clone_system_shared_regions(FALSE,
1050 TRUE, /* chain_regions */
1051 ENV_DEFAULT_ROOT);
9bccf70c
A
1052 if (error) {
1053 goto lsf_bailout_free_vput;
1054 }
9bccf70c 1055 }
1c79356b 1056
55e303ae 1057 vm_get_shared_region(current_task(), &shared_region);
1c79356b
A
1058 task_mapping_info.self = (vm_offset_t)shared_region;
1059
1060 shared_region_mapping_info(shared_region,
1061 &(task_mapping_info.text_region),
1062 &(task_mapping_info.text_size),
1063 &(task_mapping_info.data_region),
1064 &(task_mapping_info.data_size),
1065 &(task_mapping_info.region_mappings),
1066 &(task_mapping_info.client_base),
1067 &(task_mapping_info.alternate_base),
1068 &(task_mapping_info.alternate_next),
55e303ae
A
1069 &(task_mapping_info.fs_base),
1070 &(task_mapping_info.system),
1071 &(task_mapping_info.flags), &next);
1072
1073 {
1074 shared_region_mapping_t default_shared_region;
1075 default_shared_region =
1076 lookup_default_shared_region(
1077 ENV_DEFAULT_ROOT,
1078 task_mapping_info.system);
1079 if(shared_region == default_shared_region) {
1080 default_regions = 1;
1081 }
1082 shared_region_mapping_dealloc(default_shared_region);
1083 }
1084 /* If we are running on a removable file system we must not */
1085 /* be in a set of shared regions or the file system will not */
1086 /* be removable. */
1087 if(((vp->v_mount != rootvnode->v_mount) && (default_regions))
1088 && (lsf_mapping_pool_gauge() < 75)) {
1089 /* We don't want to run out of shared memory */
1090 /* map entries by starting too many private versions */
1091 /* of the shared library structures */
91447636
A
1092 int error2;
1093
1094 error2 = clone_system_shared_regions(!(p->p_flag & P_NOSHLIB),
1095 TRUE, /* chain_regions */
1096 ENV_DEFAULT_ROOT);
1097 if (error2) {
55e303ae
A
1098 goto lsf_bailout_free_vput;
1099 }
1100 local_flags = local_flags & ~NEW_LOCAL_SHARED_REGIONS;
1101 vm_get_shared_region(current_task(), &shared_region);
1102 shared_region_mapping_info(shared_region,
1103 &(task_mapping_info.text_region),
1104 &(task_mapping_info.text_size),
1105 &(task_mapping_info.data_region),
1106 &(task_mapping_info.data_size),
1107 &(task_mapping_info.region_mappings),
1108 &(task_mapping_info.client_base),
1109 &(task_mapping_info.alternate_base),
1110 &(task_mapping_info.alternate_next),
1111 &(task_mapping_info.fs_base),
1112 &(task_mapping_info.system),
d7e50217 1113 &(task_mapping_info.flags), &next);
55e303ae 1114 }
d7e50217 1115
1c79356b
A
1116 /* This is a work-around to allow executables which have been */
1117 /* built without knowledge of the proper shared segment to */
1118 /* load. This code has been architected as a shared region */
1119 /* handler, the knowledge of where the regions are loaded is */
1120 /* problematic for the extension of shared regions as it will */
1121 /* not be easy to know what region an item should go into. */
1122 /* The code below however will get around a short term problem */
1123 /* with executables which believe they are loading at zero. */
1124
1125 {
1126 if (((unsigned int)local_base &
1127 (~(task_mapping_info.text_size - 1))) !=
1128 task_mapping_info.client_base) {
1129 if(local_flags & ALTERNATE_LOAD_SITE) {
1130 local_base = (caddr_t)(
1131 (unsigned int)local_base &
1132 (task_mapping_info.text_size - 1));
1133 local_base = (caddr_t)((unsigned int)local_base
1134 | task_mapping_info.client_base);
1135 } else {
1136 error = EINVAL;
1137 goto lsf_bailout_free_vput;
1138 }
1139 }
1140 }
1141
1c79356b
A
1142
1143 if((kr = copyin_shared_file((vm_offset_t)mapped_file_addr,
1144 mapped_file_size,
1145 (vm_offset_t *)&local_base,
0b4e3aa0 1146 map_cnt, map_list, file_control,
1c79356b
A
1147 &task_mapping_info, &local_flags))) {
1148 switch (kr) {
1149 case KERN_FAILURE:
1150 error = EINVAL;
1151 break;
1152 case KERN_INVALID_ARGUMENT:
1153 error = EINVAL;
1154 break;
1155 case KERN_INVALID_ADDRESS:
91447636 1156 error = EFAULT;
1c79356b
A
1157 break;
1158 case KERN_PROTECTION_FAILURE:
1159 /* save EAUTH for authentication in this */
1160 /* routine */
1161 error = EPERM;
1162 break;
1163 case KERN_NO_SPACE:
1164 error = ENOMEM;
1165 break;
1166 default:
1167 error = EINVAL;
1168 };
1169 if((caller_flags & ALTERNATE_LOAD_SITE) && systemLogDiags) {
0b4e3aa0 1170 printf("load_shared_file: Failed to load shared file! error: 0x%x, Base_address: 0x%x, number of mappings: %d, file_control 0x%x\n", error, local_base, map_cnt, file_control);
1c79356b
A
1171 for(i=0; i<map_cnt; i++) {
1172 printf("load_shared_file: Mapping%d, mapping_offset: 0x%x, size: 0x%x, file_offset: 0x%x, protection: 0x%x\n"
1173 , i, map_list[i].mapping_offset,
1174 map_list[i].size,
1175 map_list[i].file_offset,
1176 map_list[i].protection);
1177 }
1178 }
1179 } else {
9bccf70c
A
1180 if(default_regions)
1181 local_flags |= SYSTEM_REGION_BACKED;
91447636 1182 if(!(error = copyout(&local_flags, CAST_USER_ADDR_T(flags), sizeof (int)))) {
1c79356b 1183 error = copyout(&local_base,
91447636 1184 CAST_USER_ADDR_T(base_address), sizeof (caddr_t));
1c79356b
A
1185 }
1186 }
1187
1188lsf_bailout_free_vput:
91447636 1189 vnode_put(vp);
1c79356b
A
1190
1191lsf_bailout_free:
1192 kmem_free(kernel_map, (vm_offset_t)filename_str,
1193 (vm_size_t)(MAXPATHLEN));
1194 kmem_free(kernel_map, (vm_offset_t)map_list,
1195 (vm_size_t)(map_cnt*sizeof(sf_mapping_t)));
1196
1197lsf_bailout:
1c79356b
A
1198 return error;
1199}
1200
1c79356b 1201int
91447636
A
1202reset_shared_file(__unused struct proc *p, struct reset_shared_file_args *uap,
1203 __unused register int *retval)
1c79356b 1204{
91447636
A
1205 caddr_t *base_address=uap->ba;
1206 int map_cnt=uap->map_cnt;
1207 sf_mapping_t *mappings=uap->mappings;
1c79356b 1208 register int error;
1c79356b 1209
91447636
A
1210 sf_mapping_t *map_list;
1211 caddr_t local_base;
1212 vm_offset_t map_address;
1213 int i;
1214 kern_return_t kret;
1c79356b 1215
91447636 1216 AUDIT_ARG(addr, CAST_DOWN(user_addr_t, base_address));
1c79356b 1217 /* Retrieve the base address */
91447636 1218 if ( (error = copyin(CAST_USER_ADDR_T(base_address), &local_base, sizeof (caddr_t))) ) {
1c79356b
A
1219 goto rsf_bailout;
1220 }
1221
1222 if (((unsigned int)local_base & GLOBAL_SHARED_SEGMENT_MASK)
1223 != GLOBAL_SHARED_TEXT_SEGMENT) {
1224 error = EINVAL;
1225 goto rsf_bailout;
1226 }
1227
1228 kret = kmem_alloc(kernel_map, (vm_offset_t *)&map_list,
1229 (vm_size_t)(map_cnt*sizeof(sf_mapping_t)));
1230 if (kret != KERN_SUCCESS) {
1231 error = ENOMEM;
1232 goto rsf_bailout;
1233 }
1234
91447636
A
1235 if ( (error =
1236 copyin(CAST_USER_ADDR_T(mappings), map_list, (map_cnt*sizeof(sf_mapping_t)))) ) {
1c79356b
A
1237
1238 kmem_free(kernel_map, (vm_offset_t)map_list,
1239 (vm_size_t)(map_cnt*sizeof(sf_mapping_t)));
1240 goto rsf_bailout;
1241 }
1242 for (i = 0; i<map_cnt; i++) {
1243 if((map_list[i].mapping_offset
1244 & GLOBAL_SHARED_SEGMENT_MASK) == 0x10000000) {
1245 map_address = (vm_offset_t)
1246 (local_base + map_list[i].mapping_offset);
1247 vm_deallocate(current_map(),
1248 map_address,
1249 map_list[i].size);
1250 vm_map(current_map(), &map_address,
91447636
A
1251 map_list[i].size, 0,
1252 SHARED_LIB_ALIAS | VM_FLAGS_FIXED,
1c79356b
A
1253 shared_data_region_handle,
1254 ((unsigned int)local_base
1255 & SHARED_DATA_REGION_MASK) +
1256 (map_list[i].mapping_offset
1257 & SHARED_DATA_REGION_MASK),
1258 TRUE, VM_PROT_READ,
1259 VM_PROT_READ, VM_INHERIT_SHARE);
1260 }
1261 }
1262
1263 kmem_free(kernel_map, (vm_offset_t)map_list,
1264 (vm_size_t)(map_cnt*sizeof(sf_mapping_t)));
1265
1266rsf_bailout:
1c79356b
A
1267 return error;
1268}
1269
9bccf70c 1270int
91447636
A
1271new_system_shared_regions(__unused struct proc *p,
1272 __unused struct new_system_shared_regions_args *uap,
1273 register int *retval)
9bccf70c 1274{
9bccf70c
A
1275 if(!(is_suser())) {
1276 *retval = EINVAL;
1277 return EINVAL;
1278 }
1279
55e303ae
A
1280 /* clear all of our existing defaults */
1281 remove_all_shared_regions();
9bccf70c
A
1282
1283 *retval = 0;
1284 return 0;
1285}
1c79356b
A
1286
1287
1288
1289int
91447636
A
1290clone_system_shared_regions(
1291 int shared_regions_active,
1292 int chain_regions,
1293 int base_vnode)
1c79356b
A
1294{
1295 shared_region_mapping_t new_shared_region;
1296 shared_region_mapping_t next;
1297 shared_region_mapping_t old_shared_region;
1298 struct shared_region_task_mappings old_info;
1299 struct shared_region_task_mappings new_info;
1300
1c79356b
A
1301 vm_get_shared_region(current_task(), &old_shared_region);
1302 old_info.self = (vm_offset_t)old_shared_region;
1303 shared_region_mapping_info(old_shared_region,
1304 &(old_info.text_region),
1305 &(old_info.text_size),
1306 &(old_info.data_region),
1307 &(old_info.data_size),
1308 &(old_info.region_mappings),
1309 &(old_info.client_base),
1310 &(old_info.alternate_base),
1311 &(old_info.alternate_next),
55e303ae
A
1312 &(old_info.fs_base),
1313 &(old_info.system),
1c79356b 1314 &(old_info.flags), &next);
55e303ae
A
1315 if ((shared_regions_active) ||
1316 (base_vnode == ENV_DEFAULT_ROOT)) {
1317 if (shared_file_create_system_region(&new_shared_region))
1318 return (ENOMEM);
1319 } else {
1320 new_shared_region =
1321 lookup_default_shared_region(
1322 base_vnode, old_info.system);
1323 if(new_shared_region == NULL) {
1324 shared_file_boot_time_init(
1325 base_vnode, old_info.system);
1326 vm_get_shared_region(current_task(), &new_shared_region);
1327 } else {
1328 vm_set_shared_region(current_task(), new_shared_region);
1329 }
1330 if(old_shared_region)
1331 shared_region_mapping_dealloc(old_shared_region);
1332 }
1c79356b
A
1333 new_info.self = (vm_offset_t)new_shared_region;
1334 shared_region_mapping_info(new_shared_region,
1335 &(new_info.text_region),
1336 &(new_info.text_size),
1337 &(new_info.data_region),
1338 &(new_info.data_size),
1339 &(new_info.region_mappings),
1340 &(new_info.client_base),
1341 &(new_info.alternate_base),
1342 &(new_info.alternate_next),
55e303ae
A
1343 &(new_info.fs_base),
1344 &(new_info.system),
1c79356b 1345 &(new_info.flags), &next);
9bccf70c
A
1346 if(shared_regions_active) {
1347 if(vm_region_clone(old_info.text_region, new_info.text_region)) {
1348 panic("clone_system_shared_regions: shared region mis-alignment 1");
1c79356b
A
1349 shared_region_mapping_dealloc(new_shared_region);
1350 return(EINVAL);
9bccf70c
A
1351 }
1352 if (vm_region_clone(old_info.data_region, new_info.data_region)) {
1353 panic("clone_system_shared_regions: shared region mis-alignment 2");
1c79356b
A
1354 shared_region_mapping_dealloc(new_shared_region);
1355 return(EINVAL);
9bccf70c 1356 }
91447636
A
1357 if (chain_regions) {
1358 /*
1359 * We want a "shadowed" clone, a private superset of the old
1360 * shared region. The info about the old mappings is still
1361 * valid for us.
1362 */
1363 shared_region_object_chain_attach(
1364 new_shared_region, old_shared_region);
1365 } else {
1366 /*
1367 * We want a completely detached clone with no link to
1368 * the old shared region. We'll be removing some mappings
1369 * in our private, cloned, shared region, so the old mappings
1370 * will become irrelevant to us. Since we have a private
1371 * "shared region" now, it isn't going to be shared with
1372 * anyone else and we won't need to maintain mappings info.
1373 */
1374 shared_region_object_chain_detached(new_shared_region);
1375 }
1c79356b
A
1376 }
1377 if (vm_map_region_replace(current_map(), old_info.text_region,
1378 new_info.text_region, old_info.client_base,
1379 old_info.client_base+old_info.text_size)) {
1380 panic("clone_system_shared_regions: shared region mis-alignment 3");
1381 shared_region_mapping_dealloc(new_shared_region);
1382 return(EINVAL);
1383 }
1384 if(vm_map_region_replace(current_map(), old_info.data_region,
1385 new_info.data_region,
1386 old_info.client_base + old_info.text_size,
1387 old_info.client_base
1388 + old_info.text_size + old_info.data_size)) {
1389 panic("clone_system_shared_regions: shared region mis-alignment 4");
1390 shared_region_mapping_dealloc(new_shared_region);
1391 return(EINVAL);
1392 }
1393 vm_set_shared_region(current_task(), new_shared_region);
9bccf70c
A
1394
1395 /* consume the reference which wasn't accounted for in object */
1396 /* chain attach */
91447636 1397 if (!shared_regions_active || !chain_regions)
9bccf70c
A
1398 shared_region_mapping_dealloc(old_shared_region);
1399
1c79356b
A
1400 return(0);
1401
1402}
9bccf70c 1403
9bccf70c
A
1404/* header for the profile name file. The profiled app info is held */
1405/* in the data file and pointed to by elements in the name file */
1406
1407struct profile_names_header {
1408 unsigned int number_of_profiles;
1409 unsigned int user_id;
1410 unsigned int version;
1411 off_t element_array;
1412 unsigned int spare1;
1413 unsigned int spare2;
1414 unsigned int spare3;
1415};
1416
1417struct profile_element {
1418 off_t addr;
1419 vm_size_t size;
1420 unsigned int mod_date;
1421 unsigned int inode;
1422 char name[12];
1423};
1424
1425struct global_profile {
1426 struct vnode *names_vp;
1427 struct vnode *data_vp;
1428 vm_offset_t buf_ptr;
1429 unsigned int user;
1430 unsigned int age;
1431 unsigned int busy;
1432};
1433
1434struct global_profile_cache {
1435 int max_ele;
1436 unsigned int age;
1437 struct global_profile profiles[3];
1438};
1439
91447636
A
1440/* forward declarations */
1441int bsd_open_page_cache_files(unsigned int user,
1442 struct global_profile **profile);
1443void bsd_close_page_cache_files(struct global_profile *profile);
1444int bsd_search_page_cache_data_base(
1445 struct vnode *vp,
1446 struct profile_names_header *database,
1447 char *app_name,
1448 unsigned int mod_date,
1449 unsigned int inode,
1450 off_t *profile,
1451 unsigned int *profile_size);
1452
9bccf70c 1453struct global_profile_cache global_user_profile_cache =
91447636
A
1454 {3, 0, {{NULL, NULL, 0, 0, 0, 0},
1455 {NULL, NULL, 0, 0, 0, 0},
1456 {NULL, NULL, 0, 0, 0, 0}} };
9bccf70c
A
1457
1458/* BSD_OPEN_PAGE_CACHE_FILES: */
1459/* Caller provides a user id. This id was used in */
1460/* prepare_profile_database to create two unique absolute */
1461/* file paths to the associated profile files. These files */
1462/* are either opened or bsd_open_page_cache_files returns an */
1463/* error. The header of the names file is then consulted. */
1464/* The header and the vnodes for the names and data files are */
1465/* returned. */
1466
1467int
1468bsd_open_page_cache_files(
1469 unsigned int user,
1470 struct global_profile **profile)
1471{
91447636 1472 const char *cache_path = "/var/vm/app_profile/";
9bccf70c
A
1473 struct proc *p;
1474 int error;
91447636 1475 vm_size_t resid;
9bccf70c
A
1476 off_t resid_off;
1477 unsigned int lru;
1478 vm_size_t size;
1479
1480 struct vnode *names_vp;
1481 struct vnode *data_vp;
1482 vm_offset_t names_buf;
1483 vm_offset_t buf_ptr;
1484
1485 int profile_names_length;
1486 int profile_data_length;
1487 char *profile_data_string;
1488 char *profile_names_string;
1489 char *substring;
1490
91447636
A
1491 off_t file_size;
1492 struct vfs_context context;
9bccf70c 1493
9bccf70c
A
1494 kern_return_t ret;
1495
1496 struct nameidata nd_names;
1497 struct nameidata nd_data;
9bccf70c
A
1498 int i;
1499
1500
1501 p = current_proc();
1502
91447636
A
1503 context.vc_proc = p;
1504 context.vc_ucred = kauth_cred_get();
1505
9bccf70c
A
1506restart:
1507 for(i = 0; i<global_user_profile_cache.max_ele; i++) {
1508 if((global_user_profile_cache.profiles[i].user == user)
1509 && (global_user_profile_cache.profiles[i].data_vp
1510 != NULL)) {
1511 *profile = &global_user_profile_cache.profiles[i];
1512 /* already in cache, we're done */
1513 if ((*profile)->busy) {
1514 /*
1515 * drop funnel and wait
1516 */
1517 (void)tsleep((void *)
1518 *profile,
1519 PRIBIO, "app_profile", 0);
1520 goto restart;
1521 }
1522 (*profile)->busy = 1;
1523 (*profile)->age = global_user_profile_cache.age;
91447636
A
1524
1525 /*
1526 * entries in cache are held with a valid
1527 * usecount... take an iocount which will
1528 * be dropped in "bsd_close_page_cache_files"
1529 * which is called after the read or writes to
1530 * these files are done
1531 */
1532 if ( (vnode_getwithref((*profile)->data_vp)) ) {
1533
1534 vnode_rele((*profile)->data_vp);
1535 vnode_rele((*profile)->names_vp);
1536
1537 (*profile)->data_vp = NULL;
1538 (*profile)->busy = 0;
1539 wakeup(*profile);
1540
1541 goto restart;
1542 }
1543 if ( (vnode_getwithref((*profile)->names_vp)) ) {
1544
1545 vnode_put((*profile)->data_vp);
1546 vnode_rele((*profile)->data_vp);
1547 vnode_rele((*profile)->names_vp);
1548
1549 (*profile)->data_vp = NULL;
1550 (*profile)->busy = 0;
1551 wakeup(*profile);
1552
1553 goto restart;
1554 }
9bccf70c
A
1555 global_user_profile_cache.age+=1;
1556 return 0;
1557 }
1558 }
1559
1560 lru = global_user_profile_cache.age;
55e303ae 1561 *profile = NULL;
9bccf70c 1562 for(i = 0; i<global_user_profile_cache.max_ele; i++) {
55e303ae
A
1563 /* Skip entry if it is in the process of being reused */
1564 if(global_user_profile_cache.profiles[i].data_vp ==
1565 (struct vnode *)0xFFFFFFFF)
1566 continue;
1567 /* Otherwise grab the first empty entry */
9bccf70c
A
1568 if(global_user_profile_cache.profiles[i].data_vp == NULL) {
1569 *profile = &global_user_profile_cache.profiles[i];
1570 (*profile)->age = global_user_profile_cache.age;
9bccf70c
A
1571 break;
1572 }
55e303ae 1573 /* Otherwise grab the oldest entry */
9bccf70c
A
1574 if(global_user_profile_cache.profiles[i].age < lru) {
1575 lru = global_user_profile_cache.profiles[i].age;
1576 *profile = &global_user_profile_cache.profiles[i];
1577 }
1578 }
1579
55e303ae
A
1580 /* Did we set it? */
1581 if (*profile == NULL) {
1582 /*
1583 * No entries are available; this can only happen if all
1584 * of them are currently in the process of being reused;
1585 * if this happens, we sleep on the address of the first
1586 * element, and restart. This is less than ideal, but we
1587 * know it will work because we know that there will be a
1588 * wakeup on any entry currently in the process of being
1589 * reused.
1590 *
1591 * XXX Reccomend a two handed clock and more than 3 total
1592 * XXX cache entries at some point in the future.
1593 */
1594 /*
1595 * drop funnel and wait
1596 */
1597 (void)tsleep((void *)
1598 &global_user_profile_cache.profiles[0],
1599 PRIBIO, "app_profile", 0);
1600 goto restart;
1601 }
1602
1603 /*
1604 * If it's currently busy, we've picked the one at the end of the
1605 * LRU list, but it's currently being actively used. We sleep on
1606 * its address and restart.
1607 */
9bccf70c
A
1608 if ((*profile)->busy) {
1609 /*
1610 * drop funnel and wait
1611 */
1612 (void)tsleep((void *)
55e303ae 1613 *profile,
9bccf70c
A
1614 PRIBIO, "app_profile", 0);
1615 goto restart;
1616 }
1617 (*profile)->busy = 1;
1618 (*profile)->user = user;
1619
55e303ae
A
1620 /*
1621 * put dummy value in for now to get competing request to wait
1622 * above until we are finished
1623 *
1624 * Save the data_vp before setting it, so we can set it before
1625 * we kmem_free() or vrele(). If we don't do this, then we
1626 * have a potential funnel race condition we have to deal with.
1627 */
1628 data_vp = (*profile)->data_vp;
1629 (*profile)->data_vp = (struct vnode *)0xFFFFFFFF;
1630
1631 /*
1632 * Age the cache here in all cases; this guarantees that we won't
1633 * be reusing only one entry over and over, once the system reaches
1634 * steady-state.
1635 */
1636 global_user_profile_cache.age+=1;
1637
1638 if(data_vp != NULL) {
9bccf70c
A
1639 kmem_free(kernel_map,
1640 (*profile)->buf_ptr, 4 * PAGE_SIZE);
1641 if ((*profile)->names_vp) {
91447636 1642 vnode_rele((*profile)->names_vp);
9bccf70c
A
1643 (*profile)->names_vp = NULL;
1644 }
91447636 1645 vnode_rele(data_vp);
9bccf70c 1646 }
9bccf70c
A
1647
1648 /* Try to open the appropriate users profile files */
1649 /* If neither file is present, try to create them */
1650 /* If one file is present and the other not, fail. */
1651 /* If the files do exist, check them for the app_file */
1652 /* requested and read it in if present */
1653
9bccf70c
A
1654 ret = kmem_alloc(kernel_map,
1655 (vm_offset_t *)&profile_data_string, PATH_MAX);
1656
1657 if(ret) {
1658 (*profile)->data_vp = NULL;
1659 (*profile)->busy = 0;
1660 wakeup(*profile);
1661 return ENOMEM;
1662 }
1663
1664 /* Split the buffer in half since we know the size of */
1665 /* our file path and our allocation is adequate for */
1666 /* both file path names */
1667 profile_names_string = profile_data_string + (PATH_MAX/2);
1668
1669
1670 strcpy(profile_data_string, cache_path);
1671 strcpy(profile_names_string, cache_path);
1672 profile_names_length = profile_data_length
1673 = strlen(profile_data_string);
1674 substring = profile_data_string + profile_data_length;
1675 sprintf(substring, "%x_data", user);
1676 substring = profile_names_string + profile_names_length;
1677 sprintf(substring, "%x_names", user);
1678
1679 /* We now have the absolute file names */
1680
1681 ret = kmem_alloc(kernel_map,
1682 (vm_offset_t *)&names_buf, 4 * PAGE_SIZE);
1683 if(ret) {
1684 kmem_free(kernel_map,
1685 (vm_offset_t)profile_data_string, PATH_MAX);
1686 (*profile)->data_vp = NULL;
1687 (*profile)->busy = 0;
1688 wakeup(*profile);
1689 return ENOMEM;
1690 }
1691
1692 NDINIT(&nd_names, LOOKUP, FOLLOW | LOCKLEAF,
91447636 1693 UIO_SYSSPACE32, CAST_USER_ADDR_T(profile_names_string), &context);
9bccf70c 1694 NDINIT(&nd_data, LOOKUP, FOLLOW | LOCKLEAF,
91447636
A
1695 UIO_SYSSPACE32, CAST_USER_ADDR_T(profile_data_string), &context);
1696
1697 if ( (error = vn_open(&nd_data, FREAD | FWRITE, 0)) ) {
9bccf70c
A
1698#ifdef notdef
1699 printf("bsd_open_page_cache_files: CacheData file not found %s\n",
1700 profile_data_string);
1701#endif
1702 kmem_free(kernel_map,
1703 (vm_offset_t)names_buf, 4 * PAGE_SIZE);
1704 kmem_free(kernel_map,
1705 (vm_offset_t)profile_data_string, PATH_MAX);
1706 (*profile)->data_vp = NULL;
1707 (*profile)->busy = 0;
1708 wakeup(*profile);
1709 return error;
1710 }
9bccf70c 1711 data_vp = nd_data.ni_vp;
9bccf70c 1712
91447636 1713 if ( (error = vn_open(&nd_names, FREAD | FWRITE, 0)) ) {
9bccf70c
A
1714 printf("bsd_open_page_cache_files: NamesData file not found %s\n",
1715 profile_data_string);
1716 kmem_free(kernel_map,
1717 (vm_offset_t)names_buf, 4 * PAGE_SIZE);
1718 kmem_free(kernel_map,
1719 (vm_offset_t)profile_data_string, PATH_MAX);
91447636
A
1720
1721 vnode_rele(data_vp);
1722 vnode_put(data_vp);
1723
9bccf70c
A
1724 (*profile)->data_vp = NULL;
1725 (*profile)->busy = 0;
1726 wakeup(*profile);
1727 return error;
1728 }
1729 names_vp = nd_names.ni_vp;
1730
91447636 1731 if ((error = vnode_size(names_vp, &file_size, &context)) != 0) {
9bccf70c
A
1732 printf("bsd_open_page_cache_files: Can't stat name file %s\n", profile_names_string);
1733 kmem_free(kernel_map,
1734 (vm_offset_t)profile_data_string, PATH_MAX);
1735 kmem_free(kernel_map,
1736 (vm_offset_t)names_buf, 4 * PAGE_SIZE);
91447636
A
1737
1738 vnode_rele(names_vp);
1739 vnode_put(names_vp);
1740 vnode_rele(data_vp);
1741 vnode_put(data_vp);
1742
9bccf70c
A
1743 (*profile)->data_vp = NULL;
1744 (*profile)->busy = 0;
1745 wakeup(*profile);
1746 return error;
1747 }
1748
91447636 1749 size = file_size;
9bccf70c
A
1750 if(size > 4 * PAGE_SIZE)
1751 size = 4 * PAGE_SIZE;
1752 buf_ptr = names_buf;
1753 resid_off = 0;
1754
1755 while(size) {
1756 error = vn_rdwr(UIO_READ, names_vp, (caddr_t)buf_ptr,
1757 size, resid_off,
91447636 1758 UIO_SYSSPACE32, IO_NODELOCKED, kauth_cred_get(), &resid, p);
9bccf70c
A
1759 if((error) || (size == resid)) {
1760 if(!error) {
1761 error = EINVAL;
1762 }
1763 kmem_free(kernel_map,
1764 (vm_offset_t)profile_data_string, PATH_MAX);
1765 kmem_free(kernel_map,
1766 (vm_offset_t)names_buf, 4 * PAGE_SIZE);
91447636
A
1767
1768 vnode_rele(names_vp);
1769 vnode_put(names_vp);
1770 vnode_rele(data_vp);
1771 vnode_put(data_vp);
1772
9bccf70c
A
1773 (*profile)->data_vp = NULL;
1774 (*profile)->busy = 0;
1775 wakeup(*profile);
1776 return error;
1777 }
1778 buf_ptr += size-resid;
1779 resid_off += size-resid;
1780 size = resid;
1781 }
9bccf70c 1782 kmem_free(kernel_map, (vm_offset_t)profile_data_string, PATH_MAX);
91447636 1783
9bccf70c
A
1784 (*profile)->names_vp = names_vp;
1785 (*profile)->data_vp = data_vp;
1786 (*profile)->buf_ptr = names_buf;
91447636
A
1787
1788 /*
1789 * at this point, the both the names_vp and the data_vp have
1790 * both a valid usecount and an iocount held
1791 */
9bccf70c
A
1792 return 0;
1793
1794}
1795
1796void
1797bsd_close_page_cache_files(
1798 struct global_profile *profile)
1799{
91447636
A
1800 vnode_put(profile->data_vp);
1801 vnode_put(profile->names_vp);
1802
9bccf70c
A
1803 profile->busy = 0;
1804 wakeup(profile);
1805}
1806
1807int
1808bsd_read_page_cache_file(
1809 unsigned int user,
1810 int *fid,
1811 int *mod,
1812 char *app_name,
1813 struct vnode *app_vp,
1814 vm_offset_t *buffer,
91447636 1815 vm_offset_t *bufsize)
9bccf70c
A
1816{
1817
91447636 1818 boolean_t funnel_state;
9bccf70c
A
1819
1820 struct proc *p;
1821 int error;
91447636 1822 unsigned int resid;
9bccf70c
A
1823
1824 off_t profile;
1825 unsigned int profile_size;
1826
1827 vm_offset_t names_buf;
91447636
A
1828 struct vnode_attr va;
1829 struct vfs_context context;
9bccf70c
A
1830
1831 kern_return_t ret;
1832
1833 struct vnode *names_vp;
1834 struct vnode *data_vp;
9bccf70c
A
1835
1836 struct global_profile *uid_files;
1837
1838 funnel_state = thread_funnel_set(kernel_flock, TRUE);
1839
1840 /* Try to open the appropriate users profile files */
1841 /* If neither file is present, try to create them */
1842 /* If one file is present and the other not, fail. */
1843 /* If the files do exist, check them for the app_file */
1844 /* requested and read it in if present */
1845
1846
1847 error = bsd_open_page_cache_files(user, &uid_files);
1848 if(error) {
1849 thread_funnel_set(kernel_flock, funnel_state);
1850 return EINVAL;
1851 }
1852
1853 p = current_proc();
1854
1855 names_vp = uid_files->names_vp;
1856 data_vp = uid_files->data_vp;
1857 names_buf = uid_files->buf_ptr;
1858
91447636
A
1859 context.vc_proc = p;
1860 context.vc_ucred = kauth_cred_get();
9bccf70c 1861
91447636
A
1862 VATTR_INIT(&va);
1863 VATTR_WANTED(&va, va_fileid);
1864 VATTR_WANTED(&va, va_modify_time);
1865
1866 if ((error = vnode_getattr(app_vp, &va, &context))) {
9bccf70c
A
1867 printf("bsd_read_cache_file: Can't stat app file %s\n", app_name);
1868 bsd_close_page_cache_files(uid_files);
1869 thread_funnel_set(kernel_flock, funnel_state);
1870 return error;
1871 }
1872
91447636
A
1873 *fid = (u_long)va.va_fileid;
1874 *mod = va.va_modify_time.tv_sec;
9bccf70c 1875
91447636
A
1876 if (bsd_search_page_cache_data_base(
1877 names_vp,
1878 (struct profile_names_header *)names_buf,
1879 app_name,
1880 (unsigned int) va.va_modify_time.tv_sec,
1881 (u_long)va.va_fileid, &profile, &profile_size) == 0) {
9bccf70c
A
1882 /* profile is an offset in the profile data base */
1883 /* It is zero if no profile data was found */
1884
1885 if(profile_size == 0) {
91447636
A
1886 *buffer = 0;
1887 *bufsize = 0;
9bccf70c
A
1888 bsd_close_page_cache_files(uid_files);
1889 thread_funnel_set(kernel_flock, funnel_state);
1890 return 0;
1891 }
1892 ret = (vm_offset_t)(kmem_alloc(kernel_map, buffer, profile_size));
1893 if(ret) {
9bccf70c
A
1894 bsd_close_page_cache_files(uid_files);
1895 thread_funnel_set(kernel_flock, funnel_state);
1896 return ENOMEM;
1897 }
91447636 1898 *bufsize = profile_size;
9bccf70c
A
1899 while(profile_size) {
1900 error = vn_rdwr(UIO_READ, data_vp,
1901 (caddr_t) *buffer, profile_size,
91447636
A
1902 profile, UIO_SYSSPACE32, IO_NODELOCKED,
1903 kauth_cred_get(), &resid, p);
d7e50217 1904 if((error) || (profile_size == resid)) {
9bccf70c
A
1905 bsd_close_page_cache_files(uid_files);
1906 kmem_free(kernel_map, (vm_offset_t)*buffer, profile_size);
1907 thread_funnel_set(kernel_flock, funnel_state);
1908 return EINVAL;
1909 }
1910 profile += profile_size - resid;
1911 profile_size = resid;
1912 }
9bccf70c
A
1913 bsd_close_page_cache_files(uid_files);
1914 thread_funnel_set(kernel_flock, funnel_state);
1915 return 0;
1916 } else {
9bccf70c
A
1917 bsd_close_page_cache_files(uid_files);
1918 thread_funnel_set(kernel_flock, funnel_state);
1919 return EINVAL;
1920 }
1921
1922}
1923
1924int
1925bsd_search_page_cache_data_base(
1926 struct vnode *vp,
1927 struct profile_names_header *database,
1928 char *app_name,
1929 unsigned int mod_date,
1930 unsigned int inode,
1931 off_t *profile,
1932 unsigned int *profile_size)
1933{
1934
1935 struct proc *p;
1936
1937 unsigned int i;
1938 struct profile_element *element;
1939 unsigned int ele_total;
1940 unsigned int extended_list = 0;
1941 off_t file_off = 0;
1942 unsigned int size;
1943 off_t resid_off;
91447636
A
1944 unsigned int resid;
1945 vm_offset_t local_buf = 0;
9bccf70c
A
1946
1947 int error;
1948 kern_return_t ret;
1949
1950 p = current_proc();
1951
1952 if(((vm_offset_t)database->element_array) !=
1953 sizeof(struct profile_names_header)) {
1954 return EINVAL;
1955 }
1956 element = (struct profile_element *)(
1957 (vm_offset_t)database->element_array +
1958 (vm_offset_t)database);
1959
1960 ele_total = database->number_of_profiles;
1961
1962 *profile = 0;
1963 *profile_size = 0;
1964 while(ele_total) {
1965 /* note: code assumes header + n*ele comes out on a page boundary */
1966 if(((local_buf == 0) && (sizeof(struct profile_names_header) +
1967 (ele_total * sizeof(struct profile_element)))
1968 > (PAGE_SIZE * 4)) ||
1969 ((local_buf != 0) &&
1970 (ele_total * sizeof(struct profile_element))
1971 > (PAGE_SIZE * 4))) {
1972 extended_list = ele_total;
1973 if(element == (struct profile_element *)
1974 ((vm_offset_t)database->element_array +
1975 (vm_offset_t)database)) {
1976 ele_total = ((PAGE_SIZE * 4)/sizeof(struct profile_element)) - 1;
1977 } else {
1978 ele_total = (PAGE_SIZE * 4)/sizeof(struct profile_element);
1979 }
1980 extended_list -= ele_total;
1981 }
1982 for (i=0; i<ele_total; i++) {
1983 if((mod_date == element[i].mod_date)
1984 && (inode == element[i].inode)) {
1985 if(strncmp(element[i].name, app_name, 12) == 0) {
1986 *profile = element[i].addr;
1987 *profile_size = element[i].size;
91447636
A
1988 if(local_buf != 0) {
1989 kmem_free(kernel_map, local_buf, 4 * PAGE_SIZE);
9bccf70c
A
1990 }
1991 return 0;
1992 }
1993 }
1994 }
1995 if(extended_list == 0)
1996 break;
91447636
A
1997 if(local_buf == 0) {
1998 ret = kmem_alloc(kernel_map, &local_buf, 4 * PAGE_SIZE);
9bccf70c
A
1999 if(ret != KERN_SUCCESS) {
2000 return ENOMEM;
2001 }
2002 }
2003 element = (struct profile_element *)local_buf;
2004 ele_total = extended_list;
2005 extended_list = 0;
2006 file_off += 4 * PAGE_SIZE;
2007 if((ele_total * sizeof(struct profile_element)) >
2008 (PAGE_SIZE * 4)) {
2009 size = PAGE_SIZE * 4;
2010 } else {
2011 size = ele_total * sizeof(struct profile_element);
2012 }
2013 resid_off = 0;
2014 while(size) {
2015 error = vn_rdwr(UIO_READ, vp,
55e303ae 2016 CAST_DOWN(caddr_t, (local_buf + resid_off)),
91447636
A
2017 size, file_off + resid_off, UIO_SYSSPACE32,
2018 IO_NODELOCKED, kauth_cred_get(), &resid, p);
d7e50217 2019 if((error) || (size == resid)) {
91447636
A
2020 if(local_buf != 0) {
2021 kmem_free(kernel_map, local_buf, 4 * PAGE_SIZE);
9bccf70c
A
2022 }
2023 return EINVAL;
2024 }
2025 resid_off += size-resid;
2026 size = resid;
2027 }
2028 }
91447636
A
2029 if(local_buf != 0) {
2030 kmem_free(kernel_map, local_buf, 4 * PAGE_SIZE);
9bccf70c
A
2031 }
2032 return 0;
2033}
2034
2035int
2036bsd_write_page_cache_file(
2037 unsigned int user,
2038 char *file_name,
2039 caddr_t buffer,
2040 vm_size_t size,
2041 int mod,
2042 int fid)
2043{
2044 struct proc *p;
91447636 2045 int resid;
9bccf70c 2046 off_t resid_off;
91447636 2047 int error;
9bccf70c 2048 boolean_t funnel_state;
91447636
A
2049 off_t file_size;
2050 struct vfs_context context;
2051 off_t profile;
2052 unsigned int profile_size;
9bccf70c
A
2053
2054 vm_offset_t names_buf;
2055 struct vnode *names_vp;
2056 struct vnode *data_vp;
9bccf70c
A
2057 struct profile_names_header *profile_header;
2058 off_t name_offset;
9bccf70c
A
2059 struct global_profile *uid_files;
2060
2061
2062 funnel_state = thread_funnel_set(kernel_flock, TRUE);
2063
2064
9bccf70c
A
2065 error = bsd_open_page_cache_files(user, &uid_files);
2066 if(error) {
2067 thread_funnel_set(kernel_flock, funnel_state);
2068 return EINVAL;
2069 }
2070
2071 p = current_proc();
2072
2073 names_vp = uid_files->names_vp;
2074 data_vp = uid_files->data_vp;
2075 names_buf = uid_files->buf_ptr;
2076
9bccf70c
A
2077 /* Stat data file for size */
2078
91447636
A
2079 context.vc_proc = p;
2080 context.vc_ucred = kauth_cred_get();
2081
2082 if ((error = vnode_size(data_vp, &file_size, &context)) != 0) {
9bccf70c
A
2083 printf("bsd_write_page_cache_file: Can't stat profile data %s\n", file_name);
2084 bsd_close_page_cache_files(uid_files);
2085 thread_funnel_set(kernel_flock, funnel_state);
2086 return error;
2087 }
2088
2089 if (bsd_search_page_cache_data_base(names_vp,
2090 (struct profile_names_header *)names_buf,
2091 file_name, (unsigned int) mod,
2092 fid, &profile, &profile_size) == 0) {
2093 /* profile is an offset in the profile data base */
2094 /* It is zero if no profile data was found */
2095
2096 if(profile_size == 0) {
2097 unsigned int header_size;
2098 vm_offset_t buf_ptr;
2099
2100 /* Our Write case */
2101
2102 /* read header for last entry */
2103 profile_header =
2104 (struct profile_names_header *)names_buf;
2105 name_offset = sizeof(struct profile_names_header) +
2106 (sizeof(struct profile_element)
2107 * profile_header->number_of_profiles);
2108 profile_header->number_of_profiles += 1;
2109
2110 if(name_offset < PAGE_SIZE * 4) {
2111 struct profile_element *name;
2112 /* write new entry */
2113 name = (struct profile_element *)
2114 (names_buf + (vm_offset_t)name_offset);
91447636 2115 name->addr = file_size;
9bccf70c
A
2116 name->size = size;
2117 name->mod_date = mod;
2118 name->inode = fid;
2119 strncpy (name->name, file_name, 12);
2120 } else {
2121 unsigned int ele_size;
2122 struct profile_element name;
2123 /* write new entry */
91447636 2124 name.addr = file_size;
9bccf70c
A
2125 name.size = size;
2126 name.mod_date = mod;
2127 name.inode = fid;
2128 strncpy (name.name, file_name, 12);
2129 /* write element out separately */
2130 ele_size = sizeof(struct profile_element);
2131 buf_ptr = (vm_offset_t)&name;
2132 resid_off = name_offset;
2133
2134 while(ele_size) {
2135 error = vn_rdwr(UIO_WRITE, names_vp,
2136 (caddr_t)buf_ptr,
2137 ele_size, resid_off,
91447636
A
2138 UIO_SYSSPACE32, IO_NODELOCKED,
2139 kauth_cred_get(), &resid, p);
9bccf70c
A
2140 if(error) {
2141 printf("bsd_write_page_cache_file: Can't write name_element %x\n", user);
9bccf70c
A
2142 bsd_close_page_cache_files(
2143 uid_files);
2144 thread_funnel_set(
2145 kernel_flock,
2146 funnel_state);
2147 return error;
2148 }
2149 buf_ptr += (vm_offset_t)
2150 ele_size-resid;
2151 resid_off += ele_size-resid;
2152 ele_size = resid;
2153 }
2154 }
2155
2156 if(name_offset < PAGE_SIZE * 4) {
2157 header_size = name_offset +
2158 sizeof(struct profile_element);
2159
2160 } else {
2161 header_size =
2162 sizeof(struct profile_names_header);
2163 }
2164 buf_ptr = (vm_offset_t)profile_header;
2165 resid_off = 0;
2166
2167 /* write names file header */
2168 while(header_size) {
2169 error = vn_rdwr(UIO_WRITE, names_vp,
2170 (caddr_t)buf_ptr,
2171 header_size, resid_off,
91447636
A
2172 UIO_SYSSPACE32, IO_NODELOCKED,
2173 kauth_cred_get(), &resid, p);
9bccf70c 2174 if(error) {
9bccf70c
A
2175 printf("bsd_write_page_cache_file: Can't write header %x\n", user);
2176 bsd_close_page_cache_files(
2177 uid_files);
2178 thread_funnel_set(
2179 kernel_flock, funnel_state);
2180 return error;
2181 }
2182 buf_ptr += (vm_offset_t)header_size-resid;
2183 resid_off += header_size-resid;
2184 header_size = resid;
2185 }
2186 /* write profile to data file */
91447636 2187 resid_off = file_size;
9bccf70c
A
2188 while(size) {
2189 error = vn_rdwr(UIO_WRITE, data_vp,
2190 (caddr_t)buffer, size, resid_off,
91447636
A
2191 UIO_SYSSPACE32, IO_NODELOCKED,
2192 kauth_cred_get(), &resid, p);
9bccf70c 2193 if(error) {
9bccf70c
A
2194 printf("bsd_write_page_cache_file: Can't write header %x\n", user);
2195 bsd_close_page_cache_files(
2196 uid_files);
2197 thread_funnel_set(
2198 kernel_flock, funnel_state);
2199 return error;
2200 }
2201 buffer += size-resid;
2202 resid_off += size-resid;
2203 size = resid;
2204 }
9bccf70c
A
2205 bsd_close_page_cache_files(uid_files);
2206 thread_funnel_set(kernel_flock, funnel_state);
2207 return 0;
2208 }
2209 /* Someone else wrote a twin profile before us */
9bccf70c
A
2210 bsd_close_page_cache_files(uid_files);
2211 thread_funnel_set(kernel_flock, funnel_state);
2212 return 0;
2213 } else {
9bccf70c
A
2214 bsd_close_page_cache_files(uid_files);
2215 thread_funnel_set(kernel_flock, funnel_state);
2216 return EINVAL;
2217 }
2218
2219}
2220
2221int
2222prepare_profile_database(int user)
2223{
91447636 2224 const char *cache_path = "/var/vm/app_profile/";
9bccf70c
A
2225 struct proc *p;
2226 int error;
2227 int resid;
2228 off_t resid_off;
9bccf70c
A
2229 vm_size_t size;
2230
2231 struct vnode *names_vp;
2232 struct vnode *data_vp;
2233 vm_offset_t names_buf;
2234 vm_offset_t buf_ptr;
2235
2236 int profile_names_length;
2237 int profile_data_length;
2238 char *profile_data_string;
2239 char *profile_names_string;
2240 char *substring;
2241
91447636
A
2242 struct vnode_attr va;
2243 struct vfs_context context;
9bccf70c
A
2244
2245 struct profile_names_header *profile_header;
2246 kern_return_t ret;
2247
2248 struct nameidata nd_names;
2249 struct nameidata nd_data;
2250
9bccf70c
A
2251 p = current_proc();
2252
91447636
A
2253 context.vc_proc = p;
2254 context.vc_ucred = kauth_cred_get();
2255
9bccf70c
A
2256 ret = kmem_alloc(kernel_map,
2257 (vm_offset_t *)&profile_data_string, PATH_MAX);
2258
2259 if(ret) {
2260 return ENOMEM;
2261 }
2262
2263 /* Split the buffer in half since we know the size of */
2264 /* our file path and our allocation is adequate for */
2265 /* both file path names */
2266 profile_names_string = profile_data_string + (PATH_MAX/2);
2267
2268
2269 strcpy(profile_data_string, cache_path);
2270 strcpy(profile_names_string, cache_path);
2271 profile_names_length = profile_data_length
2272 = strlen(profile_data_string);
2273 substring = profile_data_string + profile_data_length;
2274 sprintf(substring, "%x_data", user);
2275 substring = profile_names_string + profile_names_length;
2276 sprintf(substring, "%x_names", user);
2277
2278 /* We now have the absolute file names */
2279
2280 ret = kmem_alloc(kernel_map,
2281 (vm_offset_t *)&names_buf, 4 * PAGE_SIZE);
2282 if(ret) {
2283 kmem_free(kernel_map,
2284 (vm_offset_t)profile_data_string, PATH_MAX);
2285 return ENOMEM;
2286 }
2287
2288 NDINIT(&nd_names, LOOKUP, FOLLOW,
91447636 2289 UIO_SYSSPACE32, CAST_USER_ADDR_T(profile_names_string), &context);
9bccf70c 2290 NDINIT(&nd_data, LOOKUP, FOLLOW,
91447636 2291 UIO_SYSSPACE32, CAST_USER_ADDR_T(profile_data_string), &context);
9bccf70c 2292
91447636
A
2293 if ( (error = vn_open(&nd_data,
2294 O_CREAT | O_EXCL | FWRITE, S_IRUSR|S_IWUSR)) ) {
9bccf70c
A
2295 kmem_free(kernel_map,
2296 (vm_offset_t)names_buf, 4 * PAGE_SIZE);
2297 kmem_free(kernel_map,
2298 (vm_offset_t)profile_data_string, PATH_MAX);
91447636 2299
9bccf70c
A
2300 return 0;
2301 }
9bccf70c 2302 data_vp = nd_data.ni_vp;
9bccf70c 2303
91447636
A
2304 if ( (error = vn_open(&nd_names,
2305 O_CREAT | O_EXCL | FWRITE, S_IRUSR|S_IWUSR)) ) {
9bccf70c
A
2306 printf("prepare_profile_database: Can't create CacheNames %s\n",
2307 profile_data_string);
2308 kmem_free(kernel_map,
2309 (vm_offset_t)names_buf, 4 * PAGE_SIZE);
2310 kmem_free(kernel_map,
2311 (vm_offset_t)profile_data_string, PATH_MAX);
91447636
A
2312
2313 vnode_rele(data_vp);
2314 vnode_put(data_vp);
2315
9bccf70c
A
2316 return error;
2317 }
9bccf70c
A
2318 names_vp = nd_names.ni_vp;
2319
9bccf70c
A
2320 /* Write Header for new names file */
2321
2322 profile_header = (struct profile_names_header *)names_buf;
2323
2324 profile_header->number_of_profiles = 0;
2325 profile_header->user_id = user;
2326 profile_header->version = 1;
2327 profile_header->element_array =
2328 sizeof(struct profile_names_header);
2329 profile_header->spare1 = 0;
2330 profile_header->spare2 = 0;
2331 profile_header->spare3 = 0;
2332
2333 size = sizeof(struct profile_names_header);
2334 buf_ptr = (vm_offset_t)profile_header;
2335 resid_off = 0;
2336
2337 while(size) {
2338 error = vn_rdwr(UIO_WRITE, names_vp,
2339 (caddr_t)buf_ptr, size, resid_off,
91447636
A
2340 UIO_SYSSPACE32, IO_NODELOCKED,
2341 kauth_cred_get(), &resid, p);
9bccf70c
A
2342 if(error) {
2343 printf("prepare_profile_database: Can't write header %s\n", profile_names_string);
2344 kmem_free(kernel_map,
2345 (vm_offset_t)names_buf, 4 * PAGE_SIZE);
2346 kmem_free(kernel_map,
2347 (vm_offset_t)profile_data_string,
2348 PATH_MAX);
91447636
A
2349
2350 vnode_rele(names_vp);
2351 vnode_put(names_vp);
2352 vnode_rele(data_vp);
2353 vnode_put(data_vp);
2354
9bccf70c
A
2355 return error;
2356 }
2357 buf_ptr += size-resid;
2358 resid_off += size-resid;
2359 size = resid;
2360 }
91447636
A
2361 VATTR_INIT(&va);
2362 VATTR_SET(&va, va_uid, user);
9bccf70c 2363
91447636 2364 error = vnode_setattr(names_vp, &va, &context);
9bccf70c
A
2365 if(error) {
2366 printf("prepare_profile_database: "
2367 "Can't set user %s\n", profile_names_string);
2368 }
91447636
A
2369 vnode_rele(names_vp);
2370 vnode_put(names_vp);
9bccf70c 2371
91447636
A
2372 VATTR_INIT(&va);
2373 VATTR_SET(&va, va_uid, user);
2374 error = vnode_setattr(data_vp, &va, &context);
9bccf70c
A
2375 if(error) {
2376 printf("prepare_profile_database: "
2377 "Can't set user %s\n", profile_data_string);
2378 }
91447636
A
2379 vnode_rele(data_vp);
2380 vnode_put(data_vp);
2381
9bccf70c
A
2382 kmem_free(kernel_map,
2383 (vm_offset_t)profile_data_string, PATH_MAX);
2384 kmem_free(kernel_map,
2385 (vm_offset_t)names_buf, 4 * PAGE_SIZE);
2386 return 0;
2387
2388}