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

📄 013_mm_mremap_c.html

📁 重读linux 2.4.2o所写的笔记
💻 HTML
字号:
  <html lang="zh-CN" xmlns:gdoc="">  <head> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <style type="text/css">/* default css */table {  font-size: 1em;  line-height: inherit;}div, address, ol, ul, li, option, select {   margin-top: 0px;  margin-bottom: 0px;}p {  margin: 0px;}body {        margin: 0px;          padding: 0px;    font-family: Verdana, sans-serif;  font-size: 10pt;  background-color: #ffffff;}h6 { font-size: 10pt }h5 { font-size: 11pt }h4 { font-size: 12pt }h3 { font-size: 13pt }h2 { font-size: 14pt }h1 { font-size: 16pt }blockquote {padding: 10px; border: 1px #DDD dashed }a img {border: 0}div.google_header, div.google_footer {  position: relative;  margin-top: 1em;  margin-bottom: 1em;}/* end default css */  /* default print css */    @media print {    body {       padding: 0;       margin: 0;     }    div.google_header, div.google_footer {      display: block;      min-height: 0;      border: none;    }    div.google_header {      flow: static(header);    }    /* used to insert page numbers */    div.google_header::before, div.google_footer::before {      position: absolute;      top: 0;    }    div.google_footer {      flow: static(footer);    }    /* always consider this element at the start of the doc */    div#google_footer {      flow: static(footer, start);    }    span.google_pagenumber {      content: counter(page);    }    span.google_pagecount {      content: counter(pages);    }  }  @page {    @top {      content: flow(header);    }    @bottom {      content: flow(footer);    }  }  /* end default print css */ /* custom css *//* end custom css */  /* ui edited css */    body {    font-family: Verdana;        font-size: 10.0pt;    line-height: normal;    background-color: #ffffff;  }    .documentBG {    background-color: #ffffff;  }  /* end ui edited css */</style>   </head>  <body  revision="dcbsxfpf_54cr593rcq:5">      <table align=center cellpadding=0 cellspacing=0 height=5716 width=768>
  <tbody>
  <tr>
    <td height=5716 valign=top width=100%>
      <pre>2006-5-24   <br>mm/mremap.c<br><br>  本模块提供系统调用,mremap。请先参考对模块mm/mmap.c的分析。先看系统调<br>用的功能。<br>  sys_mremap(unsigned long addr,unsigned long old_len, unsigned long new_len,<br>	unsigned long flags, unsigned long new_addr)<br>	<br>	mremap扩展或者收缩现存的memory mapping。可能会将映射在虚拟地址内进行移动。<br>  addr是要进行remap的现存映射首地址。old_size是现存映射的大小.new_len是<br>这次remap的请求长度。<br>  利用mremap可以实现高效的无拷贝realloc。<br>  flags:<br>  MREMAP_MAYMOVE:容许配给一个新的虚拟地址.<br>  MREMAP_FIXED: 配合new_addr,仅当此标记置位,new_addr才有意义.<br>  <br>  对这系统调用的分析,我们采用代码的强注释来完成:<br>  <br>/* 分为三种情况阅读代码比较容易或得整体印象:<br> *  start --end(start+len) 位于vma的起始,结束,末尾<br> *  加上每种又分为扩展和收缩两种情况。<br> */<br>/*注意如果是fixmap,新旧地址就不能相等,并且<br> *新旧地址交叠也不容许。(除非新旧长度都是0)<br> */<br>unsigned long do_mremap(unsigned long addr,unsigned long old_len, <br>unsigned long new_len,unsigned long flags, unsigned long new_addr)<br>{<br>	struct vm_area_struct *vma;<br>	unsigned long ret = -EINVAL;<br><br>	if (flags &amp; ~(MREMAP_FIXED | MREMAP_MAYMOVE))//仅支持这两个标记<br>		goto out;<br><br>	if (addr &amp; ~PAGE_MASK)//首地址需要page align<br>		goto out;<br><br>	old_len = PAGE_ALIGN(old_len);<br>	new_len = PAGE_ALIGN(new_len);<br><br>	/* new_addr is only valid if MREMAP_FIXED is specified */<br>	//如果要求fix remap,首先清除指定(新)地址上的映射<br>	if (flags &amp; MREMAP_FIXED) {//要求映射到指定虚拟地址<br>		if (new_addr &amp; ~PAGE_MASK)<br>			goto out;<br>		if (!(flags &amp; MREMAP_MAYMOVE))//fixmap要求和move配合使用<br>			goto out;<br><br>		if (new_len &gt; TASK_SIZE || new_addr &gt; TASK_SIZE - new_len)<br>			goto out;<br><br>		/* Check if the location we're moving into overlaps the<br>		 * old location at all, and fail if it does.<br>		 */<br>		 //fix map要求新旧地址空间不能有任何重叠<br>		if ((new_addr &lt;= addr) &amp;&amp; (new_addr+new_len) &gt; addr)<br>			goto out;<br><br>		if ((addr &lt;= new_addr) &amp;&amp; (addr+old_len) &gt; new_addr)<br>			goto out;<br><br>		do_munmap(current-&gt;mm, new_addr, new_len);/*参考对mmap.c的分析*/<br>	}<br><br>	/*<br>	 * Always allow a shrinking remap: that just unmaps<br>	 * the unnecessary pages..<br>	 */<br>	//如果remap后映射缩减,需要unmap缩减部分<br>	ret = addr;<br>	if (old_len &gt;= new_len) {<br>		do_munmap(current-&gt;mm, addr+new_len, old_len - new_len);<br>		if (!(flags &amp; MREMAP_FIXED) || (new_addr == addr))<br>			goto out;<br>	}<br><br>	/*<br>	 * Ok, we need to grow..  or relocate.<br>	 */<br>	//寻找涉案vma<br>	ret = -EFAULT;<br>	vma = find_vma(current-&gt;mm, addr); //addr&lt;vma_end<br>	if (!vma || vma-&gt;vm_start &gt; addr)<br>		goto out;//no such vma contain "addr"<br><br>	//检查指定vma 是否容许此次remap<br>	/* We can't remap across vm area boundaries */<br>	if (old_len &gt; vma-&gt;vm_end - addr)//注意:remap 不能跨越vma<br>		goto out; //注意用户指定的addr 可以在一个vma内,而不是vma_stat<br>	if (vma-&gt;vm_flags &amp; VM_DONTEXPAND) {//不能扩展的vma<br>		if (new_len &gt; old_len)<br>			goto out;<br>	}<br>	if (vma-&gt;vm_flags &amp; VM_LOCKED) {//内存锁定 总量不能超越限制<br>		unsigned long locked = current-&gt;mm-&gt;locked_vm &lt;&lt; PAGE_SHIFT;<br>		locked += new_len - old_len;<br>		ret = -EAGAIN;<br>		if (locked &gt; current-&gt;rlim[RLIMIT_MEMLOCK].rlim_cur)<br>			goto out;<br>	}<br>	ret = -ENOMEM;<br>	if ((current-&gt;mm-&gt;total_vm &lt;&lt; PAGE_SHIFT) + (new_len - old_len)<br>	    &gt; current-&gt;rlim[RLIMIT_AS].rlim_cur)//总vma不能超限<br>		goto out;<br>	/* Private writable mapping? Check memory availability.. */<br>	            /*内核为此种映射保留一定的内存,除非用户无需此种机制*/<br>	if ((vma-&gt;vm_flags &amp; (VM_SHARED | VM_WRITE)) == VM_WRITE &amp;&amp;<br>	    !(flags &amp; MAP_NORESERVE)				 &amp;&amp;<br>	    !vm_enough_memory((new_len - old_len) &gt;&gt; PAGE_SHIFT))<br>		goto out;<br><br><br><br>	/* old_len exactly to the end of the area..<br>	 * And we're not relocating the area.<br>	 */<br>	if (old_len == vma-&gt;vm_end - addr &amp;&amp;<br>	    !((flags &amp; MREMAP_FIXED) &amp;&amp; (addr != new_addr)) &amp;&amp;<br>	    (old_len != new_len || !(flags &amp; MREMAP_MAYMOVE))) {<br>	    //位于末尾,长度不等或者不容许移动<br>	    //并且不是非等首地址的fixmap<br>	  unsigned long max_addr = TASK_SIZE;<br>		if (vma-&gt;vm_next)<br>			max_addr = vma-&gt;vm_next-&gt;vm_start;<br>		/* can we just expand the current mapping? */<br>		if (max_addr - addr &gt;= new_len) {<br>			int pages = (new_len - old_len) &gt;&gt; PAGE_SHIFT;<br>			spin_lock(&amp;vma-&gt;vm_mm-&gt;page_table_lock);<br>			vma-&gt;vm_end = addr + new_len;<br>			spin_unlock(&amp;vma-&gt;vm_mm-&gt;page_table_lock);<br>			current-&gt;mm-&gt;total_vm += pages;<br>			if (vma-&gt;vm_flags &amp; VM_LOCKED) {<br>				current-&gt;mm-&gt;locked_vm += pages;<br>				make_pages_present(addr + old_len,<br>						   addr + new_len);<br>			}<br>			ret = addr;<br>			goto out;<br>		}<br>	}<br><br>	/*<br>	 * We weren't able to just expand or shrink the area,<br>	 * we need to create a new one and move it..<br>	 */<br>	 /*必须移动映射了*/<br>	ret = -ENOMEM;<br>	if (flags &amp; MREMAP_MAYMOVE) {//必须容许移动<br>		if (!(flags &amp; MREMAP_FIXED)) {/*非fixmap时可以寻找新的虚拟空间*/<br>                                        <br>			new_addr = get_unmapped_area(0, new_len);<br>			if (!new_addr)<br>				goto out;<br>		}<br>		/*fixmap时new_addr指定的一段空间不会和old space交叠在一起所以move <br>	   vma没有问题*/<br>		ret = move_vma(vma, addr, old_len, new_len, new_addr);<br>	}<br>out:<br>	return ret;<br>}  <br><br>剩下的需要分析的函数就是move_vma,其他函数不再分析:  <br>static inline unsigned long move_vma(struct vm_area_struct * vma,<br>	unsigned long addr, unsigned long old_len, unsigned long new_len,<br>	unsigned long new_addr)<br>{<br>	struct vm_area_struct * new_vma;<br><br>	new_vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);<br>	if (new_vma) {<br>		//移动页表包括分配新的页表,页目录,拷贝pte<br>		if (!move_page_tables(current-&gt;mm, new_addr, addr, old_len)) {<br>			//页表操作完成,建立新的vma<br>		 	*new_vma = *vma;<br>			new_vma-&gt;vm_start = new_addr;<br>			new_vma-&gt;vm_end = new_addr+new_len;<br>			new_vma-&gt;vm_pgoff += (addr - vma-&gt;vm_start) &gt;&gt; PAGE_SHIFT;<br>			new_vma-&gt;vm_raend = 0;<br>			if (new_vma-&gt;vm_file)<br>				get_file(new_vma-&gt;vm_file);<br>			if (new_vma-&gt;vm_ops &amp;&amp; new_vma-&gt;vm_ops-&gt;open)<br>				new_vma-&gt;vm_ops-&gt;open(new_vma);<br>			insert_vm_struct(current-&gt;mm, new_vma);<br>			do_munmap(current-&gt;mm, addr, old_len);   //unmap老的地址空间<br>			current-&gt;mm-&gt;total_vm += new_len &gt;&gt; PAGE_SHIFT;<br>			if (new_vma-&gt;vm_flags &amp; VM_LOCKED) {//lock就立即分配内存<br>				current-&gt;mm-&gt;locked_vm += new_len &gt;&gt; PAGE_SHIFT;<br>				make_pages_present(new_vma-&gt;vm_start,<br>						   new_vma-&gt;vm_end);<br>			}<br>			return new_addr;<br>		}<br>		kmem_cache_free(vm_area_cachep, new_vma);<br>	}<br>	return -ENOMEM;<br>}<br>  <br><br>	<br><br>  <br>  <br></pre>
    </td>
  </tr>
  </tbody>
</table></body></html>

⌨️ 快捷键说明

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