在 Linux 内核中,struct inode
是一个核心数据结构,用于表示文件系统中的文件、目录或符号链接的元数据。在设备驱动开发中(尤其是字符设备驱动),inode
结构体是驱动与文件系统交互的关键接口之一。以下是其核心要点:
1. struct inode
的核心作用
- 元数据容器:存储文件的属性(权限、所有者、时间戳、大小等)。
- 唯一标识:通过
i_ino
字段唯一标识一个文件(在同一个文件系统中)。 - 设备关联:对于设备文件(如
/dev/sda
),inode->i_rdev
存储设备号,驱动通过此字段识别硬件。
2. 关键成员字段
struct inode {
// 文件类型和权限(如 S_IFREG 表示普通文件)
umode_t i_mode;
// 文件所有者 UID 和 GID
uid_t i_uid;
gid_t i_gid;
// 链接计数(硬链接数量)
unsigned int i_nlink;
// 设备号(对于设备文件)
dev_t i_rdev;
// 文件大小(字节)
loff_t i_size;
// 访问、修改、状态变更时间戳
struct timespec i_atime, i_mtime, i_ctime;
// 块设备信息(对于块设备驱动)
struct block_device *i_bdev;
// 字符设备信息(对于字符设备驱动)
struct cdev *i_cdev;
// 其他字段(如文件系统私有数据)
void *i_private;
};
3. 在设备驱动中的典型使用场景
字符设备驱动示例
// 在驱动的 file_operations 中
static int my_open(struct inode *inode, struct file *file) {
// 获取设备号(主设备号 + 次设备号)
dev_t dev = inode->i_rdev;
// 通过设备号查找驱动的 cdev 结构
struct cdev *cdev = inode->i_cdev;
// 获取驱动私有数据(如硬件寄存器地址)
struct my_device *dev_data = container_of(cdev, struct my_device, cdev);
file->private_data = dev_data;
return 0;
}
块设备驱动示例
// 在块设备请求处理中
static void my_block_request(struct request_queue *q) {
struct request *req;
while ((req = blk_fetch_request(q)) != NULL) {
// 通过 req->rq_disk 获取关联的 gendisk 结构
struct gendisk *disk = req->rq_disk;
// 通过 disk->part0 获取 inode(可选)
struct inode *inode = disk->part0->__part;
// 处理 I/O 请求...
}
}
4. 驱动开发中的关键操作
- 获取设备号:
inode->i_rdev
(字符设备)或inode->i_bdev->bd_dev
(块设备)。 - 关联私有数据:通过
inode->i_private
存储驱动私有状态。 - 权限检查:在
open
函数中验证inode->i_mode
的权限位。 - 同步机制:使用
inode_lock(inode)
保护元数据操作。
5. 生命周期管理
- 创建:由文件系统在
mknod
或设备注册时自动创建。 - 销毁:由文件系统在文件卸载时自动释放。
- 引用计数:通过
iget
/iput
管理引用,避免内存泄漏。
6. 与 struct file
的关系
struct inode
表示文件的元数据(静态属性)。struct file
表示打开的文件实例(动态状态,如文件偏移量)。- 驱动函数(如
read
/write
)通过struct file *filp
参数访问inode
:struct inode *inode = filp->f_inode;
总结
在 Linux 驱动开发中,struct inode
是连接文件系统与硬件设备的桥梁。驱动通过 inode
获取设备号、权限信息,并管理设备状态。理解其字段和生命周期是编写稳定驱动的关键。