scull 使用的内存区, 也称为一个设备, 长度可变. 你写的越多, 它增长越多; 通过使用 一个短文件覆盖设备来进行修整.

scull 驱动引入 2 个核心函数来管理 Linux 内核中的内存. 这些函数, 定义在

<linux/slab.h>, 是:

void *kmalloc(size_t size, int flags); void kfree(void *ptr);

对 kmalloc 的调用试图分配 size 字节的内存; 返回值是指向那个内存的指针或者如果分 配失败为 NULL. flags 参数用来描述内存应当如何分配; 我们在第 8 章详细查看这些标 志. 对于现在, 我们一直使用 GFP_KERNEL. 分配的内存应当用 kfree 来释放. 你应当从 不传递任何不是从 kmalloc 获得的东西给 kfree. 但是, 传递一个 NULL 指针给 kfree 是合法的.

kmalloc 不是最有效的分配大内存区的方法(见第 8 章), 所以挑选给 scull 的实现不是 一个特别巧妙的. 一个巧妙的源码实现可能更难阅读, 而本节的目标是展示读和写, 不是 内存管理. 这是为什么代码只是使用 kmalloc 和 kfree 而不依靠整页的分配, 尽管这个 方法会更有效.

在 flip 一边, 我们不想限制"设备"区的大小, 由于理论上的和实践上的理由. 理论上, 给在被管理的数据项施加武断的限制总是个坏想法. 实践上, scull 可用来暂时地吃光你 系统中的内存, 以便运行在低内存条件下的测试. 运行这样的测试可能会帮助你理解系统 的内部. 你可以使用命令 cp /dev/zero /dev/scull0 来用 scull 吃掉所有的真实 RAM, 并且你可以使用 dd 工具来选择贝多少数据给 scull 设备.

在 scull, 每个设备是一个指针链表, 每个都指向一个 scull_dev 结构. 每个这样的结构, 缺省地, 指向最多 4 兆字节, 通过一个中间指针数组. 发行代码使用一个 1000 个指针的 数组指向每个 4000 字节的区域. 我们称每个内存区域为一个量子, 数组(或者它的长度) 为一个量子集. 一个 scull 设备和它的内存区.

选定的数字是这样, 在 scull 中写单个一个字节消耗 8000 或 12,000 KB 内存:
4000 是 量子, 4000 或者 8000 是量子集(根据指针在目标平台上是用 32 位还是
64 位表示). 相 反, 如果你写入大量数据, 链表的开销不是太坏. 每 4 MB 数据只有一个链表元素, 设备 的最大尺寸受限于计算机的内存大小.

为量子和量子集选择合适的值是一个策略问题, 而不是机制, 并且优化的值依赖于设备如 何使用. 因此, scull 驱动不应当强制给量子和量子集使用任何特别的值. 在 scull 中, 用户可以掌管改变这些值, 有几个途径:编译时间通过改变
scull.h 中的宏

SCULL_QUANTUM 和 SCULL_QSET, 在模块加载时设定整数值 scull_quantum 和 scull_qset, 或者使用 ioctl 在运行时改变当前值和缺省值.

使用宏定义和一个整数值来进行编译时和加载时配置, 是对于如何选择主编号的回忆. 我 们在驱动中任何与策略相关或专断的值上运用这个技术.

余下的唯一问题是如果选择缺省值. 在这个特殊情况下, 问题是找到最好的平衡, 由填充 了一半的量子和量子集导致内存浪费, 如果量子和量子集小的情况下分配释放和指针连接 引起开销. 另外, kmalloc 的内部设计应当考虑进去. (现在我们不追求这点, 不过; kmalloc 的内部在第
8 章探索.) 缺省值的选择来自假设测试时可能有大量数据写进
scull, 尽管设备的正常使用最可能只传送几 KB 数据.

我们已经见过内部代表我们设备的
scull_dev 结构. 结构的 quantum 和 qset 分别代表 设备的量子和量子集大小. 实际数据, 但是, 是由一个不同的结构跟踪, 我们称为
struct scull_qset:

struct scull_qset { void **data;

struct
scull_qset *next;

};

下一个代码片段展示了实际中 struct
scull_dev 和 struct scull_qset 是如何被用来持 有数据的. sucll_trim 函数负责释放整个数据区, 由
scull_open 在文件为写而打开时调 用. 它简单地遍历列表并且释放它发现的任何量子和量子集.

int
scull_trim(struct scull_dev *dev)

{

struct
scull_qset *next, *dptr;

int
qset = dev->qset; /* "dev" is not-null */ int i;

for
(dptr = dev->data; dptr; dptr = next)

{
/* all the list items */

if
(dptr->data) {

for
(i = 0; i < qset; i++)

kfree(dptr->data[i]); kfree(dptr->data);

dptr->data
= NULL;

}

next
= dptr->next; kfree(dptr);

}

dev->size = 0;

dev->quantum
= scull_quantum; dev->qset = scull_qset;

dev->data = NULL; return 0;

}

