针对linux内核而言,其基本上以“一切皆文件”的思想实现,linux内核针对字符设备、块设备、存储设备、网络通信的访问,都是注册成不同的文件系统(procfs、devtmpfs、ext3、ext4、ramdisk、sockfs、yaffs2、ubi、squashfs等),并实现具体的读写接口,最终由系统调用统一调用。而linux内核为了抽象文件系统的共性,便于对多文件系统的支持,向上次提供统一的接口,linux提供了vfs框架,本文主要介绍vfs框架相关的概念及相关的结构体。一、文件系统、vfs、系统调用之间的关系
而文件系统、vfs、系统调用之间的关系,如下图所示。
二、vfs相关的概念及结构体介绍
针对vfs主要涉及超级块(superblock)、目录项(dentry)、索引节点(inode)、文件系统类型。2.1 超级块(superblock)
superblock主要用于表示文件系统相关的信息,代表了一个文件系统整个信息,包括文件系统的类型、逻辑块大小、该文件系统支持的最大文件大小、根索引节点、根目录项、该文件系统类型、超级块相关的处理接口(索引节点相关的操作(节点的申请、释放、读、写)、获取文件系统的状态(statfs)、同步(sync_fs)等)
struct super_block {
struct list_head s_list; /*超级块相关的链接链表*/
dev_t s_dev; /* search index; _not_ kdev_t */
unsigned char s_blocksize_bits;/*块大小对应的bit位*/
unsigned long s_blocksize;/*块大小*/
loff_t s_maxbytes; /*该文件系统支持的最大文件字节数*/
struct file_system_type *s_type;/*指向对应的已注册的文件系统*/
const struct super_operations *s_op;/*超级块相关的接口*/
const struct dquot_operations *dq_op;
const struct quotactl_ops *s_qcop;
const struct export_operations *s_export_op;
unsigned long s_flags;
unsigned long s_magic;/*魔数*/
struct dentry *s_root;/*指向根目录项*/
struct rw_semaphore s_umount;
int s_count;/*引用计数*/
atomic_t s_active;
#ifdef CONFIG_SECURITY
void *s_security;
#endif
const struct xattr_handler **s_xattr;
struct list_head s_inodes; /* all inodes */
struct hlist_bl_head s_anon; /* anonymous dentries for (nfs) exporting */
#ifdef CONFIG_SMP
struct list_head __percpu *s_files;
#else
struct list_head s_files;/*指向struct files类型的指针变量*/
#endif
struct list_head s_mounts; /* list of mounts; _not_ for fs use */
/* s_dentry_lru, s_nr_dentry_unused protected by dcache.c lru locks */
struct list_head s_dentry_lru; /* unused dentry lru */
int s_nr_dentry_unused; /* # of dentry on lru */
/* s_inode_lru_lock protects s_inode_lru and s_nr_inodes_unused */
spinlock_t s_inode_lru_lock ____cacheline_aligned_in_smp;
struct list_head s_inode_lru; /* unused inode lru */
int s_nr_inodes_unused; /* # of inodes on lru */
struct block_device *s_bdev;/*指向块设备类型的指针变量*/
struct backing_dev_info *s_bdi;
struct mtd_info *s_mtd;/*指向mtd相关的指针变量,这个与闪存设备抽象模块有关(内存技术模块)*/
struct hlist_node s_instances;
struct quota_info s_dquot; /* Diskquota specific options */
struct sb_writers s_writers;
char s_id[32]; /* Informational name */
u8 s_uuid[16]; /* UUID */
void *s_fs_info; /* Filesystem private info */
unsigned int s_max_links;
fmode_t s_mode;
/* Granularity of c/m/atime in ns.
Cannot be worse than a second */
u32 s_time_gran;
/*
* The next field is for VFS *only*. No filesystems have any business
* even looking at it. You had been warned.
*/
struct mutex s_vfs_rename_mutex; /* Kludge */
/*
* Filesystem subtype. If non-empty the filesystem type field
* in /proc/mounts will be "type.subtype"
*/
char *s_subtype;
/*
* Saved mount options for lazy filesystems using
* generic_show_options()
*/
char __rcu *s_options;
const struct dentry_operations *s_d_op; /* default d_op for dentries */
/*
* Saved pool identifier for cleancache (-1 means none)
*/
int cleancache_poolid;
struct shrinker s_shrink; /* per-sb shrinker handle */
/* Number of inodes with nlink == 0 but still referenced */
atomic_long_t s_remove_count;
/* Being remounted read-only */
int s_readonly_remount;
};
如下为系统中超级块的链表
针对struct super_operations,主要是索引节点相关的操作接口、mount相关的接口等
struct super_operations {
struct inode *(*alloc_inode)(struct super_block *sb);
void (*destroy_inode)(struct inode *);
void (*dirty_inode) (struct inode *, int flags);
int (*write_inode) (struct inode *, struct writeback_control *wbc);
int (*drop_inode) (struct inode *);
void (*evict_inode) (struct inode *);
void (*put_super) (struct super_block *);
int (*sync_fs)(struct super_block *sb, int wait);
int (*freeze_fs) (struct super_block *);
int (*unfreeze_fs) (struct super_block *);
int (*statfs) (struct dentry *, struct kstatfs *);
int (*remount_fs) (struct super_block *, int *, char *);
void (*umount_begin) (struct super_block *);
int (*show_options)(struct seq_file *, struct dentry *);
int (*show_devname)(struct seq_file *, struct dentry *);
int (*show_path)(struct seq_file *, struct dentry *);
int (*show_stats)(struct seq_file *, struct dentry *);
#ifdef CONFIG_QUOTA
ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
#endif
int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
int (*nr_cached_objects)(struct super_block *);
void (*free_cached_objects)(struct super_block *, int);
};
2.2 目录项(dentry)
存放目录项与对应文件进行链接的信息,目录本身也是一个文件,当目录对应索引节点表示目录时,则索引节点(inode)中的块数据是该目录下所有文件或者子目录的名称;当目录对应索引节点表示文件时,则索引节点(inode)中的块数据中保存的是文件的数据。每一个目录或者文件均有一个索引节点(inode),该一个索引节点则可以和多个目录项关联。
struct dentry {
/* RCU lookup touched fields */
unsigned int d_flags; /* protected by d_lock */
seqcount_t d_seq; /* per dentry seqlock */
struct hlist_bl_node d_hash; /* lookup hash list */
struct dentry *d_parent; /*指向到父dentry*/
struct qstr d_name;
struct inode *d_inode; /* 指向struct inode类型的指针,通过dentry与inode可以描述一个文件或目录*/
unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
/* Ref lookup also touches following */
unsigned int d_count; /* protected by d_lock */
spinlock_t d_lock; /* per dentry lock */
const struct dentry_operations *d_op;/*目录项相关的操作接口*/
struct super_block *d_sb; /* 指向超级块*/
unsigned long d_time; /* used by d_revalidate */
void *d_fsdata; /* fs-specific data */
struct list_head d_lru; /* LRU list */
/*
* d_child and d_rcu can share memory
*/
union {
struct list_head d_child; /* child of parent list */
struct rcu_head d_rcu;
} d_u;
struct list_head d_subdirs; /* 该目录项的子项 */
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 i_mutex_dir_key;
};
linux内核中文件系统变量之间的联系如下图所示
下面根据文件系统的注册函数,注册一个文件系统类型(该文件系统类型仅仅用于测试,未提供任何实质的内容),测试代码如下
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static struct file_system_type test_fs_type = {
.name = "test-fs",
.kill_sb = kill_litter_super,
};
static int __init fs_test_init(void)
{
int err = register_filesystem(&test_fs_type);
if (err) {
printk(KERN_ERR "%s: unable to register devtmpfs type %i\n", __FUNCTION__, err);
return err;
}
return 0;
}
static void __exit fs_test_exit(void)
{
unregister_filesystem(&test_fs_type);
}
module_init(fs_test_init);
module_exit(fs_test_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("fs-test driver");
加载该驱动后,在/proc/filesystems下就存在新添加的文件系统类型了,如下图所示。
本章主要介绍vfs相关的概念以及数据结构,下一章继续进行文件系统注册及mount相关的内容介绍。