目录
6.3 和文件系统关联
6.3.1 inode的设备文件成员
6.3.2 标准文件操作
6.3.3 字符设备的标准操作
6.3.4 块设备的标准操作
6.4 字符设备操作
6.4.1 表示字符设备
6.4.2 打开设备文件
6.4.3 读写操作
本专栏文章将有70篇左右,欢迎+关注,查看后续文章。
6.3 和文件系统关联
普通文件和设备文件都通过相同接口访问。
6.3.1 inode的设备文件成员
每个文件都有一个inode,用于存储文件属性。
struct inode {
dev_t i_rdev;
//主,从设备号。
umode_t i_mode;
//文件类型。如socket,fifo,block,char,dir,link
struct file_operations *i_fop;
//供VFS调用,用于读写该文件。
union {
struct block_device *i_bdev;
struct cdev *i_cdev;
}
}
unsigned imajor(const struct inode *inode)
unsigned iminor(const struct inode *inode)
这两个函数可分别得到主设备号,从设备号。
6.3.2 标准文件操作
当创建设备文件时(如mknod命令),各种文件系统都调用init_special_inode,以创建inode。
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{
inode->i_mode = mode;
if (S_ISCHR(mode)) { //字符设备
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;
}
}
jffs2_mknod/ubifs_mknod/logfs_mknod:
都会调用init_special_inode。
6.3.3 字符设备的标准操作
只有一个open操作, 没有读写操作。
struct file_operations def_chr_fops = {
.open = chrdev_open,
};
chrdev_open(struct inode *inode, struct file *filp)
将调用struct file *filp->f_op->open(inode, filp),从而操作设备自身。
此处只定义一个open函数。因为其他read,write,mmap等函数通常由设备文件自定义实现。
6.3.4 块设备的标准操作
const struct file_operations def_blk_fops = {
.open = blkdev_open,
.release = blkdev_close,
.llseek = block_llseek,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = blkdev_aio_read,
.aio_write = blkdev_aio_write,
.mmap = generic_file_mmap,
.fsync = blkdev_fsync,
.unlocked_ioctl = block_ioctl,
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
};
VFS调用file_operations,而file_operations调用block_device_operations中的函数。
struct file_operations def_blk_fops:
所有块设备通用实现。
block_device_operations:
对各种块设备具体独立实现。
6.4 字符设备操作
6.4.1 表示字符设备
struct cdev {
struct kobject kobj; //内核对象
struct module *owner;
struct file_operations *ops;
struct list_head list; //连接所有表示该设备文件的inode
dev_t dev; //设备号
unsigned int count;
}
6.4.2 打开设备文件
//创建设备文件时(mknod)
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{
if (S_ISCHR(mode))
inode->i_fop = &def_chr_fops; //创建设备文件时就已经初始化好
}
const struct file_operations def_chr_fops = {
.open = chrdev_open,
.llseek = noop_llseek,
};
打开设备文件时执行chrdev_open。
int chrdev_open(struct inode *inode, struct file *filp)
{
struct cdev *cdev;
struct kobject *kobj;
int idx;
kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
//查找设备文件对应kobject。
cdev = container_of(kobj, struct cdev, kobj);
//得到struct cdev实例。
inode->i_cdev = cdev;
//保存,后续次直接用,不用查找了。
filp->f_op = fops_get(cdev->ops);
filp->f_op->open(inode, filp);
//最终调用该字符设备自定义的open函数。
return 0;
}
打开上述设备,依次对应如下函数。
创建设备文件时,创建一个struct inode。
打开设备文件时,创建一个struct file。
6.4.3 读写操作
不同设备各自实现struct file_operations中read/write函数。