scull_trim 也用在模块清理函数中, 来归还 scull 使用的内存给系统.

scull 的内存使用的更多相关文章

  1. linux scull 的内存使用

    在介绍读写操作前, 我们最好看看如何以及为什么 scull 进行内存分配. "如何"是需要全 面理解代码, "为什么"演示了驱动编写者需要做的选择, 尽管 sc ...

  2. Linux 设备驱动 Edition 3

    原文网址:http://oss.org.cn/kernel-book/ldd3/index.html Linux 设备驱动 Edition 3 By Jonathan Corbet, Alessand ...

  3. linux驱动开发手记【2】

    1./dev目录下,主设备号和次设备号.ls -l可以通过第一个字母是c或者b区分是字符设备或者是块设备.主设备号标识设备对应的驱动程序. 2.分配设备编号: 如果我们提前明确知道所需要的设备编号,则 ...

  4. 内存映射MMAP和DMA【转】

    转自:http://blog.csdn.net/zhoudengqing/article/details/41654293 版权声明:本文为博主原创文章,未经博主允许不得转载. 这一章介绍Linux内 ...

  5. Introduction the naive“scull” 《linux设备驱动》 学习笔记

    Introduction the naive "scull" 首先.什么是scull? scull (Simple Character Utility for Loading Lo ...

  6. Linux设备驱动程序学习之分配内存

    内核为设备驱动提供了一个统一的内存管理接口,所以模块无需涉及分段和分页等问题. 我已经在第一个scull模块中使用了 kmalloc 和 kfree 来分配和释放内存空间. kmalloc 函数内幕 ...

  7. 《Linux设备驱动程序》编译LDD3的scull驱动问题总结***

    由于Linux内核版本更新的原因,LDD3(v2.6.10)提供的源码无法直接使用,下面是本人编译scull源码时出现的一些问题及解决方法.编译环境:Ubuntu 10.04 LTS(kernel v ...

  8. linux scull 中的读写代码

    读和写方法都进行类似的任务, 就是, 从和到应用程序代码拷贝数据. 因此, 它们的原型 相当相似, 可以同时介绍它们: ssize_t read(struct file *filp, char   u ...

  9. linux scull 的设计

    编写驱动的第一步是定义驱动将要提供给用户程序的能力(机制).因为我们的"设备"是计算 机内存的一部分, 我们可自由做我们想做的事情. 它可以是一个顺序的或者随机存取的设 备, 一个 ...

随机推荐

  1. NX二次开发-UFUN适应窗口UF_VIEW_fit_view

    NX9+VS2012 #include <uf.h> #include <uf_view.h> #include <uf_modl.h> UF_initialize ...

  2. NX二次开发-UFUN遍历图层UF_LAYER_cycle_by_layer

    NX11+VS2013 #include <uf.h> #include <uf_layer.h> #include <uf_ui.h> UF_initialize ...

  3. NX二次开发-bat脚本文件切换NX的环境变量(NX路径和语言)

    路径环境变量切换到NX9.bat @echo off setx /M UGII_BASE_DIR "D:\Program Files\Siemens\NX 9.0" ------- ...

  4. <转载>深入 理解char * ,char ** ,char a[ ] ,char *a[] 的区别

    C语言中由于指针的灵活性,导致指针能代替数组使用,或者混合使用,这些导致了许多指针和数组的迷惑,因此,刻意再次深入探究了指针和数组这玩意儿,其他类型的数组比较简单,容易混淆的是字符数组和字符指针这两个 ...

  5. Spring-Security (学习记录四)--配置权限过滤器,采用数据库方式获取权限

    目录 1. 需要在spring-security.xml中配置验证过滤器,来取代spring-security.xml的默认过滤器 2. 配置securityMetadataSource,可以通过ur ...

  6. C++之内存分区

  7. (转)AttributeError: module 'tkinter' has no attribute 'messagebox'

    AttributeError: module 'tkinter' has no attribute 'messagebox' improt tkinter from tkinter import * ...

  8. Day 11:函数装饰器

    在说装饰器前,先说一个东西,再Python里,有一个 一切皆对象,一切皆变量. 例: def hello(name="sunjinyao"): return "hi &q ...

  9. USACO2007 Protecting the Flowers /// 比值 前缀和 oj21161

    题目大意: 有N (2 ≤ N ≤ 100,000) 头牛偷吃花 将牛赶回牛棚需Ti minutes (1 ≤ Ti ≤ 2,000,000) 每头牛每分钟能吃Di (1 ≤ Di ≤ 100) 朵花 ...

  10. USACO2008 Cow Cars /// oj23323

    题目大意: N (1 ≤ N ≤ 50,000)头牛被编号为1-N,牛i可以在M(1 ≤ M ≤ N)条不同的高速路上以Si (1 ≤ Si ≤ 1,000,000) km/h的速度飞驰 为了避免相撞 ...