The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/vm/vm_unix.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000-2004 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  * 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  */
   31 
   32 
   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>
   39 #include <mach/mach_traps.h>
   40 #include <mach/time_value.h>
   41 #include <mach/vm_map.h>
   42 #include <mach/vm_param.h>
   43 #include <mach/vm_prot.h>
   44 #include <mach/port.h>
   45 
   46 #include <sys/file_internal.h>
   47 #include <sys/param.h>
   48 #include <sys/systm.h>
   49 #include <sys/dir.h>
   50 #include <sys/namei.h>
   51 #include <sys/proc_internal.h>
   52 #include <sys/kauth.h>
   53 #include <sys/vm.h>
   54 #include <sys/file.h>
   55 #include <sys/vnode_internal.h>
   56 #include <sys/mount.h>
   57 #include <sys/trace.h>
   58 #include <sys/kernel.h>
   59 #include <sys/ubc_internal.h>
   60 #include <sys/user.h>
   61 #include <sys/stat.h>
   62 #include <sys/sysproto.h>
   63 #include <sys/mman.h>
   64 
   65 #include <bsm/audit_kernel.h>
   66 #include <bsm/audit_kevents.h>
   67 
   68 #include <kern/kalloc.h>
   69 #include <vm/vm_map.h>
   70 #include <vm/vm_kern.h>
   71 
   72 #include <machine/spl.h>
   73 
   74 #include <mach/shared_memory_server.h>
   75 #include <vm/vm_shared_memory_server.h>
   76 
   77 #include <vm/vm_protos.h>
   78 
   79 
   80 int
   81 useracc(
   82         user_addr_t     addr,
   83         user_size_t     len,
   84         int     prot)
   85 {
   86         return (vm_map_check_protection(
   87                         current_map(),
   88                         vm_map_trunc_page(addr), vm_map_round_page(addr+len),
   89                         prot == B_READ ? VM_PROT_READ : VM_PROT_WRITE));
   90 }
   91 
   92 int
   93 vslock(
   94         user_addr_t     addr,
   95         user_size_t     len)
   96 {
   97         kern_return_t kret;
   98         kret = vm_map_wire(current_map(), vm_map_trunc_page(addr),
   99                         vm_map_round_page(addr+len), 
  100                         VM_PROT_READ | VM_PROT_WRITE ,FALSE);
  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         }
  113 }
  114 
  115 int
  116 vsunlock(
  117         user_addr_t addr,
  118         user_size_t len,
  119         __unused int dirtied)
  120 {
  121 #if FIXME  /* [ */
  122         pmap_t          pmap;
  123         vm_page_t       pg;
  124         vm_map_offset_t vaddr;
  125         ppnum_t         paddr;
  126 #endif  /* FIXME ] */
  127         kern_return_t kret;
  128 
  129 #if FIXME  /* [ */
  130         if (dirtied) {
  131                 pmap = get_task_pmap(current_task());
  132                 for (vaddr = vm_map_trunc_page(addr);
  133                      vaddr < vm_map_round_page(addr+len);
  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 */
  144         kret = vm_map_unwire(current_map(), vm_map_trunc_page(addr),
  145                                 vm_map_round_page(addr+len), FALSE);
  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         }
  157 }
  158 
  159 int
  160 subyte(
  161         user_addr_t addr,
  162         int byte)
  163 {
  164         char character;
  165         
  166         character = (char)byte;
  167         return (copyout((void *)&(character), addr, sizeof(char)) == 0 ? 0 : -1);
  168 }
  169 
  170 int
  171 suibyte(
  172         user_addr_t addr,
  173         int byte)
  174 {
  175         char character;
  176         
  177         character = (char)byte;
  178         return (copyout((void *)&(character), addr, sizeof(char)) == 0 ? 0 : -1);
  179 }
  180 
  181 int fubyte(user_addr_t addr)
  182 {
  183         unsigned char byte;
  184 
  185         if (copyin(addr, (void *) &byte, sizeof(char)))
  186                 return(-1);
  187         return(byte);
  188 }
  189 
  190 int fuibyte(user_addr_t addr)
  191 {
  192         unsigned char byte;
  193 
  194         if (copyin(addr, (void *) &(byte), sizeof(char)))
  195                 return(-1);
  196         return(byte);
  197 }
  198 
  199 int
  200 suword(
  201         user_addr_t addr,
  202         long word)
  203 {
  204         return (copyout((void *) &word, addr, sizeof(int)) == 0 ? 0 : -1);
  205 }
  206 
  207 long fuword(user_addr_t addr)
  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 
  218 int
  219 suiword(
  220         user_addr_t addr,
  221         long word)
  222 {
  223         return (copyout((void *) &word, addr, sizeof(int)) == 0 ? 0 : -1);
  224 }
  225 
  226 long fuiword(user_addr_t addr)
  227 {
  228         long word;
  229 
  230         if (copyin(addr, (void *) &word, sizeof(int)))
  231                 return(-1);
  232         return(word);
  233 }
  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  */
  239 int
  240 sulong(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 
  250 int64_t
  251 fulong(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 }
  263 
  264 int
  265 suulong(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 
  275 uint64_t
  276 fuulong(user_addr_t addr)
  277 {
  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 
  289 int
  290 swapon(__unused struct proc *procp, __unused struct swapon_args *uap, __unused int *retval)
  291 {
  292         return(ENOTSUP);
  293 }
  294 
  295 
  296 kern_return_t
  297 pid_for_task(
  298         struct pid_for_task_args *args)
  299 {
  300         mach_port_name_t        t = args->t;
  301         user_addr_t             pid_addr  = args->pid;  
  302         struct proc * p;
  303         task_t          t1;
  304         int     pid = -1;
  305         kern_return_t   err = KERN_SUCCESS;
  306         boolean_t funnel_state;
  307 
  308         AUDIT_MACH_SYSCALL_ENTER(AUE_PIDFORTASK);
  309         AUDIT_ARG(mach_port1, t);
  310 
  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;
  316                 goto pftout;
  317         } else {
  318                 p = get_bsdtask_info(t1);
  319                 if (p) {
  320                         pid  = proc_pid(p);
  321                         err = KERN_SUCCESS;
  322                 } else {
  323                         err = KERN_FAILURE;
  324                 }
  325         }
  326         task_deallocate(t1);
  327 pftout:
  328         AUDIT_ARG(pid, pid);
  329         (void) copyout((char *) &pid, pid_addr, sizeof(int));
  330         thread_funnel_set(kernel_flock, funnel_state);
  331         AUDIT_MACH_SYSCALL_EXIT(err);
  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.
  343  *
  344  * XXX This should be a BSD system call, not a Mach trap!!!
  345  */
  346 kern_return_t
  347 task_for_pid(
  348         struct task_for_pid_args *args)
  349 {
  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;
  354         struct proc     *p;
  355         struct proc *p1;
  356         task_t          t1;
  357         mach_port_name_t        tret;
  358         void * sright;
  359         int error = 0;
  360         boolean_t funnel_state;
  361 
  362         AUDIT_MACH_SYSCALL_ENTER(AUE_TASKFORPID);
  363         AUDIT_ARG(pid, pid);
  364         AUDIT_ARG(mach_port1, target_tport);
  365 
  366         t1 = port_name_to_task(target_tport);
  367         if (t1 == TASK_NULL) {
  368                 (void ) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t));
  369                 AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
  370                 return(KERN_FAILURE);
  371         } 
  372 
  373         funnel_state = thread_funnel_set(kernel_flock, TRUE);
  374 
  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 
  393         p = pfind(pid);
  394         AUDIT_ARG(process, p);
  395 
  396         if (
  397                 (p != (struct proc *) 0)
  398                 && (p1 != (struct proc *) 0)
  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)))
  402                 && (p->p_stat != SZOMB)
  403                 ) {
  404                         if (p->task != TASK_NULL) {
  405                                 task_reference(p->task);
  406                                 sright = (void *)convert_task_to_port(p->task);
  407                                 tret = ipc_port_copyout_send(
  408                                         sright, 
  409                                         get_task_ipcspace(current_task()));
  410                         } else
  411                                 tret  = MACH_PORT_NULL;
  412                         AUDIT_ARG(mach_port2, tret);
  413                         (void ) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
  414                 task_deallocate(t1);
  415                         error = KERN_SUCCESS;
  416                         goto tfpout;
  417         }
  418     task_deallocate(t1);
  419         tret = MACH_PORT_NULL;
  420         (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
  421         error = KERN_FAILURE;
  422 tfpout:
  423         thread_funnel_set(kernel_flock, funnel_state);
  424         AUDIT_MACH_SYSCALL_EXIT(error);
  425         return(error);
  426 }
  427 
  428 
  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  */
  443 int
  444 shared_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 
  537 done:
  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  */
  563 int
  564 shared_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 
  878 done:
  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;
  899 
  900         return error;
  901 }
  902 
  903 int
  904 load_shared_file(struct proc *p, struct load_shared_file_args *uap,
  905                                         __unused int *retval)
  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 
  920         struct vfs_context context;
  921         off_t           file_size;
  922         memory_object_control_t file_control;
  923         sf_mapping_t    *map_list;
  924         caddr_t         local_base;
  925         int             local_flags;
  926         int             caller_flags;
  927         int             i;
  928         int             default_regions = 0;
  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 
  936         context.vc_proc = p;
  937         context.vc_ucred = kauth_cred_get();
  938 
  939         ndp = &nd;
  940 
  941         AUDIT_ARG(addr, CAST_USER_ADDR_T(base_address));
  942         /* Retrieve the base address */
  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         }
  949 
  950         if(local_flags & QUERY_IS_SYSTEM_REGION) {
  951                         shared_region_mapping_t default_shared_region;
  952                         vm_get_shared_region(current_task(), &shared_region);
  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) {
  973                                 local_flags = SYSTEM_REGION_BACKED;
  974                         } else {
  975                                 local_flags = 0;
  976                         }
  977                         shared_region_mapping_dealloc(default_shared_region);
  978                         error = 0;
  979                         error = copyout(&local_flags, CAST_USER_ADDR_T(flags), sizeof (int));
  980                         goto lsf_bailout;
  981         }
  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 
  998         if ( (error = copyin(CAST_USER_ADDR_T(mappings), map_list, (map_cnt*sizeof(sf_mapping_t)))) ) {
  999                 goto lsf_bailout_free;
 1000         }
 1001 
 1002         if ( (error = copyinstr(CAST_USER_ADDR_T(filename), filename_str, 
 1003                                                         MAXPATHLEN, (size_t *)&dummy)) ) {
 1004                 goto lsf_bailout_free;
 1005         }
 1006 
 1007         /*
 1008          * Get a vnode for the target file
 1009          */
 1010         NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, UIO_SYSSPACE32,
 1011             CAST_USER_ADDR_T(filename_str), &context);
 1012 
 1013         if ((error = namei(ndp))) {
 1014                 goto lsf_bailout_free;
 1015         }
 1016         vp = ndp->ni_vp;
 1017 
 1018         nameidone(ndp);
 1019 
 1020         if (vp->v_type != VREG) {
 1021                 error = EINVAL;
 1022                 goto lsf_bailout_free_vput;
 1023         }
 1024 
 1025         UBCINFOCHECK("load_shared_file", vp);
 1026 
 1027         if ((error = vnode_size(vp, &file_size, &context)) != 0)
 1028                 goto lsf_bailout_free_vput;
 1029 
 1030         file_control = ubc_getobject(vp, UBC_HOLDOBJECT);
 1031         if (file_control == MEMORY_OBJECT_CONTROL_NULL) {
 1032                 error = EINVAL;
 1033                 goto lsf_bailout_free_vput;
 1034         }
 1035 
 1036 #ifdef notdef
 1037         if(file_size != mapped_file_size) {
 1038                 error = EINVAL;
 1039                 goto lsf_bailout_free_vput;
 1040         }
 1041 #endif
 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) {
 1049                 error = clone_system_shared_regions(FALSE,
 1050                                                     TRUE, /* chain_regions */
 1051                                                     ENV_DEFAULT_ROOT);
 1052                 if (error) {
 1053                         goto lsf_bailout_free_vput;
 1054                 }
 1055         }
 1056 
 1057         vm_get_shared_region(current_task(), &shared_region);
 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), 
 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 */
 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) {
 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),
 1113                         &(task_mapping_info.flags), &next);
 1114         }
 1115 
 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 
 1142 
 1143         if((kr = copyin_shared_file((vm_offset_t)mapped_file_addr, 
 1144                         mapped_file_size, 
 1145                         (vm_offset_t *)&local_base,
 1146                         map_cnt, map_list, file_control, 
 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:
 1156                                 error = EFAULT;
 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) {
 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);
 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 {
 1180                 if(default_regions)
 1181                         local_flags |= SYSTEM_REGION_BACKED;
 1182                 if(!(error = copyout(&local_flags, CAST_USER_ADDR_T(flags), sizeof (int)))) {
 1183                         error = copyout(&local_base, 
 1184                                 CAST_USER_ADDR_T(base_address), sizeof (caddr_t));
 1185                 }
 1186         }
 1187 
 1188 lsf_bailout_free_vput:
 1189         vnode_put(vp);
 1190 
 1191 lsf_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 
 1197 lsf_bailout:
 1198         return error;
 1199 }
 1200 
 1201 int
 1202 reset_shared_file(__unused struct proc *p, struct reset_shared_file_args *uap,
 1203                                         __unused register int *retval)
 1204 {
 1205         caddr_t                         *base_address=uap->ba;
 1206         int                     map_cnt=uap->map_cnt;
 1207         sf_mapping_t            *mappings=uap->mappings;
 1208         register int            error;
 1209 
 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;
 1215 
 1216         AUDIT_ARG(addr, CAST_DOWN(user_addr_t, base_address));
 1217         /* Retrieve the base address */
 1218         if ( (error = copyin(CAST_USER_ADDR_T(base_address), &local_base, sizeof (caddr_t))) ) {
 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 
 1235         if ( (error = 
 1236                   copyin(CAST_USER_ADDR_T(mappings), map_list, (map_cnt*sizeof(sf_mapping_t)))) ) {
 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,
 1251                                 map_list[i].size, 0,
 1252                                 SHARED_LIB_ALIAS | VM_FLAGS_FIXED,
 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 
 1266 rsf_bailout:
 1267         return error;
 1268 }
 1269 
 1270 int
 1271 new_system_shared_regions(__unused struct proc *p,
 1272                           __unused struct new_system_shared_regions_args *uap,
 1273                           register int *retval)
 1274 {
 1275         if(!(is_suser())) {
 1276                 *retval = EINVAL;
 1277                 return EINVAL;
 1278         }
 1279 
 1280         /* clear all of our existing defaults */
 1281         remove_all_shared_regions();
 1282 
 1283         *retval = 0;
 1284         return 0;
 1285 }
 1286 
 1287 
 1288 
 1289 int
 1290 clone_system_shared_regions(
 1291         int             shared_regions_active,
 1292         int             chain_regions,
 1293         int             base_vnode)
 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 
 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), 
 1312                 &(old_info.fs_base),
 1313                 &(old_info.system),
 1314                 &(old_info.flags), &next);
 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         }
 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), 
 1343                 &(new_info.fs_base),
 1344                 &(new_info.system),
 1345                 &(new_info.flags), &next);
 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");
 1349                 shared_region_mapping_dealloc(new_shared_region);
 1350                 return(EINVAL);
 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");
 1354                 shared_region_mapping_dealloc(new_shared_region);
 1355                 return(EINVAL);
 1356            }
 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            }
 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);
 1394 
 1395         /* consume the reference which wasn't accounted for in object */
 1396         /* chain attach */
 1397         if (!shared_regions_active || !chain_regions)
 1398                 shared_region_mapping_dealloc(old_shared_region);
 1399 
 1400         return(0);
 1401 
 1402 }
 1403 
 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 
 1407 struct 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 
 1417 struct 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 
 1425 struct 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 
 1434 struct global_profile_cache {
 1435         int                     max_ele;
 1436         unsigned int            age;
 1437         struct global_profile   profiles[3];
 1438 };
 1439 
 1440 /* forward declarations */
 1441 int bsd_open_page_cache_files(unsigned int user,
 1442                               struct global_profile **profile);
 1443 void bsd_close_page_cache_files(struct global_profile *profile);
 1444 int 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 
 1453 struct global_profile_cache global_user_profile_cache =
 1454         {3, 0, {{NULL, NULL, 0, 0, 0, 0},
 1455                     {NULL, NULL, 0, 0, 0, 0},
 1456                     {NULL, NULL, 0, 0, 0, 0}} };
 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 
 1467 int
 1468 bsd_open_page_cache_files(
 1469         unsigned int    user,
 1470         struct global_profile **profile)
 1471 {
 1472         const char *cache_path = "/var/vm/app_profile/";
 1473         struct proc     *p;
 1474         int             error;
 1475         vm_size_t       resid;
 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 
 1491         off_t           file_size;
 1492         struct vfs_context  context;
 1493 
 1494         kern_return_t   ret;
 1495 
 1496         struct nameidata nd_names;
 1497         struct nameidata nd_data;
 1498         int             i;
 1499 
 1500 
 1501         p = current_proc();
 1502 
 1503         context.vc_proc = p;
 1504         context.vc_ucred = kauth_cred_get();
 1505 
 1506 restart:
 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;
 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                         }
 1555                         global_user_profile_cache.age+=1;
 1556                         return 0;
 1557                 }
 1558         }
 1559 
 1560         lru = global_user_profile_cache.age;
 1561         *profile = NULL;
 1562         for(i = 0; i<global_user_profile_cache.max_ele; i++) {
 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 */
 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;
 1571                         break;
 1572                 }
 1573                 /* Otherwise grab the oldest entry */
 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 
 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          */
 1608         if ((*profile)->busy) {
 1609                 /*
 1610                 * drop funnel and wait 
 1611                 */
 1612                 (void)tsleep((void *)
 1613                         *profile, 
 1614                         PRIBIO, "app_profile", 0);
 1615                 goto restart;
 1616         }
 1617         (*profile)->busy = 1;
 1618         (*profile)->user = user;
 1619 
 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) {
 1639                 kmem_free(kernel_map, 
 1640                                 (*profile)->buf_ptr, 4 * PAGE_SIZE);
 1641                 if ((*profile)->names_vp) {
 1642                         vnode_rele((*profile)->names_vp);
 1643                         (*profile)->names_vp = NULL;
 1644                 }
 1645                 vnode_rele(data_vp);
 1646         }
 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 
 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, 
 1693                         UIO_SYSSPACE32, CAST_USER_ADDR_T(profile_names_string), &context);
 1694         NDINIT(&nd_data, LOOKUP, FOLLOW | LOCKLEAF, 
 1695                         UIO_SYSSPACE32, CAST_USER_ADDR_T(profile_data_string), &context);
 1696 
 1697         if ( (error = vn_open(&nd_data, FREAD | FWRITE, 0)) ) {
 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         }
 1711         data_vp = nd_data.ni_vp;
 1712 
 1713         if ( (error = vn_open(&nd_names, FREAD | FWRITE, 0)) ) {
 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);
 1720 
 1721                 vnode_rele(data_vp);
 1722                 vnode_put(data_vp);
 1723 
 1724                 (*profile)->data_vp = NULL;
 1725                 (*profile)->busy = 0;
 1726                 wakeup(*profile);
 1727                 return error;
 1728         }
 1729         names_vp = nd_names.ni_vp;
 1730 
 1731         if ((error = vnode_size(names_vp, &file_size, &context)) != 0) {
 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);
 1737 
 1738                 vnode_rele(names_vp);
 1739                 vnode_put(names_vp);
 1740                 vnode_rele(data_vp);
 1741                 vnode_put(data_vp);
 1742 
 1743                 (*profile)->data_vp = NULL;
 1744                 (*profile)->busy = 0;
 1745                 wakeup(*profile);
 1746                 return error;
 1747         }
 1748 
 1749         size = file_size;
 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,
 1758                         UIO_SYSSPACE32, IO_NODELOCKED, kauth_cred_get(), &resid, p);
 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);
 1767 
 1768                         vnode_rele(names_vp);
 1769                         vnode_put(names_vp);
 1770                         vnode_rele(data_vp);
 1771                         vnode_put(data_vp);
 1772 
 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         }
 1782         kmem_free(kernel_map, (vm_offset_t)profile_data_string, PATH_MAX);
 1783 
 1784         (*profile)->names_vp = names_vp;
 1785         (*profile)->data_vp = data_vp;
 1786         (*profile)->buf_ptr = names_buf;
 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          */
 1792         return 0;
 1793 
 1794 }
 1795 
 1796 void
 1797 bsd_close_page_cache_files(
 1798         struct global_profile *profile)
 1799 {
 1800         vnode_put(profile->data_vp);
 1801         vnode_put(profile->names_vp);
 1802 
 1803         profile->busy = 0;
 1804         wakeup(profile);
 1805 }
 1806 
 1807 int
 1808 bsd_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,
 1815         vm_offset_t     *bufsize)
 1816 {
 1817 
 1818         boolean_t       funnel_state;
 1819 
 1820         struct proc     *p;
 1821         int             error;
 1822         unsigned int    resid;
 1823 
 1824         off_t           profile;
 1825         unsigned int    profile_size;
 1826 
 1827         vm_offset_t     names_buf;
 1828         struct vnode_attr       va;
 1829         struct vfs_context  context;
 1830 
 1831         kern_return_t   ret;
 1832 
 1833         struct  vnode   *names_vp;
 1834         struct  vnode   *data_vp;
 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 
 1859         context.vc_proc = p;
 1860         context.vc_ucred = kauth_cred_get();
 1861 
 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))) {
 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 
 1873         *fid = (u_long)va.va_fileid;
 1874         *mod = va.va_modify_time.tv_sec;
 1875                 
 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) {
 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) {
 1886                         *buffer = 0;
 1887                         *bufsize = 0;
 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) {
 1894                         bsd_close_page_cache_files(uid_files);
 1895                         thread_funnel_set(kernel_flock, funnel_state);
 1896                         return ENOMEM;
 1897                 }
 1898                 *bufsize = profile_size;
 1899                 while(profile_size) {
 1900                         error = vn_rdwr(UIO_READ, data_vp, 
 1901                                 (caddr_t) *buffer, profile_size, 
 1902                                 profile, UIO_SYSSPACE32, IO_NODELOCKED, 
 1903                                 kauth_cred_get(), &resid, p);
 1904                         if((error) || (profile_size == resid)) {
 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                 }
 1913                 bsd_close_page_cache_files(uid_files);
 1914                 thread_funnel_set(kernel_flock, funnel_state);
 1915                 return 0;
 1916         } else {
 1917                 bsd_close_page_cache_files(uid_files);
 1918                 thread_funnel_set(kernel_flock, funnel_state);
 1919                 return EINVAL;
 1920         }
 1921         
 1922 }
 1923 
 1924 int
 1925 bsd_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;
 1944         unsigned int            resid;
 1945         vm_offset_t             local_buf = 0;
 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;
 1988                                         if(local_buf != 0) {
 1989                                                 kmem_free(kernel_map, local_buf, 4 * PAGE_SIZE);
 1990                                         }
 1991                                         return 0;
 1992                                 }
 1993                         }
 1994                 }
 1995                 if(extended_list == 0)
 1996                         break;
 1997                 if(local_buf == 0) {
 1998                         ret = kmem_alloc(kernel_map, &local_buf, 4 * PAGE_SIZE);
 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, 
 2016                                 CAST_DOWN(caddr_t, (local_buf + resid_off)),
 2017                                 size, file_off + resid_off, UIO_SYSSPACE32, 
 2018                                 IO_NODELOCKED, kauth_cred_get(), &resid, p);
 2019                         if((error) || (size == resid)) {
 2020                                 if(local_buf != 0) {
 2021                                         kmem_free(kernel_map, local_buf, 4 * PAGE_SIZE);
 2022                                 }
 2023                                 return EINVAL;
 2024                         }
 2025                         resid_off += size-resid;
 2026                         size = resid;
 2027                 }
 2028         }
 2029         if(local_buf != 0) {
 2030                 kmem_free(kernel_map, local_buf, 4 * PAGE_SIZE);
 2031         }
 2032         return 0;
 2033 }
 2034 
 2035 int
 2036 bsd_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;
 2045         int                             resid;
 2046         off_t                   resid_off;
 2047         int                             error;
 2048         boolean_t               funnel_state;
 2049         off_t                   file_size;
 2050         struct vfs_context      context;
 2051         off_t                   profile;
 2052         unsigned int    profile_size;
 2053 
 2054         vm_offset_t     names_buf;
 2055         struct  vnode   *names_vp;
 2056         struct  vnode   *data_vp;
 2057         struct  profile_names_header *profile_header;
 2058         off_t                   name_offset;
 2059         struct global_profile *uid_files;
 2060 
 2061 
 2062         funnel_state = thread_funnel_set(kernel_flock, TRUE);
 2063 
 2064 
 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 
 2077         /* Stat data file for size */
 2078 
 2079         context.vc_proc = p;
 2080         context.vc_ucred = kauth_cred_get();
 2081 
 2082         if ((error = vnode_size(data_vp, &file_size, &context)) != 0) {
 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);
 2115                                 name->addr =  file_size;
 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 */
 2124                                 name.addr = file_size;
 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, 
 2138                                                 UIO_SYSSPACE32, IO_NODELOCKED, 
 2139                                                 kauth_cred_get(), &resid, p);
 2140                                         if(error) {
 2141                                                 printf("bsd_write_page_cache_file: Can't write name_element %x\n", user);
 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, 
 2172                                         UIO_SYSSPACE32, IO_NODELOCKED, 
 2173                                         kauth_cred_get(), &resid, p);
 2174                                 if(error) {
 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 */
 2187                         resid_off = file_size;
 2188                         while(size) {
 2189                                 error = vn_rdwr(UIO_WRITE, data_vp, 
 2190                                         (caddr_t)buffer, size, resid_off, 
 2191                                         UIO_SYSSPACE32, IO_NODELOCKED, 
 2192                                         kauth_cred_get(), &resid, p);
 2193                                 if(error) {
 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                         }
 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 */
 2210                 bsd_close_page_cache_files(uid_files);
 2211                 thread_funnel_set(kernel_flock, funnel_state);
 2212                 return 0;
 2213         } else {                
 2214                 bsd_close_page_cache_files(uid_files);
 2215                 thread_funnel_set(kernel_flock, funnel_state);
 2216                 return EINVAL;
 2217         }
 2218         
 2219 }
 2220 
 2221 int
 2222 prepare_profile_database(int    user)
 2223 {
 2224         const char *cache_path = "/var/vm/app_profile/";
 2225         struct proc     *p;
 2226         int             error;
 2227         int             resid;
 2228         off_t           resid_off;
 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 
 2242         struct vnode_attr va;
 2243         struct vfs_context context;
 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 
 2251         p = current_proc();
 2252 
 2253         context.vc_proc = p;
 2254         context.vc_ucred = kauth_cred_get();
 2255 
 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, 
 2289                         UIO_SYSSPACE32, CAST_USER_ADDR_T(profile_names_string), &context);
 2290         NDINIT(&nd_data, LOOKUP, FOLLOW,
 2291                         UIO_SYSSPACE32, CAST_USER_ADDR_T(profile_data_string), &context);
 2292 
 2293         if ( (error = vn_open(&nd_data, 
 2294                                                         O_CREAT | O_EXCL | FWRITE, S_IRUSR|S_IWUSR)) ) {
 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);
 2299                         
 2300                         return 0;
 2301         }
 2302         data_vp = nd_data.ni_vp;
 2303 
 2304         if ( (error = vn_open(&nd_names, 
 2305                                                         O_CREAT | O_EXCL | FWRITE, S_IRUSR|S_IWUSR)) ) {
 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);
 2312 
 2313                         vnode_rele(data_vp);
 2314                         vnode_put(data_vp);
 2315 
 2316                         return error;
 2317         }
 2318         names_vp = nd_names.ni_vp;
 2319 
 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,
 2340                                 UIO_SYSSPACE32, IO_NODELOCKED, 
 2341                                 kauth_cred_get(), &resid, p);
 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);
 2349 
 2350                         vnode_rele(names_vp);
 2351                         vnode_put(names_vp);
 2352                         vnode_rele(data_vp);
 2353                         vnode_put(data_vp);
 2354 
 2355                         return error;
 2356                 }
 2357                 buf_ptr += size-resid;
 2358                 resid_off += size-resid;
 2359                 size = resid;
 2360         }
 2361         VATTR_INIT(&va);
 2362         VATTR_SET(&va, va_uid, user);
 2363 
 2364         error = vnode_setattr(names_vp, &va, &context);
 2365         if(error) {
 2366                 printf("prepare_profile_database: "
 2367                         "Can't set user %s\n", profile_names_string);
 2368         }
 2369         vnode_rele(names_vp);
 2370         vnode_put(names_vp);
 2371         
 2372         VATTR_INIT(&va);
 2373         VATTR_SET(&va, va_uid, user);
 2374         error = vnode_setattr(data_vp, &va, &context);
 2375         if(error) {
 2376                 printf("prepare_profile_database: "
 2377                         "Can't set user %s\n", profile_data_string);
 2378         }
 2379         vnode_rele(data_vp);
 2380         vnode_put(data_vp);
 2381 
 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 }

Cache object: 0d2d15c77e7c4eacf7db954498078e90


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.