文章目录
-
- 一、mknod引入
- 二、mknod 工作流程
- 三、要点
一、mknod引入
用于创建指定类型的特殊文件。
一般流程是创建一个设备文件,然后根据 mknod 指令中的设备号,将
struct inode
和
cdev_map->probes->cdev->file_operations
绑定起来。
查看 mknod 指令使用帮助:
mknod --help
用法:mknod [选项]... 文件名称 类型 [主设备号 次设备号]
Create the special file NAME of the given TYPE.
...
当类型为"p"时可不指定主设备号和次设备号,否则它们是必须指定的。
如果主设备号和次设备号以"0x"或"0X"开头,它们会被视作十六进制数来解析;
如果以"0"开头,则被视作八进制数;其余情况下被视作十进制数。
可用的类型包括:
b 创建(有缓冲的)区块特殊文件
c, u 创建(没有缓冲的)字符特殊文件
p 创建先进先出(FIFO)特殊文件
如:
mkmod /dev/test c 2 0
可以自己编写一个设备驱动模块,加载后使用
cat /proc/devices
查看主设备号。
再使用 mknod 创建一个文件,要求主设备号相同,次设备号相同或者在范围内。 file_operation 复制成功。
二、mknod 工作流程

ext4_mknod:新创建一个 inode 节点。
init_special_inode函数分析
定义在:
/fs/inode.c
函数主要操作:判断文件类型,如果是
字符设备类型
,则把
def_chr_fops
作为该文件的操作接口,并把设备号记录在
inode->i_rdev
。
/* inode:新创建的 inode 节点。
* mode:文件的读写权限。
* rdev:设备文件关联的主次设备号,是在shell调用mknod命令传参进来的。
*/
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{
inode->i_mode = mode;
if (S_ISCHR(mode)) { /* 判断文件是否属于字符设备,可由 mknod 指定 */
/* 设置文件的操作接口。
* def_chr_fops 是字符设备通用的文件操作接口,详见下一个代码块。
*/
inode->i_fop = &def_chr_fops;
/* 设置设备号,由参数传进来 */
inode->i_rdev = rdev;
} else if (S_ISBLK(mode)) { /* 判断是否是块设备 */
inode->i_fop = &def_blk_fops;
inode->i_rdev = rdev;
} else if (S_ISFIFO(mode)) /* 判断是否是管道类型 */
inode->i_fop = &pipefifo_fops;
else if (S_ISSOCK(mode))
; /* leave it no_open_fops */
else
printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
" inode %s:%lu\n", mode, inode->i_sb->s_id,
inode->i_ino);
}
EXPORT_SYMBOL(init_special_inode);
结构体
def_chr_fops
定义在
fs/chr_dev.c
*
* 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 = {
/* 在此函数绑定自定义的file_operations到文件中 */
.open = chrdev_open,
.llseek = noop_llseek,
};
函数
chrdev_open
定义在
fs/chr_dev.c
/*
* Called every time a character special file is opened
*/
static int chrdev_open(struct inode *inode, struct file *filp)
{
const struct file_operations *fops;
struct cdev *p;
struct cdev *new = NULL;
int ret = 0;
spin_lock(&cdev_lock);
p = inode->i_cdev;
if (!p) {
struct kobject *kobj;
int idx;
spin_unlock(&cdev_lock);
kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
if (!kobj)
return -ENXIO;
new = container_of(kobj, struct cdev, kobj);
spin_lock(&cdev_lock);
/* Check i_cdev again in case somebody beat us to it while
we dropped the lock. */
p = inode->i_cdev;
if (!p) {
inode->i_cdev = p = new;
list_add(&inode->i_devices, &p->list);
new = NULL;
} else if (!cdev_get(p))
ret = -ENXIO;
} else if (!cdev_get(p))
ret = -ENXIO;
spin_unlock(&cdev_lock);
cdev_put(new);
if (ret)
return ret;
ret = -ENXIO;
fops = fops_get(p->ops);
if (!fops)
goto out_cdev_put;
/* 在此处完成自定义fops的绑定 */
replace_fops(filp, fops);
if (filp->f_op->open) {
ret = filp->f_op->open(inode, filp);
if (ret)
goto out_cdev_put;
}
return 0;
out_cdev_put:
cdev_put(p);
return ret;
}
三、要点
struct inode
中的 成员变量
file_operation
一开始并不是自己构造的
file_operation
,而是字符设备通用的
def_chr_fops
。
在应用程序对此文件进行 open 操作后,会执行
def_chr_fops->open
,在此函数中完成对
struct inode
和
设备号对应cdev_map->probes 哈希表中的 cdev->file_operation
进行配对。