Linux内核文件系统-虚拟文件系统-其他数据结构

建议点击这里查看个人主页上的最新原文

一般的Linux书籍都是先讲解进程和内存相关的知识,但我想先讲解文件系统。

第一,因为我就是做文件系统的,更擅长这一块,其他模块的内容我还要再去好好看看书,毕竟不能误人子弟嘛;第二,是

因为文件系统模块更接近于用户态,是相对比较好理解的内容(当然想深入还是要下大功夫的),由文件系统入手比较适合初学者。

虚拟文件系统英文全称Virtual file system,缩写为VFS,又称为虚拟文件切换系统(virtual filesystem switch)。所有的文件系统都要先经过虚拟文件系统层,虚拟文件系统相当于制定了一套规则,如果你想写一个新的文件系统,只需要遵守这套规则就可以了。

VFS虽然是用C语言写的,但使用了面向对象的设计思路。

file_system_type描述各种特定文件系统类型,每种文件系统只有一个file_system_type对象,具体文件系统如ext2模块加载时调用init_ext2_fs() -> register_filesystem()注册。根文件系统类型rootfs_fs_type

struct file_system_type {
        const char *name; // 名字
        int fs_flags; // 类型标志
#define FS_REQUIRES_DEV         1 
#define FS_BINARY_MOUNTDATA     2
#define FS_HAS_SUBTYPE          4
#define FS_USERNS_MOUNT         8       /* 可以由用户命名空间根目录挂载 */
#define FS_DISALLOW_NOTIFY_PERM 16      /* 禁用 fanotify 权限事件 */
#define FS_ALLOW_IDMAP         32       /* 文件系统已更新以处理 vfs id 映射。 */
#define FS_RENAME_DOES_D_MOVE   32768   /* 文件系统将在内部处理 rename() 时的 d_move()。 */
        int (*init_fs_context)(struct fs_context *);
        const struct fs_parameter_spec *parameters;
        struct dentry *(*mount) (struct file_system_type *, int, // 从磁盘中读取超级块
                       const char *, void *);
        void (*kill_sb) (struct super_block *);   // 终止访问超级块
        struct module *owner; // 文件系统模块
        struct file_system_type * next; // 链表中下一个文件系统类型
        struct hlist_head fs_supers;    // 超级块对象链表

        // 运行时使锁生效
        struct lock_class_key s_lock_key;
        struct lock_class_key s_umount_key;
        struct lock_class_key s_vfs_rename_key;
        struct lock_class_key s_writers_key[SB_FREEZE_LEVELS];

        struct lock_class_key i_lock_key;
        struct lock_class_key i_mutex_key;
        struct lock_class_key invalidate_lock_key;
        struct lock_class_key i_mutex_dir_key;
};

文件系统挂载时,有一个mount结构体在挂载点被创建,代表文件系统实例,也就是代表一个挂载点。

struct mount {
        struct hlist_node mnt_hash;     // 散列表
        struct mount *mnt_parent;       // 父文件系统
        struct dentry *mnt_mountpoint;  // 挂载点的目录项
        struct vfsmount mnt;
        union {
                struct rcu_head mnt_rcu;
                struct llist_node mnt_llist;
        };
#ifdef CONFIG_SMP
        struct mnt_pcp __percpu *mnt_pcp;
#else
        int mnt_count;   // 引用计数
        int mnt_writers; // 写者引用计数
#endif
        struct list_head mnt_mounts;    /* 子文件系统链表, 固定在此 */
        struct list_head mnt_child;     /* 子文件系统链表 */
        struct list_head mnt_instance;  /* sb->s_mounts 上的挂载实例 */
        const char *mnt_devname;        /* 设备名称,例如 /dev/dsk/hda1 */
        struct list_head mnt_list;      // 描述符链表
        struct list_head mnt_expire;    /* 在到期链表的位置 */
        struct list_head mnt_share;     /* 在共享安装链表的位置 */
        struct list_head mnt_slave_list;/* 从安装链表 */
        struct list_head mnt_slave;     /* 在从安装链表的位置 */
        struct mount *mnt_master;       /* 从安装链表的主人 */
        struct mnt_namespace *mnt_ns;   /* 相关的命名空间 */
        struct mountpoint *mnt_mp;      /* 挂载的位置 */
        union {
                struct hlist_node mnt_mp_list;  /* 具有相同挂载点的挂载链表 */
                struct hlist_node mnt_umount;
        };
        struct list_head mnt_umounting; /* 用于卸载传播的列表条目 */
#ifdef CONFIG_FSNOTIFY
        struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;
        __u32 mnt_fsnotify_mask;
#endif
        int mnt_id;                     /* 安装标识符 */
        int mnt_group_id;               /* 组标识符 */
        int mnt_expiry_mark;            /* 到期时为1 */
        struct hlist_head mnt_pins;
        struct hlist_head mnt_stuck_children;
} __randomize_layout;

