Linux的虚拟文件系统

1.几个重要的数据结构:
<超级块>: 一个已安装的文件系统对应一个超级块

1318struct super_block {
1319        struct list_head        s_list;         /* Keep this first */
1320        dev_t                   s_dev;          /* search index; _not_ kdev_t */
1321        unsigned char           s_dirt;
1322        unsigned char           s_blocksize_bits;
1323        unsigned long           s_blocksize;
1324        loff_t                  s_maxbytes;     /* Max file size */
1325        struct file_system_type *s_type;
1326        const struct super_operations   *s_op;
…… ……
1330        unsigned long           s_flags;
1332        struct dentry           *s_root;
1335        int                     s_count;
1342        struct list_head        s_inodes;       /* all inodes */
1347        struct list_head        s_files;
1353        struct block_device     *s_bdev;
1357        struct quota_info       s_dquot;        /* Diskquota specific options */
1362        char s_id[32];                          /* Informational name */
…… ……
1388};

字段解释:
s_list: 系统中所有的超级块组成的双向链表
s_dev:  超级块所描述的系统所在的设备号
s_type: 超级块所描述的文件系统的系统类型
s_op:   操作函数指针
s_root: 超级块所描述的系统的根目录目录项
s_count:超级块的引用计数
s_inodes: 该文件系统的所有索引结点组成的链表的链表头
s_files: 该文件系统所有打开文件的文件描述符链表, 3.13版本中没有看见
s_id: 超级块的名称

<索引结点>:磁盘中的一个文件对应一个索引结点

 725struct inode {
 726        struct hlist_node       i_hash;
 727        struct list_head        i_list;         /* backing dev IO list */
 729        struct list_head        i_dentry;
 730        unsigned long           i_ino;
 731        atomic_t                i_count;
 732        unsigned int            i_nlink;
 733        uid_t                   i_uid;
 734        gid_t                   i_gid;
 735        dev_t                   i_rdev;
 736        unsigned int            i_blkbits;
 737        u64                     i_version;
 738        loff_t                  i_size;
…… ……
 742        struct timespec         i_atime;
 743        struct timespec         i_mtime;
 744        struct timespec         i_ctime;
 745        blkcnt_t                i_blocks;
 746        unsigned short          i_bytes;
 747        umode_t                 i_mode;
 …… ……
 751        const struct inode_operations   *i_op;
 752        const struct file_operations    *i_fop; /* former ->i_op->default_file_ops */
 753        struct super_block      *i_sb;
 760        struct list_head        i_devices;
 761        union {
 762                struct pipe_inode_info  *i_pipe;
 763                struct block_device     *i_bdev;
 764                struct cdev             *i_cdev;
 765        };
 …… ……
 788};

 字段解释:
 i_hash:  系统中的索引结点组成了一个hash表,hash值相同的索引结点用链表连接
 i_list:  处于同一状态的索引结点组成一个链表, 此种状态有未被使用的,正在被使用的,脏链表,hash值相同的
 i_dentry: 不同的目录项可以对应同一个索引结点,这些目录项组成一个链表,i_dentry就是链表头
 i_ino: 索引结点号
 i_count: 引用计数
 i_nlink: 硬链接数
 i_uid: 索引结点对应的文件的所有者的用户id
 i_rdev:  索引结点如果是设备文件,则表示对应的设备号
 i_atime: 索引结点的访问时间
 i_mtime: 索引结点内容的修改时间
 i_ctime: 索引结点属性的修改时间
 i_op: 索引结点操作函数指针
 i_fop: 与该索引结点对应的文件对象的文件操作函数指针,用于给file->f_op指针赋值
 i_sb: 超级块
 i_pipe: 表示该索引结点是管道
 i_bdev: 表示该索引结点是块设备
 i_cdev: 表示该索引结点是字符设备

<目录项>:目标文件路径中的每一项都代表一个目录项,比如/home/test.c中,/,home,test.c都分别是一个目录项.这些目录项都属于路径的一部分,并且每个目录项都与其对应的inode相联系

  89struct dentry {
  90        atomic_t d_count;
  91        unsigned int d_flags;           /* protected by d_lock */
  92        spinlock_t d_lock;              /* per dentry lock */
  93        int d_mounted;
  94        struct inode *d_inode;          /* Where the name belongs to - NULL is
  …… ……
 100        struct hlist_node d_hash;       /* lookup hash list */
 101        struct dentry *d_parent;        /* parent directory */
 102        struct qstr d_name;
 103
 104        struct list_head d_lru;         /* LRU list */
 108        union {
 109                struct list_head d_child;       /* child of parent list */
 110                struct rcu_head d_rcu;
 111        } d_u;
 112        struct list_head d_subdirs;     /* our children */
 113        struct list_head d_alias;       /* inode alias list */
 115        const struct dentry_operations *d_op;
 116        struct super_block *d_sb;       /* The root of the dentry tree */
…… ……
 120};

