Linux驱动 2026年4月23日 12 分钟

struct inode 和 struct file 详解

这两个是 Linux 内核中 VFS(虚拟文件系统)层的核心结构体,驱动开发者不需要自己定义它们,而是由内核在调用驱动函…

这两个是 Linux 内核中 VFS(虚拟文件系统)层的核心结构体,驱动开发者不需要自己定义它们,而是由内核在调用驱动函数时自动传入。

两者对比

属性struct inodestruct file
含义文件的元数据文件的打开实例
生命周期内核中唯一(所有进程共享)每次 open() 创建一个
数量关系一个文件对应一个 inode同一文件可被多个进程打开,产生多个 file
存储内容设备号、文件大小、权限、时间戳等文件位置指针、打开模式、私有数据等

struct inode — 文件元数据

// 内核源码:include/linux/fs.h
struct inode {
    umode_t         i_mode;      /* 文件权限和类型 */
    kuid_t          i_uid;       /* 文件所有者 UID */
    kgid_t          i_gid;       /* 文件所有者 GID */
    loff_t          i_size;      /* 文件大小 */

    struct timespec i_atime;     /* 最后访问时间 */
    struct timespec i_mtime;     /* 最后修改时间 */
    struct timespec i_ctime;     /* 最后状态改变时间 */

    unsigned long   i_ino;       /* inode 号(唯一标识) */

    dev_t           i_rdev;      /* 真实设备号(对设备文件有意义) */
    union {
        struct cdev *i_cdev;     /* 指向字符设备结构体的指针 */
        struct block_device *i_bdev;
    };

    // ... 其他字段
};

驱动中最常用

// 从 inode 获取主次设备号(设备文件的设备号)
dev_t dev_num = inode->i_rdev;

// 从 inode 获取 cdev 结构体(内核内部用)
struct cdev *cdev = inode->i_cdev;

struct file — 打开的文件实例

// 内核源码:include/linux/fs.h
struct file {
    union {
        struct llist_node       fu_llist;
        struct rcu_head         fu_rcuhead;
    } f_u;
    struct path             f_path;       /* 路径信息 */
    struct inode            *f_inode;     /* 关联的 inode */
    const struct file_operations *f_op;   /* 文件操作集(驱动实现) */
    void                    *private_data;/* 驱动私有数据指针 */
    loff_t                  f_pos;        /* 当前文件读写位置 */
    unsigned int            f_flags;     /* open() 时的标志 (O_RDWR 等) */
    fmode_t                 f_mode;       /* 文件打开模式 */

    atomic_long_t           f_count;      /* 引用计数 */
    // ... 其他字段
};

驱动中最常用

file->private_data   /* 存储驱动自定义的设备结构体指针 */
file->f_pos          /* 当前读写位置(对字符设备通常不用管) */
file->f_flags        /* O_RDWR、O_NONBLOCK 等 */

为什么驱动里看不到它们定义,却能直接用?

因为它们是由内核在调用时自动创建并传递的:

用户空间
    open("/dev/xxx")          用户调用 open()
         │
         ▼
内核 VFS 层
    alloc inode + file        内核分配结构体
         │
         ▼
    chrdev_open(inode, file) 内核调用驱动的 open 函数
         │                    ← 你在这里收到这两个结构体
         ▼
    read/write/ioctl          内核继续调用其他驱动函数
         │
         ▼
    file_release()            关闭时内核调用
         │
         ▼
内核 VFS 层
    iput inode + fput file   释放结构体

在驱动中的实际用法

/* open 函数:初始化私有数据 */
static int chrdev_open(struct inode *inode, struct file *file)
{
    /* 从 inode 提取设备号(通过 inode->i_cdev 反向找到我们的 cdev) */
    struct cdev *cdev = inode->i_cdev;
    struct device_test *dev = container_of(cdev, struct device_test, cdev_test);

    /* 将设备结构体存入 file 的私有数据,后续 read/write 可以直接取出 */
    file->private_data = dev;

    printk(KERN_INFO "Device opened\n");
    return 0;
}

/* read 函数:从 private_data 取出设备信息 */
static ssize_t chrdev_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
    struct device_test *dev = file->private_data;  /* 取出之前存的结构体指针 */
    /* 用 dev 做事... */
    return 0;
}

/* release 函数:清理 */
static int chrdev_release(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "Device closed\n");
    return 0;
}

核心流程总结

open() 被调用
   │
   ├─ 内核分配 struct inode(存放设备号等元数据)
   ├─ 内核分配 struct file(存放打开状态等)
   │
   ├─ 传入驱动 chrdev_open(inode, file)
   │     └─ file->private_data = &my_dev  ← 绑定设备
   │
   ├─ 传入驱动 chrdev_read/write/ioctl(file, ...)
   │     └─ 从 file->private_data 取出设备 → 操作硬件
   │
   └─ close() 时
         └─ 传入驱动 chrdev_release(inode, file)

简单说:inode 告诉你”打开的是什么设备”,file 告诉你”这次打开的会话状态”。驱动通过 file->private_data 将自己的设备结构体和每一次打开操作关联起来

上一篇 Vim 编辑器详细使用手册

# Vim 编辑器详细使用手册 ## 目录 1. [Vim 简介](#1-vim-简介) 2. [三种模式](#2-三种...

下一篇 同步、异步、阻塞、非阻塞详解

同步、异步、阻塞、非阻塞详解 第一部分:四个概念的本质区别与联系 一、两个维度 维度 关注的问题 概念 消息通知机制 结...