The release Method

The role of the release method is the reverse of open. Sometimes you'll find that the method implementation is called device_close instead of device_release. Either way, the device method should perform the following tasks: 释放方法的作用与打开相反。 有时你会发现方法实现被称为 device_close 而不是 device_release。 无论哪种方式,设备方法都应该执行以下任务:

Deallocate anything that open allocated in filp->private_data解除分配在 filp->private_data 中打开的所有内容

Shut down the device on last close在最后一次关闭时关闭设备

The basic form of scull has no hardware to shut down, so the code required is minimal:[7] scull 的基本形式没有要关闭的硬件,因此所需的代码很少:[7]

int scull_release(struct inode *inode, struct file *filp) {

return 0;

}

You may be wondering what happens when a device file is closed more times than it is opened. After all, the dup and fork system calls create copies of open files without calling open; each of those copies is then closed at program termination. For example, most programs don't open their stdin file (or device), but all of them end up closing it. How does a driver know when an open device file has really been closed? 您可能想知道当设备文件关闭的次数多于打开的次数时会发生什么。 毕竟,dup 和 fork 系统调用创建打开文件的副本而不调用 open; 然后在程序终止时关闭这些副本中的每一个。 例如,大多数程序不会打开它们的标准输入文件(或设备),但最终都会关闭它。 驱动程序如何知道打开的设备文件何时真正关闭?

The answer is simple: not every close system call causes the release method to be invoked. Only the calls that actually release the device data structure invoke the method—hence its name. The kernel keeps a counter of how many times a file structure is being used. Neither fork nor dup creates a new file structure (only open does that); they just increment the counter in the existing structure. The close system call executes the release method only when the counter for the file structure drops to 0, which happens when the structure is destroyed. This relationship between the release method and the close system call guarantees that your driver sees only one release call for each open. 答案很简单:不是每个 close 系统调用都会调用 release 方法。 只有真正释放设备数据结构的调用才会调用该方法——因此得名。 内核会记录一个文件结构被使用了多少次。 fork 和 dup 都不会创建新的文件结构(只有 open 会这样做); 他们只是增加现有结构中的计数器。 只有当文件结构的计数器下降到 0 时,close 系统调用才会执行 release 方法,这发生在结构被破坏时。 释放方法和关闭系统调用之间的这种关系保证了您的驱动程序在每次打开时只看到一个释放调用。

Note that the flush method is called every time an application calls close. However, very few drivers implement flush, because usually there's nothing to perform at close time unless release is involved. 请注意,每次应用程序调用 close 时都会调用 flush 方法。 然而,很少有驱动程序实现flush,因为除非涉及release,否则通常没有什么可以在close时执行。

As you may imagine, the previous discussion applies even when the application terminates without explicitly closing its open files: the kernel automatically closes any file at process exit time by internally using the close system call. 正如您可能想象的那样,即使应用程序在没有显式关闭其打开的文件的情况下终止,前面的讨论也适用:内核通过内部使用 close 系统调用在进程退出时自动关闭任何文件。

scull's Memory Usage

Before introducing the read and write operations, we'd better look at how and why scull performs memory allocation. "How" is needed to thoroughly understand the code, and "why" demonstrates the kind of choices a driver writer needs to make, although scull is definitely not typical as a device. 在介绍读写操作之前,我们最好先看看 scull 是如何以及为什么执行内存分配的。 需要“如何”来彻底理解代码,“为什么”说明驱动程序编写者需要做出的选择,尽管 scull 绝对不是典型的设备。

This section deals only with the memory allocation policy in scull and doesn't show the hardware management skills you need to write real drivers. These skills are introduced in Chapter 9 and Chapter 10. Therefore, you can skip this section if you're not interested in understanding the inner workings of the memory-oriented scull driver. 本节仅涉及 scull 中的内存分配策略,不展示编写真正驱动程序所需的硬件管理技能。 这些技巧在第 9 章和第 10 章中介绍。因此,如果您对了解面向内存的 scull 驱动程序的内部工作不感兴趣,可以跳过本节。

The region of memory used by scull, also called a device, is variable in length. The more you write, the more it grows; trimming is performed by overwriting the device with a shorter file. scull 使用的内存区域(也称为设备)的长度是可变的。 你写得越多,它就增长得越多; 修剪是通过用较短的文件覆盖设备来执行的。

The scull driver introduces two core functions used to manage memory in the Linux kernel. These functions, defined in <linux/slab.h>, are: scull 驱动程序引入了两个用于在 Linux 内核中管理内存的核心函数。 这些在 <linux/slab.h> 中定义的函数是:

void *kmalloc(size_t size, int flags);

void kfree(void *ptr);

A call to kmalloc attempts to allocate size bytes of memory; the return value is a pointer to that memory or NULL if the allocation fails. The flags argument is used to describe how the memory should be allocated; we examine those flags in detail in Chapter 8. For now, we always use GFP_KERNEL. Allocated memory should be freed with kfree. You should never pass anything to kfree that was not obtained from kmalloc. It is, however, legal to pass a NULL pointer to kfree. 对 kmalloc 的调用尝试分配 size 字节的内存; 返回值是指向该内存的指针,如果分配失败,则返回 NULL。 flags 参数用于描述应该如何分配内存; 我们将在第 8 章详细检查这些标志。目前,我们总是使用 GFP_KERNEL。 分配的内存应该用 kfree 释放。 你不应该将任何不是从 kmalloc 获得的东西传递给 kfree。 但是,将 NULL 指针传递给 kfree 是合法的。

kmalloc is not the most efficient way to allocate large areas of memory (see Chapter 8), so the implementation chosen for scull is not a particularly smart one. The source code for a smart implementation would be more difficult to read, and the aim of this section is to show read and write, not memory management. That's why the code just uses kmalloc and kfree without resorting to allocation of whole pages, although that approach would be more efficient. kmalloc 不是分配大块内存的最有效方式(参见第 8 章),因此为 scull 选择的实现并不是特别聪明。 智能实现的源代码会更难阅读,本节的目的是展示读写,而不是内存管理。 这就是为什么代码只使用 kmalloc 和 kfree 而不诉诸整个页面的分配,尽管这种方法会更有效。

On the flip side, we didn't want to limit the size of the "device" area, for both a philosophical reason and a practical one. Philosophically, it's always a bad idea to put arbitrary limits on data items being managed. Practically, scull can be used to temporarily eat up your system's memory in order to run tests under low-memory conditions. Running such tests might help you understand the system's internals. You can use the command cp /dev/zero /dev/scull0 to eat all the real RAM with scull, and you can use the dd utility to choose how much data is copied to the scull device. 另一方面,出于哲学和实际原因,我们不想限制“设备”区域的大小。 从哲学上讲,任意限制要管理的数据项总是一个坏主意。 实际上, scull 可用于暂时消耗系统内存,以便在低内存条件下运行测试。 运行此类测试可能会帮助您了解系统的内部结构。 您可以使用命令 cp /dev/zero /dev/scull0 用 scull 吃掉所有真实 RAM,并且可以使用 dd 实用程序来选择将多少数据复制到 scull 设备。

In scull, each device is a linked list of pointers, each of which points to a scull_dev structure. Each such structure can refer, by default, to at most four million bytes, through an array of intermediate pointers. The released source uses an array of 1000 pointers to areas of 4000 bytes. We call each memory area a quantum and the array (or its length) a quantum set. A scull device and its memory areas are shown in Figure 3-1. 在 scull 中,每个设备都是一个指针链表,每个指针指向一个 scull_dev 结构。 默认情况下,每个这样的结构可以通过中间指针数组引用最多四百万字节。 发布的源代码使用一个包含 1000 个指针的数组,指向 4000 字节的区域。 我们称每个内存区域为一个量子,而数组(或其长度)为一个量子集。 scull 设备及其内存区域如图 3-1 所示。

Figure 3-1. The layout of a scull device

The chosen numbers are such that writing a single byte in scull consumes 8000 or 12,000 thousand bytes of memory: 4000 for the quantum and 4000 or 8000 for the quantum set (according to whether a pointer is represented in 32 bits or 64 bits on the target platform). If, instead, you write a huge amount of data, the overhead of the linked list is not too bad. There is only one list element for every four megabytes of data, and the maximum size of the device is limited by the computer's memory size. 选择的数字使得在 scull 中写入单个字节会消耗 8000 或 12,000,000 字节的内存:4000 用于量子,4000 或 8000 用于量子集(根据指针在目标上是用 32 位还是 64 位表示) 平台)。 相反,如果您写入大量数据,则链表的开销并不算太糟糕。 每四兆字节的数据只有一个列表元素,设备的最大大小受计算机内存大小的限制。

Choosing the appropriate values for the quantum and the quantum set is a question of policy, rather than mechanism, and the optimal sizes depend on how the device is used. Thus, the scull driver should not force the use of any particular values for the quantum and quantum set sizes. In scull, the user can change the values in charge in several ways: by changing the macros SCULL_QUANTUM and SCULL_QSET in scull.h at compile time, by setting the integer values scull_quantum and scull_qset at module load time, or by changing both the current and default values using ioctl at runtime. 为量子和量子集选择合适的值是一个策略问题,而不是机制问题,最佳尺寸取决于设备的使用方式。 因此,scull 驱动程序不应强制对量程和量程集大小使用任何特定值。 在 scull 中,用户可以通过多种方式更改负责的值:通过在编译时更改 scull.h 中的宏 SCULL_QUANTUM 和 SCULL_QSET,通过在模块加载时设置整数值 scull_quantum 和 scull_qset,或者通过同时更改当前和 在运行时使用 ioctl 的默认值。

Using a macro and an integer value to allow both compile-time and load-time configuration is reminiscent of how the major number is selected. We use this technique for whatever value in the driver is arbitrary or related to policy. 使用宏和整数值来允许编译时和加载时配置让人想起如何选择主编号。 我们将这种技术用于驱动程序中任意或与策略相关的任何值。

