linux内核 之struct file、struct inode、struct file_operations、struct cdev之间的关系

本文深入解析Linux内核中字符设备的实现机制,包括structcdev、structfile_operations等关键数据结构的作用及其相互间的关系,帮助读者理解字符设备的底层原理。


                       struct cdev与struct file_operations的关系


                             各种数据结构之间的关系




struct file:(表示已打开的文件)

(路径:linux-3.13.10\include\linux\fs.h)

(描述进程中打开的文件,进程中只要调用了open就有一个该对象。具体描述了打开文件的路径,权限,标志,内部偏移。file结构体是用来维护打开的文件的

struct file {

union {
struct llist_node fu_llist;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
#define f_dentry f_path.dentry
struct inode *f_inode; /* cached value */
const struct file_operations *f_op;


/*
* Protects f_ep_links, f_flags, f_pos vs i_size in lseek SEEK_CUR.
* Must not be taken from IRQ context.
*/
spinlock_t f_lock;
atomic_long_t f_count;
unsigned int f_flags;
fmode_t f_mode;
loff_t f_pos;
struct fown_struct f_owner;
const struct cred *f_cred;
struct file_ra_state f_ra;


u64 f_version;

        

        …… …… ……

};

struct file,在linux/fs.h中声明,表示已打开的文件

重要的成员有struct file_operations(字符设备操作函数)struct inode(linux 节点)





struct inode:(linux节点)

(路径:linux-3.13.10\include\linux\fs.h)

struct inode {

……  ……

union {
const unsigned int i_nlink;
unsigned int __i_nlink;
};
dev_t i_rdev;
loff_t i_size;
struct timespec i_atime;
struct timespec i_mtime;
struct timespec i_ctime;
spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
unsigned short          i_bytes;
unsigned int i_blkbits;

blkcnt_t i_blocks;

…… ……

struct list_head i_devices;
union {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct cdev *i_cdev;

};

struct inode,有2个重要的成员:

dev_t   i_rdev:设备号

structcdev   *i_cdev:字符设备的地址





struct file_operations(文件操作接口)

(路径:linux-3.13.10\include\linux\fs.h)

(file_operations是一个函数指针的集合,用于存放我们定义的用于操作设备的函数的指针,如果我们不定义,它默认保留为NULL。)

struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*iterate) (struct file *, struct dir_context *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, loff_t, loff_t, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
 loff_t len);
int (*show_fdinfo)(struct seq_file *m, struct file *f);

};



struct cdev (在linux内核中用cdev描述一个字符设备)

(路径:linux-3.13.10\include\linux\cdev.h)

#ifndef _LINUX_CDEV_H
#define _LINUX_CDEV_H

#include <linux/kobject.h>
#include <linux/kdev_t.h>
#include <linux/list.h>

struct file_operations;
struct inode;
struct module;

struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};

void cdev_init(struct cdev *, const struct file_operations *);
struct cdev *cdev_alloc(void);
void cdev_put(struct cdev *p);
int cdev_add(struct cdev *, dev_t, unsigned);
void cdev_del(struct cdev *);
void cd_forget(struct inode *);
extern struct backing_dev_info directly_mappable_cdev_bdi;

#endif


初始化字符设备的函数cdev_init。

输入参数:

structcdev*  :字符设备指针

Structfile_operations *: 字符设备操作函数指针



添加字符设备到linux内核函数cdev_add

输入参数:

structcdev*  :字符设备指针

dev_t设备号

unsigned设备数量



从linux内核中卸载字符设备cdev_del。

输入参数:

structcdev*  :字符设备指针


参考:https://blog.youkuaiyun.com/qq_27977257/article/details/54928863


`struct file` 是 Linux 内核中用于表示打开文件的核心数据结构。每个打开的文件、设备或管道等都有一个关联的 `file` 结构体实例,它是内核管理和操作这些对象的关键桥梁。通过理解 `struct file` 的组成部分及其工作原理,我们可以更好地把握 Linux 文件系统的行为以及编写高效的驱动程序和其他底层模块。 ### 主要字段解释 以下是 `struct file` 中一些重要的字段和其含义: 1. **f_mode**: 指明文件访问模式(读、写权限)。通常包括以下标志位组合: - `FMODE_READ`: 标识这是一个只读文件。 - `FMODE_WRITE`: 标识这是个可写的文件。 2. **f_flags**: 包含来自用户空间 open() 系统调用设置的各种选项标记,例如 O_RDONLY, O_WRONLY, O_RDWR, O_APPEND 等。 3. **f_pos**: 当前文件偏移量,指示下一次读写将开始的位置。 4. **f_op**: 这是一个指针数组,指向一组针对此文件类型的 VFS(虚拟文件系统)方法表(即文件操作函数集)。常见的成员有 read(), write(), ioctl(), mmap() 等。 5. **private_data**: 用户自定义的数据指针,常用于保存与特定打开文件相关的上下文信息或者回调所需的状态变量。 6. **f_inode**: 关联的 inode 结构体指针,代表实际存储于磁盘上的元数据记录。对于常规文件来说,这里包含有关文件大小、所有者以及其他属性的重要细节。 7. **f_path**: 描述路径名解析过程中所得的结果,其中包括 dentry (目录项) 和 vfsmount 组件,有助于定位文件所在的具体位置及命名空间环境。 8. **f_owner**: 信号接收者的任务结构体指针,默认为空但可以在某些场合指定谁会收到关于该文件的操作通知。 9. **f_count**: 引用计数器,用来跟踪有多少进程持有着这个文件句柄;当计数值降为零时表明没有任何活跃使用者,并准备释放相关资源。 --- ### 示例说明 下面给出一段简化版代码片段展示如何使用 `struct file` 定义一个新的字符设备驱动程序中的核心部分: ```c #include <linux/fs.h> #include <linux/cdev.h> // 设备的主次编号 #define DEVICE_MAJOR 240 static dev_t device_number; /* 打开文件时调用 */ static int my_char_open(struct inode *inode, struct file *filp) { printk(KERN_INFO "Device opened\n"); return 0; } /* 关闭文件时调用 */ static int my_char_release(struct inode *inode, struct file *filp) { printk(KERN_INFO "Device closed\n"); return 0; } /* 实现read/write等其他标准VFS方法... */ static const struct file_operations fops = { .owner = THIS_MODULE, .open = my_char_open, .release = my_char_release, }; static int __init char_init(void) { alloc_chrdev_region(&device_number, 0, 1, "mychardev"); // 注册设备号区间 cdev_init(&cdev, &fops); // 初始化字符设备 cdev_add(&cdev, device_number, 1); // 向系统添加设备 return 0; } module_init(char_init); ``` 在这个例子中,我们首先声明了一个名为 `fops` 的 `file_operations` 类型的对象,它包含了各种标准文件操作函数指针,如 `.open`, `.release`。然后我们在初始化阶段设置了对应的动作,并最终注册了我们的字符设备。 --- 总之,深入理解和恰当地运用 `struct file` 对于开发高质量的Linux驱动程序至关重要。了解这一基础概念能够帮助程序员更准确地控制文件生命周期内的各项行为,进而提高系统的稳定性和性能表现。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值