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

📄 ch08s03.html

📁 介绍Linux内核驱动编程的一本书 最主要的是有源代码,都是可用的 学习操作系统很好
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<html xmlns:cf="http://docbook.sourceforge.net/xmlns/chunkfast/1.0"><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><title>8.3.&#160;get_free_page 和其友-Linux设备驱动第三版(中文版)- - </title><meta name="description" content="驱动开发- - " /><meta name="keywords" content="Linux设备驱动,中文版,第三版,ldd,linux device driver,驱动开发,电子版,程序设计,软件开发, " /><meta name="author" content="  www.21cstar.com QQ:610061171" /> <meta name="verify-v1" content="5asbXwkS/Vv5OdJbK3Ix0X8osxBUX9hutPyUxoubhes=" /><link rel="stylesheet" href="docbook.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.69.0"><link rel="start" href="index.html" title="Linux 设备驱动 Edition 3"><link rel="up" href="ch08.html" title="第&#160;8&#160;章&#160;分配内存"><link rel="prev" href="ch08s02.html" title="8.2.&#160;后备缓存"><link rel="next" href="ch08s04.html" title="8.4.&#160;每-CPU 的变量"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">8.3.&#160;get_free_page 和其友</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch08s02.html">上一页</a>&#160;</td><th width="60%" align="center">第&#160;8&#160;章&#160;分配内存</th><td width="20%" align="right">&#160;<a accesskey="n" href="ch08s04.html">下一页</a></td></tr></table><hr></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="getfreepageandFriends.sect"></a>8.3.&#160;get_free_page 和其友</h2></div></div></div><p>如果一个模块需要分配大块的内存, 它常常最好是使用一个面向页的技术. 请求整个页也有其他的优点, 这个在 15 章介绍.</p><p>为分配页, 下列函数可用:</p><div class="variablelist"><dl><dt><span class="term"><span>get_zeroed_page(unsigned int flags);</span></span></dt><dd><p>返回一个指向新页的指针并且用零填充了该页.</p></dd><dt><span class="term"><span>__get_free_page(unsigned int flags);</span></span></dt><dd><p>类似于 get_zeroed_page, 但是没有清零该页.</p></dd><dt><span class="term"><span>__get_free_pages(unsigned int flags, unsigned int order);</span></span></dt><dd><p>分配并返回一个指向一个内存区第一个字节的指针, 内存区可能是几个(物理上连续)页长但是没有清零.</p></dd></dl></div><p>flags 参数同 kmalloc 的用法相同; 常常使用 GFP_KERNEL 或者 GFP_ATOMIC, 可能带有 __GFP_DMA 标志( 给可能用在 ISA DMA 操作的内存 ) 或者 __GFP_HIGHMEM 当可能使用高端内存时. <sup>[<a name="id451239" href="#ftn.id451239">29</a>]</sup>order 是你在请求的或释放的页数的以 2 为底的对数(即, log2N). 例如, 如果你要一个页 order 为 0, 如果你请求 8 页就是 3. 如果 order 太大(没有那个大小的连续区可用), 页分配失败. get_order 函数, 它使用一个整数参数, 可以用来从一个 size 中提取 order(它必须是 2 的幂)给主机平台. order 允许的最大值是 10 或者 11 (对应于 1024 或者 2048 页), 依赖于体系. 但是, 一个 order-10 的分配在除了一个刚刚启动的有很多内存的系统中成功的机会是小的.</p><p>如果你好奇, /proc/buddyinfo 告诉你系统中每个内存区中的每个 order 有多少块可用.</p><p>当一个程序用完这些页, 它可以使用下列函数之一来释放它们. 第一个函数是一个落回第二个函数的宏:</p><pre class="programlisting">void free_page(unsigned long addr);void free_pages(unsigned long addr, unsigned long order);</pre><p>如果你试图释放和你分配的页数不同的页数, 内存图变乱, 系统在后面时间中有麻烦.</p><p>值得强调一下, __get_free_pages 和其他的函数可以在任何时候调用, 遵循我们看到的 kmalloc 的相同规则. 这些函数不能在某些情况下分配内存, 特别当使用 GFP_ATOMIC 时. 因此, 调用这些分配函数的程序必须准备处理分配失败.</p><p>尽管 kmalloc( GFP_KERNEL )有时失败当没有可用内存时, 内核尽力满足分配请求. 因此, 容易通过分配太多的内存降低系统的响应. 例如, 你可以通过塞入一个 scull 设备大量数据使计算机关机; 系统开始爬行当它试图换出尽可能多的内存来满足 kmalloc 的请求. 因为每个资源在被增长的设备所吞食, 计算机很快就被说无法用; 在这点上, 你甚至不能启动一个新进程来试图处理这个问题. 我们在 scull 不解释这个问题, 因为它只是一个例子模块并且不是一个真正的放入多用户系统的工具. 作为一个程序员, 你必须小心, 因为一个模块是特权代码并且可能在系统中开启新的安全漏洞(最可能是一个服务拒绝漏洞好像刚刚描述过的.)</p><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="AscullUsingWholePagesscullp.sect"></a>8.3.1.&#160;一个使用整页的 scull: scullp</h3></div></div></div><p>为了真实地测试页分配, 我们已随其他例子代码发布了 scullp 模块. 它是一个简化的 scull, 就像前面介绍过的 scullc.</p><p>scullp 分配的内存量子是整页或者页集合: scullp_order 变量缺省是 0, 但是可以在编译或加载时改变.</p><p>下列代码行显示了它如何分配内存:</p><pre class="programlisting">/* Here's the allocation of a single quantum */if (!dptr-&gt;data[s_pos]){        dptr-&gt;data[s_pos] =                (void *)__get_free_pages(GFP_KERNEL, dptr-&gt;order);        if (!dptr-&gt;data[s_pos])                goto nomem;        memset(dptr-&gt;data[s_pos], 0, PAGE_SIZE &lt;&lt; dptr-&gt;order);}</pre><p>scullp 中释放内存的代码看来如此:</p><pre class="programlisting">/* This code frees a whole quantum-set */for (i = 0; i &lt; qset; i++)        if (dptr-&gt;data[i])                free_pages((unsigned long)(dptr-&gt;data[i]), dptr-&gt;order);</pre><p>在用户级别, 被感觉到的区别主要是一个速度提高和更好的内存使用, 因为没有内部的内存碎片. 我们运行一些测试从 scull0 拷贝 4 MB 到 scull1, 并且接着从 scullp0 到 scullp1; 结果显示了在内核空间处理器使用率有轻微上升.</p><p>性能的提高不是激动人心的, 因为 kmalloc 被设计为快的. 页级别分配的主要优势实际上不是速度, 而是更有效的内存使用. 按页分配不浪费内存, 而使用 kmalloc 由于分配的粒度会浪费无法预测数量的内存.</p><p>但是 __get_free_page 函数的最大优势是获得的页完全是你的, 并且你可以, 理论上, 可以通过适当的设置页表来组合这些页为一个线性的区域. 例如, 你可以允许一个用户进程 mmap 作为单个不联系的页而获得的内存区. 我们在 15 章讨论这种操作, 那里我们展示 scullp 如何提供内存映射, 一些 scull 无法提供的东西.</p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="TheallocpagesInterface.sect"></a>8.3.2.&#160;alloc_pages 接口</h3></div></div></div><p>为完整起见, 我们介绍另一个内存分配的接口, 尽管我们不会准备使用它直到 15 章. 现在, 能够说 struct page 是一个描述一个内存页的内部内核结构. 如同我们将见到的, 在内核中有许多地方有必要使用页结构; 它们是特别有用的, 在任何你可能处理高端内存的情况下, 高端内存在内核空间中没有一个常量地址.</p><p>Linux 页分配器的真正核心是一个称为 alloc_pages_node 的函数:</p><pre class="programlisting">struct page *alloc_pages_node(int nid, unsigned int flags, unsigned int order);</pre><p>这个函数页有 2 个变体(是简单的宏); 它们是你最可能用到的版本:</p><pre class="programlisting">struct page *alloc_pages(unsigned int flags, unsigned int order);struct page *alloc_page(unsigned int flags);</pre><p>核心函数, alloc_pages_node, 使用 3 个参数, nid 是要分配内存的 NUMA 节点 ID<sup>[<a name="id451473" href="#ftn.id451473">30</a>]</sup>, flags 是通常的 GFP_ 分配标志, 以及 order 是分配的大小. 返回值是一个指向描述分配的内存的第一个(可能许多)页结构的指针, 或者, 如常, NULL 在失败时.</p><p>alloc_pages 简化了情况, 通过在当前 NUMA 节点分配内存( 它使用 numa_node_id 的返回值作为 nid 参数调用 alloc_pages_node). 并且, 当然, alloc_pages 省略了 order 参数并且分配一个单个页. </p><p>为释放这种方式分配的页, 你应当使用下列一个:</p><pre class="programlisting">void __free_page(struct page *page);void __free_pages(struct page *page, unsigned int order);void free_hot_page(struct page *page);void free_cold_page(struct page *page);</pre><p>如果你对一个单个页的内容是否可能驻留在处理器缓存中有特殊的认识, 你应当使用 free_hot_page (对于缓存驻留的页) 或者 free_cold_page 通知内核. 这个信息帮助内存分配器在系统中优化它的内存使用.</p></div>

⌨️ 快捷键说明

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