- kmem_free(kernel_map, (vm_offset_t)map_list,
- (vm_size_t)(map_cnt*sizeof(sf_mapping_t)));
- goto rsf_bailout;
- }
- for (i = 0; i<map_cnt; i++) {
- if((map_list[i].mapping_offset
- & GLOBAL_SHARED_SEGMENT_MASK) == 0x10000000) {
- map_address = (vm_offset_t)
- (local_base + map_list[i].mapping_offset);
- vm_deallocate(current_map(),
- map_address,
- map_list[i].size);
- vm_map(current_map(), &map_address,
- map_list[i].size, 0,
- SHARED_LIB_ALIAS | VM_FLAGS_FIXED,
- shared_data_region_handle,
- ((unsigned int)local_base
- & SHARED_DATA_REGION_MASK) +
- (map_list[i].mapping_offset
- & SHARED_DATA_REGION_MASK),
- TRUE, VM_PROT_READ,
- VM_PROT_READ, VM_INHERIT_SHARE);
- }
- }
-
- kmem_free(kernel_map, (vm_offset_t)map_list,
- (vm_size_t)(map_cnt*sizeof(sf_mapping_t)));
-
-rsf_bailout:
- return error;
-}
-
-int
-new_system_shared_regions(__unused struct proc *p,
- __unused struct new_system_shared_regions_args *uap,
- register int *retval)
-{
- if(!(is_suser())) {
- *retval = EINVAL;
- return EINVAL;
- }
-
- /* clear all of our existing defaults */
- remove_all_shared_regions();
-
- *retval = 0;
- return 0;
-}
-
-
-
-int
-clone_system_shared_regions(
- int shared_regions_active,
- int chain_regions,
- int base_vnode)
-{
- shared_region_mapping_t new_shared_region;
- shared_region_mapping_t next;
- shared_region_mapping_t old_shared_region;
- struct shared_region_task_mappings old_info;
- struct shared_region_task_mappings new_info;
-
- vm_get_shared_region(current_task(), &old_shared_region);
- old_info.self = (vm_offset_t)old_shared_region;
- shared_region_mapping_info(old_shared_region,
- &(old_info.text_region),
- &(old_info.text_size),
- &(old_info.data_region),
- &(old_info.data_size),
- &(old_info.region_mappings),
- &(old_info.client_base),
- &(old_info.alternate_base),
- &(old_info.alternate_next),
- &(old_info.fs_base),
- &(old_info.system),
- &(old_info.flags), &next);
- if ((shared_regions_active) ||
- (base_vnode == ENV_DEFAULT_ROOT)) {
- if (shared_file_create_system_region(&new_shared_region))
- return (ENOMEM);
- } else {
- new_shared_region =
- lookup_default_shared_region(
- base_vnode, old_info.system);
- if(new_shared_region == NULL) {
- shared_file_boot_time_init(
- base_vnode, old_info.system);
- vm_get_shared_region(current_task(), &new_shared_region);
- } else {
- vm_set_shared_region(current_task(), new_shared_region);
- }
- if(old_shared_region)
- shared_region_mapping_dealloc(old_shared_region);
- }
- new_info.self = (vm_offset_t)new_shared_region;
- shared_region_mapping_info(new_shared_region,
- &(new_info.text_region),
- &(new_info.text_size),
- &(new_info.data_region),
- &(new_info.data_size),
- &(new_info.region_mappings),
- &(new_info.client_base),
- &(new_info.alternate_base),
- &(new_info.alternate_next),
- &(new_info.fs_base),
- &(new_info.system),
- &(new_info.flags), &next);
- if(shared_regions_active) {
- if(vm_region_clone(old_info.text_region, new_info.text_region)) {
- panic("clone_system_shared_regions: shared region mis-alignment 1");
- shared_region_mapping_dealloc(new_shared_region);
- return(EINVAL);
- }
- if (vm_region_clone(old_info.data_region, new_info.data_region)) {
- panic("clone_system_shared_regions: shared region mis-alignment 2");
- shared_region_mapping_dealloc(new_shared_region);
- return(EINVAL);
- }
- if (chain_regions) {
- /*
- * We want a "shadowed" clone, a private superset of the old
- * shared region. The info about the old mappings is still
- * valid for us.
- */
- shared_region_object_chain_attach(
- new_shared_region, old_shared_region);
- } else {
- /*
- * We want a completely detached clone with no link to
- * the old shared region. We'll be removing some mappings
- * in our private, cloned, shared region, so the old mappings
- * will become irrelevant to us. Since we have a private
- * "shared region" now, it isn't going to be shared with
- * anyone else and we won't need to maintain mappings info.
- */
- shared_region_object_chain_detached(new_shared_region);
- }
- }
- if (vm_map_region_replace(current_map(), old_info.text_region,
- new_info.text_region, old_info.client_base,
- old_info.client_base+old_info.text_size)) {
- panic("clone_system_shared_regions: shared region mis-alignment 3");
- shared_region_mapping_dealloc(new_shared_region);
- return(EINVAL);
- }
- if(vm_map_region_replace(current_map(), old_info.data_region,
- new_info.data_region,
- old_info.client_base + old_info.text_size,
- old_info.client_base
- + old_info.text_size + old_info.data_size)) {
- panic("clone_system_shared_regions: shared region mis-alignment 4");
- shared_region_mapping_dealloc(new_shared_region);
- return(EINVAL);
- }
- vm_set_shared_region(current_task(), new_shared_region);
-
- /* consume the reference which wasn't accounted for in object */
- /* chain attach */
- if (!shared_regions_active || !chain_regions)
- shared_region_mapping_dealloc(old_shared_region);
-
- return(0);
-
-}
-
-/* header for the profile name file. The profiled app info is held */
-/* in the data file and pointed to by elements in the name file */
-
-struct profile_names_header {
- unsigned int number_of_profiles;
- unsigned int user_id;
- unsigned int version;
- off_t element_array;
- unsigned int spare1;
- unsigned int spare2;
- unsigned int spare3;
-};
-
-struct profile_element {
- off_t addr;
- vm_size_t size;
- unsigned int mod_date;
- unsigned int inode;
- char name[12];
-};
-
-struct global_profile {
- struct vnode *names_vp;
- struct vnode *data_vp;
- vm_offset_t buf_ptr;
- unsigned int user;
- unsigned int age;
- unsigned int busy;
-};
-
-struct global_profile_cache {
- int max_ele;
- unsigned int age;
- struct global_profile profiles[3];
-};
-
-/* forward declarations */
-int bsd_open_page_cache_files(unsigned int user,
- struct global_profile **profile);
-void bsd_close_page_cache_files(struct global_profile *profile);
-int bsd_search_page_cache_data_base(
- struct vnode *vp,
- struct profile_names_header *database,
- char *app_name,
- unsigned int mod_date,
- unsigned int inode,
- off_t *profile,
- unsigned int *profile_size);
-
-struct global_profile_cache global_user_profile_cache =
- {3, 0, {{NULL, NULL, 0, 0, 0, 0},
- {NULL, NULL, 0, 0, 0, 0},
- {NULL, NULL, 0, 0, 0, 0}} };
-
-/* BSD_OPEN_PAGE_CACHE_FILES: */
-/* Caller provides a user id. This id was used in */
-/* prepare_profile_database to create two unique absolute */
-/* file paths to the associated profile files. These files */
-/* are either opened or bsd_open_page_cache_files returns an */
-/* error. The header of the names file is then consulted. */
-/* The header and the vnodes for the names and data files are */
-/* returned. */
-
-int
-bsd_open_page_cache_files(
- unsigned int user,
- struct global_profile **profile)
-{
- const char *cache_path = "/var/vm/app_profile/";
- struct proc *p;
- int error;
- vm_size_t resid;
- off_t resid_off;
- unsigned int lru;
- vm_size_t size;
-
- struct vnode *names_vp;
- struct vnode *data_vp;
- vm_offset_t names_buf;
- vm_offset_t buf_ptr;
-
- int profile_names_length;
- int profile_data_length;
- char *profile_data_string;
- char *profile_names_string;
- char *substring;
-
- off_t file_size;
- struct vfs_context context;
-
- kern_return_t ret;
-
- struct nameidata nd_names;
- struct nameidata nd_data;
- int i;
-
-
- p = current_proc();
-
- context.vc_proc = p;
- context.vc_ucred = kauth_cred_get();
-
-restart:
- for(i = 0; i<global_user_profile_cache.max_ele; i++) {
- if((global_user_profile_cache.profiles[i].user == user)
- && (global_user_profile_cache.profiles[i].data_vp
- != NULL)) {
- *profile = &global_user_profile_cache.profiles[i];
- /* already in cache, we're done */
- if ((*profile)->busy) {
- /*
- * drop funnel and wait
- */
- (void)tsleep((void *)
- *profile,
- PRIBIO, "app_profile", 0);
- goto restart;
- }
- (*profile)->busy = 1;
- (*profile)->age = global_user_profile_cache.age;
-
- /*
- * entries in cache are held with a valid
- * usecount... take an iocount which will
- * be dropped in "bsd_close_page_cache_files"
- * which is called after the read or writes to
- * these files are done
- */
- if ( (vnode_getwithref((*profile)->data_vp)) ) {
-
- vnode_rele((*profile)->data_vp);
- vnode_rele((*profile)->names_vp);
-
- (*profile)->data_vp = NULL;
- (*profile)->busy = 0;
- wakeup(*profile);
-
- goto restart;
- }
- if ( (vnode_getwithref((*profile)->names_vp)) ) {
-
- vnode_put((*profile)->data_vp);
- vnode_rele((*profile)->data_vp);
- vnode_rele((*profile)->names_vp);
-
- (*profile)->data_vp = NULL;
- (*profile)->busy = 0;
- wakeup(*profile);
-
- goto restart;
- }
- global_user_profile_cache.age+=1;
- return 0;
- }
- }
-
- lru = global_user_profile_cache.age;
- *profile = NULL;
- for(i = 0; i<global_user_profile_cache.max_ele; i++) {
- /* Skip entry if it is in the process of being reused */
- if(global_user_profile_cache.profiles[i].data_vp ==
- (struct vnode *)0xFFFFFFFF)
- continue;
- /* Otherwise grab the first empty entry */
- if(global_user_profile_cache.profiles[i].data_vp == NULL) {
- *profile = &global_user_profile_cache.profiles[i];
- (*profile)->age = global_user_profile_cache.age;
- break;
- }
- /* Otherwise grab the oldest entry */
- if(global_user_profile_cache.profiles[i].age < lru) {
- lru = global_user_profile_cache.profiles[i].age;
- *profile = &global_user_profile_cache.profiles[i];
- }
- }
-
- /* Did we set it? */
- if (*profile == NULL) {
- /*
- * No entries are available; this can only happen if all
- * of them are currently in the process of being reused;
- * if this happens, we sleep on the address of the first
- * element, and restart. This is less than ideal, but we
- * know it will work because we know that there will be a
- * wakeup on any entry currently in the process of being
- * reused.
- *
- * XXX Reccomend a two handed clock and more than 3 total
- * XXX cache entries at some point in the future.
- */
- /*
- * drop funnel and wait
- */
- (void)tsleep((void *)
- &global_user_profile_cache.profiles[0],
- PRIBIO, "app_profile", 0);
- goto restart;
- }
-
- /*
- * If it's currently busy, we've picked the one at the end of the
- * LRU list, but it's currently being actively used. We sleep on
- * its address and restart.
- */
- if ((*profile)->busy) {
- /*
- * drop funnel and wait
- */
- (void)tsleep((void *)
- *profile,
- PRIBIO, "app_profile", 0);
- goto restart;
- }
- (*profile)->busy = 1;
- (*profile)->user = user;
-
- /*
- * put dummy value in for now to get competing request to wait
- * above until we are finished
- *
- * Save the data_vp before setting it, so we can set it before
- * we kmem_free() or vrele(). If we don't do this, then we
- * have a potential funnel race condition we have to deal with.
- */
- data_vp = (*profile)->data_vp;
- (*profile)->data_vp = (struct vnode *)0xFFFFFFFF;
-
- /*
- * Age the cache here in all cases; this guarantees that we won't
- * be reusing only one entry over and over, once the system reaches
- * steady-state.
- */
- global_user_profile_cache.age+=1;
-
- if(data_vp != NULL) {
- kmem_free(kernel_map,
- (*profile)->buf_ptr, 4 * PAGE_SIZE);
- if ((*profile)->names_vp) {
- vnode_rele((*profile)->names_vp);
- (*profile)->names_vp = NULL;
- }
- vnode_rele(data_vp);
- }
-
- /* Try to open the appropriate users profile files */
- /* If neither file is present, try to create them */
- /* If one file is present and the other not, fail. */
- /* If the files do exist, check them for the app_file */
- /* requested and read it in if present */
-
- ret = kmem_alloc(kernel_map,
- (vm_offset_t *)&profile_data_string, PATH_MAX);
-
- if(ret) {
- (*profile)->data_vp = NULL;
- (*profile)->busy = 0;
- wakeup(*profile);
- return ENOMEM;
- }
-
- /* Split the buffer in half since we know the size of */
- /* our file path and our allocation is adequate for */
- /* both file path names */
- profile_names_string = profile_data_string + (PATH_MAX/2);
-
-
- strcpy(profile_data_string, cache_path);
- strcpy(profile_names_string, cache_path);
- profile_names_length = profile_data_length
- = strlen(profile_data_string);
- substring = profile_data_string + profile_data_length;
- sprintf(substring, "%x_data", user);
- substring = profile_names_string + profile_names_length;
- sprintf(substring, "%x_names", user);
-
- /* We now have the absolute file names */
-
- ret = kmem_alloc(kernel_map,
- (vm_offset_t *)&names_buf, 4 * PAGE_SIZE);
- if(ret) {
- kmem_free(kernel_map,
- (vm_offset_t)profile_data_string, PATH_MAX);
- (*profile)->data_vp = NULL;
- (*profile)->busy = 0;
- wakeup(*profile);
- return ENOMEM;
- }
-
- NDINIT(&nd_names, LOOKUP, FOLLOW | LOCKLEAF,
- UIO_SYSSPACE32, CAST_USER_ADDR_T(profile_names_string), &context);
- NDINIT(&nd_data, LOOKUP, FOLLOW | LOCKLEAF,
- UIO_SYSSPACE32, CAST_USER_ADDR_T(profile_data_string), &context);
-
- if ( (error = vn_open(&nd_data, FREAD | FWRITE, 0)) ) {
-#ifdef notdef
- printf("bsd_open_page_cache_files: CacheData file not found %s\n",
- profile_data_string);
-#endif
- kmem_free(kernel_map,
- (vm_offset_t)names_buf, 4 * PAGE_SIZE);
- kmem_free(kernel_map,
- (vm_offset_t)profile_data_string, PATH_MAX);
- (*profile)->data_vp = NULL;
- (*profile)->busy = 0;
- wakeup(*profile);
- return error;
- }
- data_vp = nd_data.ni_vp;
-
- if ( (error = vn_open(&nd_names, FREAD | FWRITE, 0)) ) {
- printf("bsd_open_page_cache_files: NamesData file not found %s\n",
- profile_data_string);
- kmem_free(kernel_map,
- (vm_offset_t)names_buf, 4 * PAGE_SIZE);
- kmem_free(kernel_map,
- (vm_offset_t)profile_data_string, PATH_MAX);
-
- vnode_rele(data_vp);
- vnode_put(data_vp);
-
- (*profile)->data_vp = NULL;
- (*profile)->busy = 0;
- wakeup(*profile);
- return error;
- }
- names_vp = nd_names.ni_vp;
-
- if ((error = vnode_size(names_vp, &file_size, &context)) != 0) {
- printf("bsd_open_page_cache_files: Can't stat name file %s\n", profile_names_string);
- kmem_free(kernel_map,
- (vm_offset_t)profile_data_string, PATH_MAX);
- kmem_free(kernel_map,
- (vm_offset_t)names_buf, 4 * PAGE_SIZE);
-
- vnode_rele(names_vp);
- vnode_put(names_vp);
- vnode_rele(data_vp);
- vnode_put(data_vp);
-
- (*profile)->data_vp = NULL;
- (*profile)->busy = 0;
- wakeup(*profile);
- return error;
- }
-
- size = file_size;
- if(size > 4 * PAGE_SIZE)
- size = 4 * PAGE_SIZE;
- buf_ptr = names_buf;
- resid_off = 0;
-
- while(size) {
- error = vn_rdwr(UIO_READ, names_vp, (caddr_t)buf_ptr,
- size, resid_off,
- UIO_SYSSPACE32, IO_NODELOCKED, kauth_cred_get(), &resid, p);
- if((error) || (size == resid)) {
- if(!error) {
- error = EINVAL;
- }
- kmem_free(kernel_map,
- (vm_offset_t)profile_data_string, PATH_MAX);
- kmem_free(kernel_map,
- (vm_offset_t)names_buf, 4 * PAGE_SIZE);
-
- vnode_rele(names_vp);
- vnode_put(names_vp);
- vnode_rele(data_vp);
- vnode_put(data_vp);
-
- (*profile)->data_vp = NULL;
- (*profile)->busy = 0;
- wakeup(*profile);
- return error;
- }
- buf_ptr += size-resid;
- resid_off += size-resid;
- size = resid;
- }
- kmem_free(kernel_map, (vm_offset_t)profile_data_string, PATH_MAX);
-
- (*profile)->names_vp = names_vp;
- (*profile)->data_vp = data_vp;
- (*profile)->buf_ptr = names_buf;
-
- /*
- * at this point, the both the names_vp and the data_vp have
- * both a valid usecount and an iocount held
- */
- return 0;
-
-}
-
-void
-bsd_close_page_cache_files(
- struct global_profile *profile)
-{
- vnode_put(profile->data_vp);
- vnode_put(profile->names_vp);
-
- profile->busy = 0;
- wakeup(profile);
-}
-
-int
-bsd_read_page_cache_file(
- unsigned int user,
- int *fid,
- int *mod,
- char *app_name,
- struct vnode *app_vp,
- vm_offset_t *buffer,
- vm_offset_t *bufsize)
-{
-
- boolean_t funnel_state;
-
- struct proc *p;
- int error;
- unsigned int resid;
-
- off_t profile;
- unsigned int profile_size;
-
- vm_offset_t names_buf;
- struct vnode_attr va;
- struct vfs_context context;
-
- kern_return_t ret;
-
- struct vnode *names_vp;
- struct vnode *data_vp;
-
- struct global_profile *uid_files;
-
- funnel_state = thread_funnel_set(kernel_flock, TRUE);
-
- /* Try to open the appropriate users profile files */
- /* If neither file is present, try to create them */
- /* If one file is present and the other not, fail. */
- /* If the files do exist, check them for the app_file */
- /* requested and read it in if present */
-
-
- error = bsd_open_page_cache_files(user, &uid_files);
- if(error) {
- thread_funnel_set(kernel_flock, funnel_state);
- return EINVAL;
- }
-
- p = current_proc();
-
- names_vp = uid_files->names_vp;
- data_vp = uid_files->data_vp;
- names_buf = uid_files->buf_ptr;
-
- context.vc_proc = p;
- context.vc_ucred = kauth_cred_get();
-
- VATTR_INIT(&va);
- VATTR_WANTED(&va, va_fileid);
- VATTR_WANTED(&va, va_modify_time);
-
- if ((error = vnode_getattr(app_vp, &va, &context))) {
- printf("bsd_read_cache_file: Can't stat app file %s\n", app_name);
- bsd_close_page_cache_files(uid_files);
- thread_funnel_set(kernel_flock, funnel_state);
- return error;
- }
-
- *fid = (u_long)va.va_fileid;
- *mod = va.va_modify_time.tv_sec;
-
- if (bsd_search_page_cache_data_base(
- names_vp,
- (struct profile_names_header *)names_buf,
- app_name,
- (unsigned int) va.va_modify_time.tv_sec,
- (u_long)va.va_fileid, &profile, &profile_size) == 0) {
- /* profile is an offset in the profile data base */
- /* It is zero if no profile data was found */
-
- if(profile_size == 0) {
- *buffer = 0;
- *bufsize = 0;
- bsd_close_page_cache_files(uid_files);
- thread_funnel_set(kernel_flock, funnel_state);
- return 0;
- }
- ret = (vm_offset_t)(kmem_alloc(kernel_map, buffer, profile_size));
- if(ret) {
- bsd_close_page_cache_files(uid_files);
- thread_funnel_set(kernel_flock, funnel_state);
- return ENOMEM;
- }
- *bufsize = profile_size;
- while(profile_size) {
- error = vn_rdwr(UIO_READ, data_vp,
- (caddr_t) *buffer, profile_size,
- profile, UIO_SYSSPACE32, IO_NODELOCKED,
- kauth_cred_get(), &resid, p);
- if((error) || (profile_size == resid)) {
- bsd_close_page_cache_files(uid_files);
- kmem_free(kernel_map, (vm_offset_t)*buffer, profile_size);
- thread_funnel_set(kernel_flock, funnel_state);
- return EINVAL;
- }
- profile += profile_size - resid;
- profile_size = resid;
- }
- bsd_close_page_cache_files(uid_files);
- thread_funnel_set(kernel_flock, funnel_state);
- return 0;
- } else {
- bsd_close_page_cache_files(uid_files);
- thread_funnel_set(kernel_flock, funnel_state);
- return EINVAL;
- }
-
-}
-
-int
-bsd_search_page_cache_data_base(
- struct vnode *vp,
- struct profile_names_header *database,
- char *app_name,
- unsigned int mod_date,
- unsigned int inode,
- off_t *profile,
- unsigned int *profile_size)
-{
-
- struct proc *p;
-
- unsigned int i;
- struct profile_element *element;
- unsigned int ele_total;
- unsigned int extended_list = 0;
- off_t file_off = 0;
- unsigned int size;
- off_t resid_off;
- unsigned int resid;
- vm_offset_t local_buf = 0;
-
- int error;
- kern_return_t ret;
-
- p = current_proc();
-
- if(((vm_offset_t)database->element_array) !=
- sizeof(struct profile_names_header)) {
- return EINVAL;
- }
- element = (struct profile_element *)(
- (vm_offset_t)database->element_array +
- (vm_offset_t)database);
-
- ele_total = database->number_of_profiles;
-
- *profile = 0;
- *profile_size = 0;
- while(ele_total) {
- /* note: code assumes header + n*ele comes out on a page boundary */
- if(((local_buf == 0) && (sizeof(struct profile_names_header) +
- (ele_total * sizeof(struct profile_element)))
- > (PAGE_SIZE * 4)) ||
- ((local_buf != 0) &&
- (ele_total * sizeof(struct profile_element))
- > (PAGE_SIZE * 4))) {
- extended_list = ele_total;
- if(element == (struct profile_element *)
- ((vm_offset_t)database->element_array +
- (vm_offset_t)database)) {
- ele_total = ((PAGE_SIZE * 4)/sizeof(struct profile_element)) - 1;
- } else {
- ele_total = (PAGE_SIZE * 4)/sizeof(struct profile_element);
- }
- extended_list -= ele_total;
- }
- for (i=0; i<ele_total; i++) {
- if((mod_date == element[i].mod_date)
- && (inode == element[i].inode)) {
- if(strncmp(element[i].name, app_name, 12) == 0) {
- *profile = element[i].addr;
- *profile_size = element[i].size;
- if(local_buf != 0) {
- kmem_free(kernel_map, local_buf, 4 * PAGE_SIZE);
- }
- return 0;
- }
- }
- }
- if(extended_list == 0)
- break;
- if(local_buf == 0) {
- ret = kmem_alloc(kernel_map, &local_buf, 4 * PAGE_SIZE);
- if(ret != KERN_SUCCESS) {
- return ENOMEM;
- }
- }
- element = (struct profile_element *)local_buf;
- ele_total = extended_list;
- extended_list = 0;
- file_off += 4 * PAGE_SIZE;
- if((ele_total * sizeof(struct profile_element)) >
- (PAGE_SIZE * 4)) {
- size = PAGE_SIZE * 4;
- } else {
- size = ele_total * sizeof(struct profile_element);
- }
- resid_off = 0;
- while(size) {
- error = vn_rdwr(UIO_READ, vp,
- CAST_DOWN(caddr_t, (local_buf + resid_off)),
- size, file_off + resid_off, UIO_SYSSPACE32,
- IO_NODELOCKED, kauth_cred_get(), &resid, p);
- if((error) || (size == resid)) {
- if(local_buf != 0) {
- kmem_free(kernel_map, local_buf, 4 * PAGE_SIZE);
- }
- return EINVAL;
- }
- resid_off += size-resid;
- size = resid;
- }
- }
- if(local_buf != 0) {
- kmem_free(kernel_map, local_buf, 4 * PAGE_SIZE);
- }
- return 0;
-}
-
-int
-bsd_write_page_cache_file(
- unsigned int user,
- char *file_name,
- caddr_t buffer,
- vm_size_t size,
- int mod,
- int fid)
-{
- struct proc *p;
- int resid;
- off_t resid_off;
- int error;
- boolean_t funnel_state;
- off_t file_size;
- struct vfs_context context;
- off_t profile;
- unsigned int profile_size;
-
- vm_offset_t names_buf;
- struct vnode *names_vp;
- struct vnode *data_vp;
- struct profile_names_header *profile_header;
- off_t name_offset;
- struct global_profile *uid_files;
-
-
- funnel_state = thread_funnel_set(kernel_flock, TRUE);
-
-
- error = bsd_open_page_cache_files(user, &uid_files);
- if(error) {
- thread_funnel_set(kernel_flock, funnel_state);
- return EINVAL;
- }
-
- p = current_proc();
-
- names_vp = uid_files->names_vp;
- data_vp = uid_files->data_vp;
- names_buf = uid_files->buf_ptr;
-
- /* Stat data file for size */
-
- context.vc_proc = p;
- context.vc_ucred = kauth_cred_get();
-
- if ((error = vnode_size(data_vp, &file_size, &context)) != 0) {
- printf("bsd_write_page_cache_file: Can't stat profile data %s\n", file_name);
- bsd_close_page_cache_files(uid_files);
- thread_funnel_set(kernel_flock, funnel_state);
- return error;
- }
-
- if (bsd_search_page_cache_data_base(names_vp,
- (struct profile_names_header *)names_buf,
- file_name, (unsigned int) mod,
- fid, &profile, &profile_size) == 0) {
- /* profile is an offset in the profile data base */
- /* It is zero if no profile data was found */
-
- if(profile_size == 0) {
- unsigned int header_size;
- vm_offset_t buf_ptr;
-
- /* Our Write case */
-
- /* read header for last entry */
- profile_header =
- (struct profile_names_header *)names_buf;
- name_offset = sizeof(struct profile_names_header) +
- (sizeof(struct profile_element)
- * profile_header->number_of_profiles);
- profile_header->number_of_profiles += 1;
-
- if(name_offset < PAGE_SIZE * 4) {
- struct profile_element *name;
- /* write new entry */
- name = (struct profile_element *)
- (names_buf + (vm_offset_t)name_offset);
- name->addr = file_size;
- name->size = size;
- name->mod_date = mod;
- name->inode = fid;
- strncpy (name->name, file_name, 12);
- } else {
- unsigned int ele_size;
- struct profile_element name;
- /* write new entry */
- name.addr = file_size;
- name.size = size;
- name.mod_date = mod;
- name.inode = fid;
- strncpy (name.name, file_name, 12);
- /* write element out separately */
- ele_size = sizeof(struct profile_element);
- buf_ptr = (vm_offset_t)&name;
- resid_off = name_offset;
-
- while(ele_size) {
- error = vn_rdwr(UIO_WRITE, names_vp,
- (caddr_t)buf_ptr,
- ele_size, resid_off,
- UIO_SYSSPACE32, IO_NODELOCKED,
- kauth_cred_get(), &resid, p);
- if(error) {
- printf("bsd_write_page_cache_file: Can't write name_element %x\n", user);
- bsd_close_page_cache_files(
- uid_files);
- thread_funnel_set(
- kernel_flock,
- funnel_state);
- return error;
- }
- buf_ptr += (vm_offset_t)
- ele_size-resid;
- resid_off += ele_size-resid;
- ele_size = resid;
- }
- }
-
- if(name_offset < PAGE_SIZE * 4) {
- header_size = name_offset +
- sizeof(struct profile_element);
-
- } else {
- header_size =
- sizeof(struct profile_names_header);
- }
- buf_ptr = (vm_offset_t)profile_header;
- resid_off = 0;
-
- /* write names file header */
- while(header_size) {
- error = vn_rdwr(UIO_WRITE, names_vp,
- (caddr_t)buf_ptr,
- header_size, resid_off,
- UIO_SYSSPACE32, IO_NODELOCKED,
- kauth_cred_get(), &resid, p);
- if(error) {
- printf("bsd_write_page_cache_file: Can't write header %x\n", user);
- bsd_close_page_cache_files(
- uid_files);
- thread_funnel_set(
- kernel_flock, funnel_state);
- return error;
- }
- buf_ptr += (vm_offset_t)header_size-resid;
- resid_off += header_size-resid;
- header_size = resid;
- }
- /* write profile to data file */
- resid_off = file_size;
- while(size) {
- error = vn_rdwr(UIO_WRITE, data_vp,
- (caddr_t)buffer, size, resid_off,
- UIO_SYSSPACE32, IO_NODELOCKED,
- kauth_cred_get(), &resid, p);
- if(error) {
- printf("bsd_write_page_cache_file: Can't write header %x\n", user);
- bsd_close_page_cache_files(
- uid_files);
- thread_funnel_set(
- kernel_flock, funnel_state);
- return error;
- }
- buffer += size-resid;
- resid_off += size-resid;
- size = resid;
- }
- bsd_close_page_cache_files(uid_files);
- thread_funnel_set(kernel_flock, funnel_state);
- return 0;
- }
- /* Someone else wrote a twin profile before us */
- bsd_close_page_cache_files(uid_files);
- thread_funnel_set(kernel_flock, funnel_state);
- return 0;
- } else {
- bsd_close_page_cache_files(uid_files);
- thread_funnel_set(kernel_flock, funnel_state);
- return EINVAL;
- }
-
-}
-
-int
-prepare_profile_database(int user)
-{
- const char *cache_path = "/var/vm/app_profile/";
- struct proc *p;
- int error;
- int resid;
- off_t resid_off;
- vm_size_t size;
-
- struct vnode *names_vp;
- struct vnode *data_vp;
- vm_offset_t names_buf;
- vm_offset_t buf_ptr;
-
- int profile_names_length;
- int profile_data_length;
- char *profile_data_string;
- char *profile_names_string;
- char *substring;
-
- struct vnode_attr va;
- struct vfs_context context;
-
- struct profile_names_header *profile_header;
- kern_return_t ret;
-
- struct nameidata nd_names;
- struct nameidata nd_data;
-
- p = current_proc();
-
- context.vc_proc = p;
- context.vc_ucred = kauth_cred_get();
-
- ret = kmem_alloc(kernel_map,
- (vm_offset_t *)&profile_data_string, PATH_MAX);
-
- if(ret) {
- return ENOMEM;
- }
-
- /* Split the buffer in half since we know the size of */
- /* our file path and our allocation is adequate for */
- /* both file path names */
- profile_names_string = profile_data_string + (PATH_MAX/2);
-
-
- strcpy(profile_data_string, cache_path);
- strcpy(profile_names_string, cache_path);
- profile_names_length = profile_data_length
- = strlen(profile_data_string);
- substring = profile_data_string + profile_data_length;
- sprintf(substring, "%x_data", user);
- substring = profile_names_string + profile_names_length;
- sprintf(substring, "%x_names", user);
-
- /* We now have the absolute file names */
-
- ret = kmem_alloc(kernel_map,
- (vm_offset_t *)&names_buf, 4 * PAGE_SIZE);
- if(ret) {
- kmem_free(kernel_map,
- (vm_offset_t)profile_data_string, PATH_MAX);
- return ENOMEM;
- }
-
- NDINIT(&nd_names, LOOKUP, FOLLOW,
- UIO_SYSSPACE32, CAST_USER_ADDR_T(profile_names_string), &context);
- NDINIT(&nd_data, LOOKUP, FOLLOW,
- UIO_SYSSPACE32, CAST_USER_ADDR_T(profile_data_string), &context);
-
- if ( (error = vn_open(&nd_data,
- O_CREAT | O_EXCL | FWRITE, S_IRUSR|S_IWUSR)) ) {
- kmem_free(kernel_map,
- (vm_offset_t)names_buf, 4 * PAGE_SIZE);
- kmem_free(kernel_map,
- (vm_offset_t)profile_data_string, PATH_MAX);
-
- return 0;
- }
- data_vp = nd_data.ni_vp;
-
- if ( (error = vn_open(&nd_names,
- O_CREAT | O_EXCL | FWRITE, S_IRUSR|S_IWUSR)) ) {
- printf("prepare_profile_database: Can't create CacheNames %s\n",
- profile_data_string);
- kmem_free(kernel_map,
- (vm_offset_t)names_buf, 4 * PAGE_SIZE);
- kmem_free(kernel_map,
- (vm_offset_t)profile_data_string, PATH_MAX);
-
- vnode_rele(data_vp);
- vnode_put(data_vp);
-
- return error;
- }
- names_vp = nd_names.ni_vp;
-
- /* Write Header for new names file */
-
- profile_header = (struct profile_names_header *)names_buf;
-
- profile_header->number_of_profiles = 0;
- profile_header->user_id = user;
- profile_header->version = 1;
- profile_header->element_array =
- sizeof(struct profile_names_header);
- profile_header->spare1 = 0;
- profile_header->spare2 = 0;
- profile_header->spare3 = 0;
-
- size = sizeof(struct profile_names_header);
- buf_ptr = (vm_offset_t)profile_header;
- resid_off = 0;
-
- while(size) {
- error = vn_rdwr(UIO_WRITE, names_vp,
- (caddr_t)buf_ptr, size, resid_off,
- UIO_SYSSPACE32, IO_NODELOCKED,
- kauth_cred_get(), &resid, p);
- if(error) {
- printf("prepare_profile_database: Can't write header %s\n", profile_names_string);
- kmem_free(kernel_map,
- (vm_offset_t)names_buf, 4 * PAGE_SIZE);
- kmem_free(kernel_map,
- (vm_offset_t)profile_data_string,
- PATH_MAX);
-
- vnode_rele(names_vp);
- vnode_put(names_vp);
- vnode_rele(data_vp);
- vnode_put(data_vp);
-
- return error;
- }
- buf_ptr += size-resid;
- resid_off += size-resid;
- size = resid;
- }
- VATTR_INIT(&va);
- VATTR_SET(&va, va_uid, user);
-
- error = vnode_setattr(names_vp, &va, &context);
- if(error) {
- printf("prepare_profile_database: "
- "Can't set user %s\n", profile_names_string);
- }
- vnode_rele(names_vp);
- vnode_put(names_vp);
-
- VATTR_INIT(&va);
- VATTR_SET(&va, va_uid, user);
- error = vnode_setattr(data_vp, &va, &context);
- if(error) {
- printf("prepare_profile_database: "
- "Can't set user %s\n", profile_data_string);
- }
- vnode_rele(data_vp);
- vnode_put(data_vp);
-
- kmem_free(kernel_map,
- (vm_offset_t)profile_data_string, PATH_MAX);
- kmem_free(kernel_map,
- (vm_offset_t)names_buf, 4 * PAGE_SIZE);
- return 0;
-
-}