字段解释:
d_count: 引用计数
d_lock: 目录项访问锁
d_inode: 目录项对应的索引结点
d_hash: 系统中所有的目录项组成一个hash表,hash值相同的用链表连接
d_parent: 父目录项
d_name: 目录项名称
d_child: 该目录项在父目录项的子目录项链表中的位置
d_subdirs: 该目录项的所有子目录项组成的链表的链表头
d_alias: 不同的目录项可以对应同一个索引结点,这些目录项组成一个链表,d_alias表示在该链表中的位置
d_op: 目录项操作函数指针
d_sb: 目录项对应的超级块

<文件结构体>:每一个文件打开后都对应一个打开文件结构体

 909struct file {
 …… ……
 914        union {
 915                struct list_head        fu_list;
 916                struct rcu_head         fu_rcuhead;
 917        } f_u;
 918        struct path             f_path;
 919#define f_dentry        f_path.dentry
 920#define f_vfsmnt        f_path.mnt
 921        const struct file_operations    *f_op;
 922        spinlock_t              f_lock;  /* f_ep_links, f_flags, no IRQ */
 923#ifdef CONFIG_SMP
 924        int                     f_sb_list_cpu;
 925#endif
 926        atomic_long_t           f_count;
 927        unsigned int            f_flags;
 928        fmode_t                 f_mode;
 929        loff_t                  f_pos;
 930        struct fown_struct      f_owner;
 935#ifdef CONFIG_SECURITY
 936        void                    *f_security;
 937#endif
 938        /* needed for tty driver, and maybe others */
 939        void                    *private_data;
 940
 …… ……
 949};

字段解释:
fu_list: 一个超级块中所有的文件打开对象组成一个链表, fu_list表示在该链表中的位置
f_dentry: 该打开文件对象对应的目录项
f_vfsmnt: 该文件所在系统对应的文件系统挂载点
f_op: 文件对象操作函数指针
f_lock: 访问文件对象时的锁
f_count: 引用计数
f_flags: 文件打开时候的标志,如可写,只读等
f_mode: 访问权限标志
f_pos: 文件对象的当前偏移量

<文件系统类型>:Linux系统中每一种文件类型对应一个该结构

1736struct file_system_type {
1737        const char *name;
1738        int fs_flags;
1739        int (*get_sb) (struct file_system_type *, int,
1740                       const char *, void *, struct vfsmount *);
1741        void (*kill_sb) (struct super_block *);
1742        struct module *owner;
1743        struct file_system_type * next;
1744        struct list_head fs_supers;
1745
1746        struct lock_class_key s_lock_key;
1747        struct lock_class_key s_umount_key;
1748        struct lock_class_key s_vfs_rename_key;
1749
1750        struct lock_class_key i_lock_key;
1751        struct lock_class_key i_mutex_key;
1752        struct lock_class_key i_mutex_dir_key;
1753        struct lock_class_key i_alloc_sem_key;
1754};

字段解释:
name: 文件系统的名称
get_sb: 安装一个该类型的文件系统时, 此函数用于从磁盘块中读取超级块
kill_sb: 卸载文件系统时调用,进行一些清理操作
next: 所有的文件系统类型组成一个链表,next表示下一个文件系统类型
fs_supers: 属于同一种文件系统类型的所有超级块组成一个链表, fs_supers为链表头

<虚拟文件系统挂载点>:一个文件系统安装时对应一个挂载点

struct vfsmount {
    struct dentry *mnt_root;    /* root of the mounted tree */
    struct super_block *mnt_sb; /* pointer to superblock */
    int mnt_flags;
};

字段解释:
mnt_root: 挂载点所在的根目录目录项
mnt_sb: 挂载点对应的文件系统的超级块

struct fs_struct: 记录进程的当前目录和根目录信息,进程描述符中的fs字段便是指向该进程的fs_struct结构

 6struct fs_struct {
 7        int users;
 8        spinlock_t lock;
 9        int umask;
10        int in_exec;
11        struct path root, pwd;
12};

字段解释:
users: 引用计数
lock: 访问锁
umask: 进程的文件创建屏蔽字
root: 进程的根目录
pwd: 进程的当前工作目录

struct files_struct: 保存进程所有的打开文件对象的结构

