当前位置:首页>Linux>Linux设备文件节点是怎么生成

Linux设备文件节点是怎么生成

  • 2026-10-26 11:11:51
Linux设备文件节点是怎么生成
大家好,我是王鸽,今天这篇文章主要是讲解Linux设备文件节点是怎么生成?调用的函数是怎么样的?

在Linux系统下,设备文件是种特殊的文件类型,其存在的主要意义是沟通用户空间程序和内核空间驱动程序。换句话说,用户空间的应用程序要想使用驱动程序提供的服务,需要经过设备文件来达成。

当然,如果你的驱动程序只是为内核中的其他模块提供服务,则没有必要生成对应的设备文件。

按照通用的规则,Linux系统所有的设备文件都位于/dev目录下。/dev目录在Linux系统中算是一个比较特殊的目录,在Linux系统早期还不支持动态生成设备节点时,/dev目录就是挂载的根文件系统下的/dev,对这个目录下所有文件的操作使用的是根文件系统提供的接口。比如,如果 Linux系统挂载的根文件系统是ext3,那么对/dev目录下所有目录/文件的操作都将使用ext3 文件系统的接口。

随着后来Linux内核的演进,开始支持动态设备节点的生成”,使得系统在启动过程中会自动生成各个设备节点,这就使得/dev目录不必要作为一个非易失的文件系统的形式存在。因此,当前的Linux内核在挂载完根文件系统之后,会在这个根文件系统的/dev目录上重新挂载一个新的文件系统devtmpfs,后者是个基于系统RAM的文件系统实现。当然,对动态设备节点生成的支持并不意味着一定要将根文件系统中的/dev 目录重新挂载到一个新的文件系统上,事实上动态生成设备节点技术的重点并不在文件系统上面。

目前先假定设备节点是通过 Linux 系统下的mknod 命令静态创建。为方便叙述,下面用一个具体的例子来描述设备文件产生过程中的一些关键要素,这个例子的任务很简单:在一个ext3类型的根文件系统中的/dev目录下用mknod命令来创建一个新的设备文件节点demodev,对应的驱动程序使用的设备主设备号为2,次设备号是0,命令形式为

创建字符设备(需 root 权限)

sudo mknod /dev/demodev c

mknod  /dev/demodev c 2 0

上述命令成功执行后,将会在/dev目录下生成一个名为demodev的字符设备节点。如果用strace 工具来跟踪一下上面的命令,会发现如下输出(删去了若干不相关部分):

sudo strace mknod /dev/demodev c 2 0

设备文件类型

类型
标识符
特点
示例设备
字符设备
c
按字节流访问,无缓存
/dev/tty, /dev/null
块设备
b
按数据块访问,带缓存
/dev/sda, /dev/nvme0n1

内核打印:

execve("/bin/mknod", ["mknod", "/dev/demodev", "c", "2", "0"], ...) = 0...mknod("/dev/demodev", S_IFCHR|0666, makedev(2, 0)) = -1 EPERM (Operation not permitted)...write(2, "mknod: /dev/demodev: Operation not permitted\n", ...) = 45exit_group(1)

cat /proc/devices

可见 Linux 下的 mknod 命令最终是通过调用 mknod 函数来实现的,调用时的重要参数有两个,一是设备文件名("/dev/demodev"),二是设备号(makedev(2,0))。设备文件名主要在用户空间使用(比如用户空间程序调用open函数时),而内核空间则使用inode 来表示相应的文件。本书只关注内核空间的操作,对于前面的mknod命令,它将通过系统调用sys_mknod进入内核空间,这个系统调用的原型是:

asmlinkage long sys_mknod(const char __user *filename, umode_t mode,unsigned dev);

注意: sys_mknod 的最后一个参数 dev,它是由用户空间的 mknod 命令构造出的设备号。sys_mknod 系统调用将通过/dev 目录上挂载的文件系统接口来为/dev/demodev 生成一个新的inode,设备号将被记录到这个新的inode 对象上。

展示了通过ext3 文件系统在/dev目录下生成一个新的设备节点/dev/demodev 的主要流程。

sys_mknod 首先在根文件系统ext3的根目录“/”下寻找 dev 目录所对应的inode,图中对应的inode 编号为168,ext3 文件系统的实现会通过某种映射机制,通过inode 编号最终得到该inode在内存中的实际地址(图中由标号1的线段表示)。接下来会通过dev的inode结构中的i_op成员指针所指向的ext3_dir_inode_operations(这是个 struct inode_operations类型的指针),来调用该对象中的mknod方法,这将导致ext3mknod 函数被调用。
ext3 mknod 函数的主要作用是生成一个新的inode(用来在内核空间表示 demodev 设备文件节点,demodev设备节点文件与新生成的inode 之间的关联在上图中由标号5的线段表示)。在 ext3 mknod 中会调用一个和设备驱动程序关系密切的init_special_inode 函数,其定义如下:
这个函数最主要的功能便是为新生成的inode 初始化其中的i_fop和i_rdev成员。设备文件节点inode 中的i_rdev成员用来表示该inode 所对应设备的设备号,通过参数 rdev 为其赋值。设备号在由sysmknod发起的整个内核调用链中进行传递,最早来自于用户空间的mknod 命令行参数。
i_fop成员的初始化根据是字符设备还是块设备而有不同的赋值。对于字符设备,fop指向def_chr_fops,后者主要定义了一个 open 操作:
/* * Dummy default file-operations: the only thing this does * is contain the open that then fills in the correct operations * depending on the special file... */const struct file_operations def_chr_fops = { .open = chrdev_open, .llseek = noop_llseek,};

相对于字符设备,块设备的def_blk_fops的定义则要有点复杂:

字符设备 inode 中的i_fop 指向 def_chr_fops。

谢谢阅读收藏点赞!

最新文章

随机文章