In continuation of the previous text第三章:字符设备驱动-10:open and release--release, let's GO ahead.
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.
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 Chapters 9 and 10. Therefore, you can skip this section if you’re not interested in understanding the inner workings of the memory-oriented scull driver.
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.
The scull driver introduces two core functions used to manage memory in the Linux
kernel. These functions, defined in <linux/slab.h>, are:
在介绍 read 和 write 操作之前,我们最好先了解 scull 是如何以及为何进行内存分配的。"如何" 是理解代码的基础,而 "为何" 则展示了驱动开发者需要做出的选择(尽管 scull 作为设备并不典型)。
本节仅讨论 scull 中的内存分配策略,不涉及编写真实驱动所需的硬件管理技巧(这些技巧将在第 9 章和第 10 章介绍)。因此,如果你对这个面向内存的 scull 驱动的内部工作原理不感兴趣,可以跳过本节。
scull 使用的内存区域(也称为设备)长度是可变的:写入的数据越多,它就越大;用较短的文件覆盖设备时,会触发截断操作。
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 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 会尝试分配 size 字节的内存,返回值是指向该内存的指针;若分配失败,则返回 NULL。flags 参数用于描述内存分配的方式(我们将在第 8 章详细讨论这些标志),目前我们始终使用 GFP_KERNEL。分配的内存应使用 kfree 释放,绝不能将非 kmalloc 分配的内存传给 kfree,但向 kfree 传递 NULL 指针是合法的。
kmalloc 并不是分配大块内存最高效的方式(见第 8 章),因此 scull 选择的实现方式并不是特别智能。更高效的实现代码会更难读懂,而本节的目的是展示 read 和 write 操作,而非内存管理。这就是为什么代码仅使用 kmalloc 和 kfree,而没有采用更高效的整页分配方式。
补充说明
-
GFP_KERNEL标志的含义这是内核内存分配最常用的标志,其核心特性是:
-
scull 作为内存设备,其操作均在可睡眠上下文中执行,因此适合使用该标志。
-
只能在可睡眠的上下文中使用(如
open、read等系统调用处理过程),不能在中断处理程序等禁止睡眠的场景中使用; -
允许分配过程在内存不足时进入睡眠状态,等待系统释放足够内存;
-
-
kmalloc与用户态malloc的区别特性 kmalloc(内核态)malloc(用户态)分配粒度 最小 32 字节(依架构而定),最大通常为 128KB 字节级灵活分配 内存区域 从内核堆(slab 分配器)分配 从用户堆分配 失败处理 返回 NULL,需显式检查失败时可能触发异常(如 bad_alloc)物理连续性 保证分配的内存物理地址连续 仅保证虚拟地址连续,物理地址可能离散 -
scull 选择
kmalloc的原因尽管
kmalloc不适合大块内存,但对 scull 而言有明显优势:-
释放操作简单(单
kfree调用即可),降低示例代码复杂度。 -
分配的内存可直接访问(无需映射),简化
read/write中的数据拷贝; -
简单直观,适合作为示例驱动展示基本内存操作;
-
-
scull 的内存组织方式预告
scull 通过 “量子(quantum)” 和 “量子集(qset)” 两级结构管理内存:
-
这种结构平衡了内存利用率和管理复杂度,后续
read/write方法会基于此实现数据读写。 -
量子集:包含多个量子的数组(如 100 个量子),形成更大的内存区域;
-
量子:最小分配单位(如 4KB),对应
kmalloc分配的单个内存块;
-
技术交流,欢迎加入社区:GPUers。
1427

被折叠的 条评论
为什么被折叠?