44struct files_struct {
48        atomic_t count;
49        struct fdtable *fdt;
50        struct fdtable fdtab;
54        spinlock_t file_lock ____cacheline_aligned_in_smp;
55        int next_fd;
56        struct embedded_fd_set close_on_exec_init;
57        struct embedded_fd_set open_fds_init;
58        struct file * fd_array[NR_OPEN_DEFAULT];
59};

字段解释:
count: 引用计数
fdt: 指向该进程的文件描述符表
file_lock: 访问锁
next_fd: 当前未被使用的最小描述符号
close_on_exec_init: 调用exec时需要关闭的文件对象
open_fds_init: 所有打开的文件对象(32位)
fd_array: 打开文件对象指针数组,一般情况下,NR_OPEN_DEFAULT为32,如果打开文件对象超过了32,则把该数组中的对象指针全部赋值到fdt指向的文件描述符表

2.实践例子1:
代码实现思想:

1.所有的超级块组成一个链表,这个链表有一个头结点,找到这个头结点后,就可以遍历整个超级块

2.一个超级块中的所有索引结点组成一个双向链表,这个链表的头结点保存在超级块中的s_inodes字段中.这样就可以遍历每个超级块中的所有索引结点了

3.不同的目录项可以对应同一个索引结点,这些目录项也组成一个双向链表,该链表的第一个结点保存在i_dentry字段中.这样就可以遍历一个索引结点的所有别名目录项了

代码:

#define SUPER_BLOCKS_ADDRESS 0xc19415b8   //超级块的头结点地址, grep super_blocks /proc/kallsystems  
#define SB_LOCK_ADDRESS 0xc1b59520        //超级块组成的链表的自旋锁地址, grep sb_lock /proc/kallsystems  


int sb_open(struct inode *inodep, struct file *filp)
{
    struct super_block *sb;
    struct list_head *sb_pos;

    struct inode *node;
    struct list_head *node_pos;

    struct dentry *dentry;
    struct hlist_node *dentry_pos;

    spin_lock((spinlock_t *)SB_LOCK_ADDRESS);          //获取超级块链表的自旋锁

    list_for_each(sb_pos, (struct list_head *)SUPER_BLOCKS_ADDRESS){    //遍历超级块链表
        sb = list_entry(sb_pos, struct super_block, s_list);            //得到超级块结构体

        printk("dev_t: %d, %d ", MAJOR(sb->s_dev), MINOR(sb->s_dev));
        printk("fs_name: %s\n", sb->s_type->name);

        list_for_each(node_pos, &sb->s_inodes){   //遍历每个超级块中的所有索引结点
            node = list_entry(node_pos, struct inode, i_sb_list);    //得到索引结点

            printk("inode->ino: %lu ", node->i_ino);

            printk("dentry alias name: ");  
            for(dentry_pos = node->i_dentry.first; dentry_pos; dentry_pos = dentry_pos->next)   //遍历索引结点下的目录项别名链表
            {
                dentry = list_entry(dentry_pos, struct dentry, d_alias);  //得到目录项
                printk("%s ", dentry->d_name.name);
            }       
        } 
    }

    spin_unlock((spinlock_t *)SB_LOCK_ADDRESS);

    return 0;
}

3.实践实例2:
代码实现思想:

1.系统中所有的文件系统类型组成一个双向链表,找到这个链表的第一个链表结点的地址后,就可以遍历该链表

代码:

#define FILE_SYSTEM_ADDRESS 0xc1b59b40    //文件系统类型链表的第一个结点的地址, grep file_systems /proc/kallsystems 
#define FILE_SYSTEM_LOCK_ADDRESS 0xc19447dc //文件系统类型组成的链表的自旋锁, grep file_systems_lock /proc/kallsystems

int file_system_open(void)
{
    struct file_system_type **fst_pos;

    read_lock((rwlock_t *)FILE_SYSTEM_LOCK_ADDRESS); //获取文件系统类型链表的读锁
    fst_pos = (struct file_system_type **)FILE_SYSTEM_ADDRESS;  //得到第一个结点的地址

    while(*fst_pos)  //遍历文件系统类型链表
    {
        printk("file_system_type name: %s\n", (*fst_pos)->name);

        fst_pos = &(*fst_pos)->next; 
    }

    read_unlock((rwlock_t *)FILE_SYSTEM_LOCK_ADDRESS);

    return 0;
}

本文引述自:
http://edsionte.com/techblog/archives/1984
http://edsionte.com/techblog/archives/2033
http://edsionte.com/techblog/archives/2054

你可能感兴趣的:(校招准备)