int new_page_tables(struct task_struct * tsk) { pgd_t * page_dir, * new_pg; if (!(new_pg = pgd_alloc())) return -ENOMEM; page_dir = pgd_offset(&init_mm, 0); flush_cache_mm(tsk->mm); memcpy(new_pg + USER_PTRS_PER_PGD, page_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof (pgd_t)); flush_tlb_mm(tsk->mm); SET_PAGE_DIR(tsk, new_pg); tsk->mm->pgd = new_pg; return 0; }
static inline void __exit_mm(struct task_struct * tsk) { struct mm_struct * mm = tsk->mm; /* Set us up to use the kernel mm state */ if (mm != &init_mm) { flush_cache_mm(mm); flush_tlb_mm(mm); destroy_context(mm); tsk->mm = &init_mm; tsk->swappable = 0; SET_PAGE_DIR(tsk, swapper_pg_dir); mm_release(); mmput(mm); } }
/* * This function clears all user-level page tables of a process - this * is needed by execve(), so that old pages aren't in the way. */ void clear_page_tables(struct task_struct * tsk) { int i; pgd_t * page_dir; page_dir = tsk->mm->pgd; if (!page_dir || page_dir == swapper_pg_dir) { printk("%s trying to clear kernel page-directory: not good\n", tsk->comm); return; } flush_cache_mm(tsk->mm); #ifndef CONFIG_BESTA for (i = 0 ; i < USER_PTRS_PER_PGD ; i++) free_one_pgd(page_dir + i); #else for (i = 0 ; i < PTRS_PER_PGD ; i++) free_one_pgd(page_dir + i); #endif flush_tlb_mm(tsk->mm); }
static inline void __exit_mm(struct task_struct * tsk) { struct mm_struct * mm = tsk->mm; /* Set us up to use the kernel mm state */ if (mm != &init_mm) { flush_cache_mm(mm); flush_tlb_mm(mm); tsk->mm = &init_mm; tsk->swappable = 0; SET_PAGE_DIR(tsk, swapper_pg_dir); /* free the old state - not used any more */ if (!--mm->count) { exit_mmap(mm); free_page_tables(mm); kfree(mm); } } }
static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm) { struct vm_area_struct * mpnt, *tmp, **pprev; struct rb_node **rb_link, *rb_parent; int retval; unsigned long charge; struct mempolicy *pol; down_write(&oldmm->mmap_sem); flush_cache_mm(current->mm); mm->locked_vm = 0; mm->mmap = NULL; mm->mmap_cache = NULL; mm->free_area_cache = oldmm->mmap_base; mm->map_count = 0; mm->rss = 0; mm->anon_rss = 0; cpus_clear(mm->cpu_vm_mask); mm->mm_rb = RB_ROOT; rb_link = &mm->mm_rb.rb_node; rb_parent = NULL; pprev = &mm->mmap; for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) { struct file *file; if (mpnt->vm_flags & VM_DONTCOPY) { __vm_stat_account(mm, mpnt->vm_flags, mpnt->vm_file, -vma_pages(mpnt)); continue; } charge = 0; if (mpnt->vm_flags & VM_ACCOUNT) { unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; if (security_vm_enough_memory(len)) goto fail_nomem; charge = len; } tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!tmp) goto fail_nomem; *tmp = *mpnt; pol = mpol_copy(vma_policy(mpnt)); retval = PTR_ERR(pol); if (IS_ERR(pol)) goto fail_nomem_policy; vma_set_policy(tmp, pol); tmp->vm_flags &= ~VM_LOCKED; tmp->vm_mm = mm; tmp->vm_next = NULL; anon_vma_link(tmp); file = tmp->vm_file; if (file) { struct inode *inode = file->f_dentry->d_inode; get_file(file); if (tmp->vm_flags & VM_DENYWRITE) atomic_dec(&inode->i_writecount); /* insert tmp into the share list, just after mpnt */ spin_lock(&file->f_mapping->i_mmap_lock); tmp->vm_truncate_count = mpnt->vm_truncate_count; flush_dcache_mmap_lock(file->f_mapping); vma_prio_tree_add(tmp, mpnt); flush_dcache_mmap_unlock(file->f_mapping); spin_unlock(&file->f_mapping->i_mmap_lock); } /* * Link in the new vma and copy the page table entries: * link in first so that swapoff can see swap entries, * and try_to_unmap_one's find_vma find the new vma. */ spin_lock(&mm->page_table_lock); *pprev = tmp; pprev = &tmp->vm_next; __vma_link_rb(mm, tmp, rb_link, rb_parent); rb_link = &tmp->vm_rb.rb_right; rb_parent = &tmp->vm_rb; mm->map_count++; retval = copy_page_range(mm, current->mm, tmp); spin_unlock(&mm->page_table_lock); if (tmp->vm_ops && tmp->vm_ops->open) tmp->vm_ops->open(tmp); if (retval) goto out; }
static inline int dup_mmap(struct mm_struct * mm) { struct vm_area_struct * mpnt, *tmp, **pprev; rb_node_t **rb_link, *rb_parent; int retval; unsigned long charge; flush_cache_mm(current->mm); mm->locked_vm = 0; mm->mmap = NULL; mm->mmap_cache = NULL; mm->map_count = 0; mm->free_area_cache = TASK_UNMAPPED_BASE; /* unlimited stack is larger than TASK_SIZE */ mm->non_executable_cache = NON_EXECUTABLE_CACHE(current); mm->rss = 0; mm->cpu_vm_mask = 0; mm->mm_rb = RB_ROOT; rb_link = &mm->mm_rb.rb_node; rb_parent = NULL; pprev = &mm->mmap; /* * Add it to the mmlist after the parent. * Doing it this way means that we can order the list, * and fork() won't mess up the ordering significantly. * Add it first so that swapoff can see any swap entries. */ spin_lock(&mmlist_lock); list_add(&mm->mmlist, ¤t->mm->mmlist); mmlist_nr++; spin_unlock(&mmlist_lock); for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) { struct file *file; retval = -ENOMEM; if(mpnt->vm_flags & VM_DONTCOPY) continue; charge = 0; if(mpnt->vm_flags & VM_ACCOUNT) { unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; if(!vm_enough_memory(len)) goto fail_nomem; charge = len; } tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!tmp) goto fail_nomem; *tmp = *mpnt; if (likely(!(tmp->vm_flags & VM_NO_UNLOCK))) tmp->vm_flags &= ~VM_LOCKED; tmp->vm_mm = mm; tmp->vm_next = NULL; file = tmp->vm_file; if (file) { struct inode *inode = file->f_dentry->d_inode; get_file(file); if (tmp->vm_flags & VM_DENYWRITE) atomic_dec(&inode->i_writecount); /* insert tmp into the share list, just after mpnt */ spin_lock(&inode->i_mapping->i_shared_lock); if((tmp->vm_next_share = mpnt->vm_next_share) != NULL) mpnt->vm_next_share->vm_pprev_share = &tmp->vm_next_share; mpnt->vm_next_share = tmp; tmp->vm_pprev_share = &mpnt->vm_next_share; spin_unlock(&inode->i_mapping->i_shared_lock); } /* * Link in the new vma and copy the page table entries: * link in first so that swapoff can see swap entries, * and try_to_unmap_one's find_vma find the new vma. */ spin_lock(&mm->page_table_lock); *pprev = tmp; pprev = &tmp->vm_next; __vma_link_rb(mm, tmp, rb_link, rb_parent); rb_link = &tmp->vm_rb.rb_right; rb_parent = &tmp->vm_rb; mm->map_count++; retval = copy_page_range(mm, current->mm, tmp); spin_unlock(&mm->page_table_lock); if (tmp->vm_ops && tmp->vm_ops->open) tmp->vm_ops->open(tmp); if (retval) goto fail_nomem; }