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