⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmap.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 3 页
字号:
		/* same locking considerations of the above case */		area->vm_start = end;		lock_vma_mappings(area);		spin_lock(&mm->page_table_lock);	} else {	/* Unmapping a hole: area->vm_start < addr <= end < area->vm_end */		/* Add end mapping -- leave beginning for below */		mpnt = extra;		extra = NULL;		mpnt->vm_mm = area->vm_mm;		mpnt->vm_start = end;		mpnt->vm_end = area->vm_end;		mpnt->vm_page_prot = area->vm_page_prot;		mpnt->vm_flags = area->vm_flags;		mpnt->vm_raend = 0;		mpnt->vm_ops = area->vm_ops;		mpnt->vm_pgoff = area->vm_pgoff + ((end - area->vm_start) >> PAGE_SHIFT);		mpnt->vm_file = area->vm_file;		mpnt->vm_private_data = area->vm_private_data;		if (mpnt->vm_file)			get_file(mpnt->vm_file);		if (mpnt->vm_ops && mpnt->vm_ops->open)			mpnt->vm_ops->open(mpnt);		area->vm_end = addr;	/* Truncate area */		/* Because mpnt->vm_file == area->vm_file this locks		 * things correctly.		 */		lock_vma_mappings(area);		spin_lock(&mm->page_table_lock);		__insert_vm_struct(mm, mpnt);	}	__insert_vm_struct(mm, area);	spin_unlock(&mm->page_table_lock);	unlock_vma_mappings(area);	return extra;}/* * Try to free as many page directory entries as we can, * without having to work very hard at actually scanning * the page tables themselves. * * Right now we try to free page tables if we have a nice * PGDIR-aligned area that got free'd up. We could be more * granular if we want to, but this is fast and simple, * and covers the bad cases. * * "prev", if it exists, points to a vma before the one * we just free'd - but there's no telling how much before. */static void free_pgtables(struct mm_struct * mm, struct vm_area_struct *prev,	unsigned long start, unsigned long end){	unsigned long first = start & PGDIR_MASK;	unsigned long last = end + PGDIR_SIZE - 1;	unsigned long start_index, end_index;	if (!prev) {		prev = mm->mmap;		if (!prev)			goto no_mmaps;		if (prev->vm_end > start) {			if (last > prev->vm_start)				last = prev->vm_start;			goto no_mmaps;		}	}	for (;;) {		struct vm_area_struct *next = prev->vm_next;		if (next) {			if (next->vm_start < start) {				prev = next;				continue;			}			if (last > next->vm_start)				last = next->vm_start;		}		if (prev->vm_end > first)			first = prev->vm_end + PGDIR_SIZE - 1;		break;	}no_mmaps:	/*	 * If the PGD bits are not consecutive in the virtual address, the	 * old method of shifting the VA >> by PGDIR_SHIFT doesn't work.	 */	start_index = pgd_index(first);	if (start_index < FIRST_USER_PGD_NR)		start_index = FIRST_USER_PGD_NR;	end_index = pgd_index(last);	if (end_index > start_index) {		clear_page_tables(mm, start_index, end_index - start_index);		flush_tlb_pgtables(mm, first & PGDIR_MASK, last & PGDIR_MASK);	}}/* Munmap is split into 2 main parts -- this part which finds * what needs doing, and the areas themselves, which do the * work.  This now handles partial unmappings. * Jeremy Fitzhardine <jeremy@sw.oz.au> */int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len){	struct vm_area_struct *mpnt, *prev, **npp, *free, *extra;	if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)		return -EINVAL;	if ((len = PAGE_ALIGN(len)) == 0)		return -EINVAL;	/* Check if this memory area is ok - put it on the temporary	 * list if so..  The checks here are pretty simple --	 * every area affected in some way (by any overlap) is put	 * on the list.  If nothing is put on, nothing is affected.	 */	mpnt = find_vma_prev(mm, addr, &prev);	if (!mpnt)		return 0;	/* we have  addr < mpnt->vm_end  */	if (mpnt->vm_start >= addr+len)		return 0;	/* If we'll make "hole", check the vm areas limit */	if ((mpnt->vm_start < addr && mpnt->vm_end > addr+len)	    && mm->map_count >= MAX_MAP_COUNT)		return -ENOMEM;	/*	 * We may need one additional vma to fix up the mappings ... 	 * and this is the last chance for an easy error exit.	 */	extra = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);	if (!extra)		return -ENOMEM;	npp = (prev ? &prev->vm_next : &mm->mmap);	free = NULL;	spin_lock(&mm->page_table_lock);	for ( ; mpnt && mpnt->vm_start < addr+len; mpnt = *npp) {		*npp = mpnt->vm_next;		mpnt->vm_next = free;		free = mpnt;		rb_erase(&mpnt->vm_rb, &mm->mm_rb);	}	mm->mmap_cache = NULL;	/* Kill the cache. */	spin_unlock(&mm->page_table_lock);	/* Ok - we have the memory areas we should free on the 'free' list,	 * so release them, and unmap the page range..	 * If the one of the segments is only being partially unmapped,	 * it will put new vm_area_struct(s) into the address space.	 * In that case we have to be careful with VM_DENYWRITE.	 */	while ((mpnt = free) != NULL) {		unsigned long st, end, size;		struct file *file = NULL;		free = free->vm_next;		st = addr < mpnt->vm_start ? mpnt->vm_start : addr;		end = addr+len;		end = end > mpnt->vm_end ? mpnt->vm_end : end;		size = end - st;		if (mpnt->vm_flags & VM_DENYWRITE &&		    (st != mpnt->vm_start || end != mpnt->vm_end) &&		    (file = mpnt->vm_file) != NULL) {			atomic_dec(&file->f_dentry->d_inode->i_writecount);		}		remove_shared_vm_struct(mpnt);		mm->map_count--;		zap_page_range(mm, st, size);		/*		 * Fix the mapping, and free the old area if it wasn't reused.		 */		extra = unmap_fixup(mm, mpnt, st, size, extra);		if (file)			atomic_inc(&file->f_dentry->d_inode->i_writecount);	}	validate_mm(mm);	/* Release the extra vma struct if it wasn't used */	if (extra)		kmem_cache_free(vm_area_cachep, extra);	free_pgtables(mm, prev, addr, addr+len);	return 0;}asmlinkage long sys_munmap(unsigned long addr, size_t len){	int ret;	struct mm_struct *mm = current->mm;	down_write(&mm->mmap_sem);	ret = do_munmap(mm, addr, len);	up_write(&mm->mmap_sem);	return ret;}/* *  this is really a simplified "do_mmap".  it only handles *  anonymous maps.  eventually we may be able to do some *  brk-specific accounting here. */unsigned long do_brk(unsigned long addr, unsigned long len){	struct mm_struct * mm = current->mm;	struct vm_area_struct * vma, * prev;	unsigned long flags;	rb_node_t ** rb_link, * rb_parent;	len = PAGE_ALIGN(len);	if (!len)		return addr;	/*	 * mlock MCL_FUTURE?	 */	if (mm->def_flags & VM_LOCKED) {		unsigned long locked = mm->locked_vm << PAGE_SHIFT;		locked += len;		if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur)			return -EAGAIN;	}	/*	 * Clear old maps.  this also does some error checking for us	 */ munmap_back:	vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent);	if (vma && vma->vm_start < addr + len) {		if (do_munmap(mm, addr, len))			return -ENOMEM;		goto munmap_back;	}	/* Check against address space limits *after* clearing old maps... */	if ((mm->total_vm << PAGE_SHIFT) + len	    > current->rlim[RLIMIT_AS].rlim_cur)		return -ENOMEM;	if (mm->map_count > MAX_MAP_COUNT)		return -ENOMEM;	if (!vm_enough_memory(len >> PAGE_SHIFT))		return -ENOMEM;	flags = calc_vm_flags(PROT_READ|PROT_WRITE|PROT_EXEC,				MAP_FIXED|MAP_PRIVATE) | mm->def_flags;	flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;	/* Can we just expand an old anonymous mapping? */	if (rb_parent && vma_merge(mm, prev, rb_parent, addr, addr + len, flags))		goto out;	/*	 * create a vma struct for an anonymous mapping	 */	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);	if (!vma)		return -ENOMEM;	vma->vm_mm = mm;	vma->vm_start = addr;	vma->vm_end = addr + len;	vma->vm_flags = flags;	vma->vm_page_prot = protection_map[flags & 0x0f];	vma->vm_ops = NULL;	vma->vm_pgoff = 0;	vma->vm_file = NULL;	vma->vm_private_data = NULL;	vma_link(mm, vma, prev, rb_link, rb_parent);out:	mm->total_vm += len >> PAGE_SHIFT;	if (flags & VM_LOCKED) {		mm->locked_vm += len >> PAGE_SHIFT;		make_pages_present(addr, addr + len);	}	return addr;}/* Build the RB tree corresponding to the VMA list. */void build_mmap_rb(struct mm_struct * mm){	struct vm_area_struct * vma;	rb_node_t ** rb_link, * rb_parent;	mm->mm_rb = RB_ROOT;	rb_link = &mm->mm_rb.rb_node;	rb_parent = NULL;	for (vma = mm->mmap; vma; vma = vma->vm_next) {		__vma_link_rb(mm, vma, rb_link, rb_parent);		rb_parent = &vma->vm_rb;		rb_link = &rb_parent->rb_right;	}}/* Release all mmaps. */void exit_mmap(struct mm_struct * mm){	mmu_gather_t *tlb;	struct vm_area_struct * mpnt;	release_segments(mm);	spin_lock(&mm->page_table_lock);	tlb = tlb_gather_mmu(mm);	flush_cache_mm(mm);	mpnt = mm->mmap;	while (mpnt) {		unsigned long start = mpnt->vm_start;		unsigned long end = mpnt->vm_end;		mm->map_count--;		remove_shared_vm_struct(mpnt);		unmap_page_range(tlb, mm, start, end);		mpnt = mpnt->vm_next;	}	/* This is just debugging */	if (mm->map_count)		BUG();	tlb_finish_mmu(tlb, 0, TASK_SIZE);	mpnt = mm->mmap;	mm->mmap = mm->mmap_cache = NULL;	mm->mm_rb = RB_ROOT;	mm->rss = 0;	mm->total_vm = 0;	mm->locked_vm = 0;	spin_unlock(&mm->page_table_lock);	clear_page_tables(mm, FIRST_USER_PGD_NR, USER_PTRS_PER_PGD);	/*	 * Walk the list again, actually closing and freeing it	 * without holding any MM locks.	 */	while (mpnt) {		struct vm_area_struct * next = mpnt->vm_next;		if (mpnt->vm_ops) {			if (mpnt->vm_ops->close)				mpnt->vm_ops->close(mpnt);		}		if (mpnt->vm_file)			fput(mpnt->vm_file);		kmem_cache_free(vm_area_cachep, mpnt);		mpnt = next;	}}/* Insert vm structure into process list sorted by address * and into the inode's i_mmap ring.  If vm_file is non-NULL * then the i_shared_lock must be held here. */void __insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma){	struct vm_area_struct * __vma, * prev;	rb_node_t ** rb_link, * rb_parent;	__vma = find_vma_prepare(mm, vma->vm_start, &prev, &rb_link, &rb_parent);	if (__vma && __vma->vm_start < vma->vm_end)		BUG();	__vma_link(mm, vma, prev, rb_link, rb_parent);	mm->map_count++;	validate_mm(mm);}void insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma){	struct vm_area_struct * __vma, * prev;	rb_node_t ** rb_link, * rb_parent;	__vma = find_vma_prepare(mm, vma->vm_start, &prev, &rb_link, &rb_parent);	if (__vma && __vma->vm_start < vma->vm_end)		BUG();	vma_link(mm, vma, prev, rb_link, rb_parent);	validate_mm(mm);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -