The release Method

news2025/1/23 0:58:59

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 使用的内存返回给系统。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/105439.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

跟我学 UML 系统建模

UML 系统建模 1 概述 1.1 课程概述 汇集 UML 及其相关的一些话题回顾 UML 相关的符号与概念以电商订单相关业务为例&#xff0c;借助 UML 完成系统建模将 UML 变成提升建模效率&#xff0c;表达架构思想的工具 1.2 什么是 UML ​ Unified Modeling Language 统一建模语言&a…

Leetcode-1753-移除石子的最大得分

1、堆 我们可以维护一个大顶堆&#xff0c;其中储存了三个石子堆中石子的个数。为了确保我们的分数尽可能大&#xff0c;我们每次都需要从最大的两个堆中取出石子。因此我们不断循环&#xff0c;每次都从当前最大的堆中取出石子。值得注意的是&#xff0c;为了确保能够发现游戏…

数据管理篇之存储和成本管理

第14章 存储和成本管理 目标&#xff1a;有效的降低存储资源的消耗&#xff0c;节省存储成本。 1.数据压缩 问题 在分布式文件系统中&#xff0c;为了提高数据的可用性与性能 &#xff0c;通常会将数据存储3份&#xff0c;这就意味着存储 1TB 的逻辑数据&#xff0c; 实际上…

iOS自动化真机测试验证环境过程中常见问题解析

本文节选自霍格沃兹测试学院内部教材 本章节主要讲解 iOS 自动化真机配置以及在 iOS 真机执行自动化时常见问题与解决方法。 真机使用的Capability 与模拟器不同&#xff0c;真机测试需要如下的 Capability 方式一&#xff1a;设置 App 路径&#xff0c;启动 App&#xff08;自…

SpringBoot项目开启远程调试

1、服务端设置 cat start.sh #!/bin/bash echo "i will start the program!" java -jar -Xdebug -Xrunjdwp:transportdt_socket,servery,address9999 xxxxx-SNAPSHOT.jar --server.port10991 echo "start success" 2、开发工具设置 3、然后&#…

计算机网络~计算机网络体系结构

一、计算机网络的概念和功能 1. 计算机网络 是一个将分散的、具有独立功能的计算机系统&#xff0c;通过通信设备与线路连接起来&#xff0c;由功能完善的软件实现资源共享和信息传递的系统计算机网络是互联的、自治的计算机集合 互联&#xff1a;通过通信链路互联互通自治&a…

π120M30 双通道数字隔离器兼容ADuM3210TRZ 广泛应用于工业自动化系统方案

π120M30 双通道数字隔离器兼容ADuM3210TRZ 广泛应用于工业自动化系统方案 。具有出色的性能特征和可靠性&#xff0c;整体性能优于光耦和基于其他原理的数字隔离器产品。传输通道间彼此独立&#xff0c;可实现多种传输方向的配置&#xff0c;可实现 3.0kV rms 隔离耐压等级和 …

【Java语言】— 类型转换

1.类型转换 &#xff08;1&#xff09;自动类型转换 类型范围小的变量&#xff0c;可以直接赋值给类型范围大的变量。 ①自动类型转换的底层原理 ②自动类型转换的其他形式 &#xff08;2&#xff09;表达式的自动类型转换 在表达式中&#xff0c;小范围类型的变量会自动转…

python之序列反转

python之序列反转 方式1&#xff1a;.reverse() a [1, 2, 3, 4, 5] print(a.reverse()) # None&#xff0c;函数原地反转&#xff0c;不具备排序功能&#xff0c;而且没有返回值 print(a) # [5, 4, 3, 2, 1]方式2&#xff1a;reversed a [1, 2, 3, 4, 5] print(reversed…

2021年全国职业院校技能大赛网络搭建与应用赛项——国赛组播题

2021年全国职业院校技能大赛网络搭建与应用赛项——国赛组播题 sw1:# ip pim multicast-routing &#xff08;开启组播模式&#xff0c;在全局模式&#xff09; int vlan 10 ip pim dense-mode &#xff08;在接口模式下开启组播-密集模式协议&#xff09; ip igmp version 2 i…