struct vfsmount {
        struct dentry *mnt_root;        /* 该文件系统的根目录项 */
        struct super_block *mnt_sb;     /* 超级块 */
        int mnt_flags;                  // 挂载标志, MNT_NOSUID 等
        struct mnt_idmap *mnt_idmap;
} __randomize_layout;

files_struct描述单个进程相关的信息,struct task_struct中的files成员指向它。

/*
 * /* 打开的文件表结构 */
 */
struct files_struct {
  /*
   * 主要用于读取的部分
   */
        atomic_t count;             // 引用计数
        bool resize_in_progress;
        wait_queue_head_t resize_wait;

        struct fdtable __rcu *fdt;  // 如果打开的文件数大于NR_OPEN_DEFAULT,分配一个新数组
        struct fdtable fdtab;       // 基fd表
        /*
        * 在 SMP 中,写入部分位于单独的缓存行
        */
        spinlock_t file_lock ____cacheline_aligned_in_smp;  // 单个文件的锁
        unsigned int next_fd;                               // 缓存下一个可用的fd
        unsigned long close_on_exec_init[1];                // exec()时关闭的fd链表
        unsigned long open_fds_init[1];                     // 打开的fd链表
        unsigned long full_fds_bits_init[1];
        struct file __rcu * fd_array[NR_OPEN_DEFAULT];      // 默认的文件对象数组
};

fs_struct表示文件系统进程相关的信息,struct task_struct中的fs成员指向它。

struct fs_struct {
        int users;              // 用户数目
        spinlock_t lock;        // 保护该结构体的锁
        seqcount_spinlock_t seq;
        int umask;              // 掩码
        int in_exec;            // 当前正在执行的文件
        struct path root;       // 根目录路径
        struct path pwd;        // 当前工作目录的路径
} __randomize_layout;

mnt_namespace表示单进程命名空间,struct task_struct中的nsproxy->mnt_namespace成员指向它。

struct mnt_namespace {
        struct ns_common        ns;
        struct mount *  root; // 根目录的挂载点
        /*
         * 对 .list 的遍历和修改受以下任意一种方式保护:
         * - 获取 namespace_sem 的写锁,或
         * - 获取 namespace_sem 的读锁并获取 .ns_lock
         */
        struct list_head        list; // 挂载点链表
        spinlock_t              ns_lock;
        struct user_namespace   *user_ns;
        struct ucounts          *ucounts; // 用户计数
        u64                     seq;    /* 防止循环的序列号 */
        wait_queue_head_t poll; // 轮询的等待队列
        u64 event; // 事件计数
        unsigned int            mounts; /* 命名空间中的挂载数量 */
        unsigned int            pending_mounts;
} __randomize_layout;

struct ucounts {
        struct hlist_node node;
        struct user_namespace *ns;
        kuid_t uid;
        atomic_t count; // 引用计数
        atomic_long_t ucount[UCOUNT_COUNTS];
        atomic_long_t rlimit[UCOUNT_RLIMIT_COUNTS];
};

还有文件锁的数据结构为struct file_lock

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值