The only question left is how the default numbers have been chosen. In this particular case, the problem is finding the best balance between the waste of memory resulting from half-filled quanta and quantum sets and the overhead of allocation, deallocation, and pointer chaining that occurs if quanta and sets are small. Additionally, the internal design of kmalloc should be taken into account. (We won't pursue the point now, though; the innards of kmalloc are explored in Chapter 8.) The choice of default numbers comes from the assumption that massive amounts of data are likely to be written to scull while testing it, although normal use of the device will most likely transfer just a few kilobytes of data. 剩下的唯一问题是如何选择默认数字。 在这种特殊情况下,问题是在由半填充的量子和量子集导致的内存浪费与如果量子和集合很小时发生的分配、释放和指针链接的开销之间找到最佳平衡。 此外,还应考虑 kmalloc 的内部设计。 (不过,我们现在不会追究这一点;kmalloc 的内部结构将在第 8 章中进行探讨。)默认数字的选择来自这样一种假设,即在测试时可能会写入大量数据来 scull,尽管这是正常的 使用该设备很可能只传输几千字节的数据。

We have already seen the scull_dev structure that represents our device internally. That structure's quantum and qset fields hold the device's quantum and quantum set sizes, respectively. The actual data, however, is tracked by a different structure, which we call struct scull_qset : 我们已经看到了在内部代表我们设备的 scull_dev 结构。 该结构的quantum 和qset 字段分别保存设备的quantum 和quantum set 大小。 然而,实际数据由不同的结构跟踪,我们称之为 struct scull_qset :

struct scull_qset {

void **data;

struct scull_qset *next;

};

The next code fragment shows in practice how struct scull_dev and struct scull_qset are used to hold data. The function scull_trim is in charge of freeing the whole data area and is invoked by scull_open when the file is opened for writing. It simply walks through the list and frees any quantum and quantum set it finds. 下一个代码片段在实践中展示了如何使用 struct scull_dev 和 struct scull_qset 来保存数据。 函数 scull_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 is also used in the module cleanup function to return memory used by scull to the system. scull_trim 还用于模块清理函数中,将 scull 使用的内存返回给系统。

The release Method相关推荐

  1. python 示例_Python条件类| release()方法与示例

    python 示例 Python Condition.release()方法 (Python Condition.release() Method) release() is an inbuilt m ...

  2. Java项目:课程资源管理+在线考试平台(java+SSH+mysql+maven+tomcat)

    源码获取:博客首页 "资源" 里下载! 一.项目简述 功能包括: 管理员可以增删改查教材.教材商.入库教材.用户(用 户包括学生和教师)可以对教材商.教材进行.xcel的导入 导出 ...

  3. (转)iPhone开发经典语录集锦

    1:如果无法保证子类行为的一致性,那么就用委托 If the subClass cann't keep with superClass,use delegate rather than inherit ...

  4. 一文详解CMakeLists文件编写语法规则详解

    作者丨zhanghm1995@blog 来源丨https://blog.csdn.net/zhanghm1995/article/details/80902807 编辑丨3D视觉工坊 基本语法规则 C ...

  5. python --- 基础多线程编程

    在python中进行多线程编程之前必须了解的问题: 1. 什么是线程? 答:线程是程序中一个单一的顺序控制流程.进程内一个相对独立的.可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程 ...

  6. iOS开发 小知识点

    退回输入键盘: - (BOOL) textFieldShouldReturn:(id)textField{[textField resignFirstResponder]; } CGRect CGRe ...

  7. Java多线程之JUC包:Semaphore源码学习笔记

    若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/go2sea/p/5625536.html Semaphore是JUC ...

  8. 避免Castle Windsor引起的内存泄露

    原文地址: http://nexussharp.wordpress.com/2012/04/21/castle-windsor-avoid-memory-leaks-by-learning-the-u ...

  9. AbstractQueuedSynchronizer浅析——同步

    2019独角兽企业重金招聘Python工程师标准>>> 想研究并发编程快一年了,一直断断续续,没有重点,无所收获.写此文,以明志! LockSupport,以后要重点看一下,在par ...

最新文章

  1. Binder跨进程通信原理(三):Binder IPC实现原理
  2. mysql中事务的启动方式
  3. html input type=file 文件上传; 图片上传; 图片闪烁
  4. antd 怎么用ajax,react+dva+antd接口调用方式
  5. win8学习--------计时器
  6. 多线程编程之Apue3rd_Chapter11之互斥锁_读写锁_自旋锁
  7. 攻击者可武器化防火墙和中间系统,执行 DDoS 放大攻击
  8. 深度学习2.0-36.循环神经网络RNN-时间序列表示方法
  9. 大学学习历程简单总结
  10. 奥斯汀页眉怎么设置_wps怎么只删除本页的页眉_Word页眉的设置和删除,这些问题你有遇到过吗?...
  11. 九宫格按键输入(java)
  12. Java String、StringBuffer和StringBuilder的区别
  13. C Primer Plus(6) 中文版 第5章 运算符、表达式和语句 5.5 类型转换
  14. Python 三维动画生成 绘制螺旋线
  15. elementUI:阻止form的enter(回车键)事件
  16. css3探测光圈_CSS3按钮鼠标悬浮实现光圈效果
  17. WooCommerce Product Feed指南 – Google Shopping和Facebook[2022]
  18. 为什么快捷指令无法将媒体转换为文本_全知乎最全!iOS“捷径(快捷指令)”应用进阶教程 (附入门教程链接)...
  19. perl Carp模块使用举例(转)
  20. 「蚂蚁金服」热搜的背后:「李开复」到底是不是口误?

热门文章

  1. 双重差分法之安慰剂检验
  2. 标志寄存器的状态标志
  3. 如何从Windows 10注销其他用户
  4. python plt绘制多子图
  5. B端产品的特点及开发经验
  6. 灵魂歌手 演唱:梁博
  7. “区块链技术创新要植根市场”
  8. 政策重大升级、成立最强行业联盟,上海要做长三角区块链产业发展领头羊?...
  9. style=扑克牌游戏大家应该都比较熟悉了,一副牌由54张组成,含3~A、2各4张,小王1张,大王1张。 牌面从小到大用如下字符和字符串表示(其中,小写joker表示小王,大写JOKER表示大
  10. 下载!《Nacos 架构与原理》pdf