正大国际期货:恒指德指交易导致亏损的原因是什么?

在交易过程中&#xff0c;经常会遇到我们事先对这次的交易进行了详细的分析推理&#xff0c;还制定了周密可行的策略&#xff0c;但真正落实到交易活动过程中却变得面目全非&#xff0c;屡屡败退&#xff0c;让我们措手不及这样的现象&#xff0c;是什么原因导致&#xff1f;正…

如何开通 API 服务并授予项目 API 服务的调用权限

涂鸦 IoT 开发平台开放多种业务 API 服务&#xff0c;全面覆盖全屋智能管理、行业通用设备用户管理、垂直品类开放能力、各类数据服务等业务需求。 本文将为大家介绍如何开通 API 服务并授予项目 API 服务的调用权限。 个人数据隐私声明 开发者调用的部分 云服务 API 会获取用…

链表(2)------数据结构

1)进行反转单链表:节点的值不发生改变&#xff0c;只需要进行修改节点的指向 进行测试的时候要给方法传入一个头结点 输入:1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff1b; 输出:5&#xff0c;4&#xff0c;3&#xff0c;2&#xff0c;1&#xff1b; 1)我…

从0到1介绍一下开源大数据比对平台dataCompare

1.背景&现状 在大数据领域也已经工作了多年&#xff0c;无论所待过的大公司还是小公司&#xff0c;都会遇到集群升级迁移过程中据搬迁等相关工作&#xff0c;经常会碰到搬迁之后&#xff0c;搬迁的数据是不是能对的上呢&#xff1f;两边数据究竟是不是一致的呢&#xff1f…

javaee之Mybatis4

延迟加载与立即加载的概念 Mybatis中的延迟加载与立即加载 一、一对一实现延迟加载的步骤&#xff08;多对一&#xff0c;看成一对一&#xff09; 我们这里是利用account表中的一个方法来做 先来看IAccountDao里面的一个方法 然后再去看持久层IAccountDao.xml 这个方法给我们…

Linux学习-92-SELinux管理

18 SELinux管理 root 用户在 Linux 系统当中就是无所不能的&#xff0c;而且读、写和执行权限对 root 用户完全没有作用。root 用户的存在极大地方便了 Linux 的管理&#xff0c;但是也造成了一定的安全隐患。绝大多数系统的严重错误都是由于 root 用户的误操作引起的&#xff…

开源项目 Spartacus 的 git 分支使用规范

Spartacus 开源项目里存在如下的 git 分支&#xff1a; feature/GH-xxxx 分支用于简单的功能和错误修复epic/epic-name 分支用于大功能的开发release/1.4.0-rc.0 分支用于特定的发布&#xff08;你可以将它们与维护分支区分开来&#xff0c;因为包含了完整的版本号&#xff09…

压力测试笔记

压测学习 要求&#xff1a;满足100并发500ms性能要求 压测场景 新系统上线支持 在新系统上线前&#xff0c;通过执行性能压测能够对系统的负载能力有较为清晰的认知&#xff0c;从而结合预估的潜在用户数量保障系统上线后的用户体验。技术升级验证 在系统重构过程中&#xf…

Github每日精选(第80期):自动生成命令行python-fire

Python Fire 是一个用于从绝对任何Python对象自动生成命令行界面 (CLI) 的库。 Python Fire 是一种在 Python 中创建 CLI 的简单方法。 [1]Python Fire 是用于开发和调试 Python 代码的有用工具。 [2]Python Fire 有助于探索现有代码或将其他人的代码转换为 CLI。[3]Python Fi…

Co-Scale Conv-Attentional Image Transformers

Co-Scale Conv-Attentional Image Transformers一、引言二、实现方法&#xff08;一&#xff09;、Conv-Attention Module三、Co-Scale Conv-Attentional Transformers&#xff08;一&#xff09;、Co-Scale串行块&#xff08;二&#xff09;、Co-Scale并行块&#xff08;三&am…