文件系統是對一個存儲設備上的數據和元數據進行組織的機制。 Linux 文件系統接口實現為分層的體系結構,從而將用戶接口層、文件系統實現和操作存儲設備的驅動程序分隔開。另一種看待文件系統的方式是把它看作一個協議。網絡協議(比如 IP)規定了互聯網上傳輸的數據流的意義,同樣,文件系統會給出特定存儲媒體上數據的意義。
Linux 文件系統體系結構是一個對復雜系統進行抽象化的有趣例子。通過使用一組通用的 API 函數,Linux 可以在許多種存儲設備上支持許多種文件系統。例如,read 函數調用可以從指定的文件描述符讀取一定數量的字節。read 函數不了解文件系統的類型,比如 ext3 或 NFS。它也不了解文件系統所在的存儲媒體,比如 ATAPI磁盤、SAS磁盤或 SATA磁盤。但是,當通過調用 read 函數讀取一個文件時,數據會正常返回。
盡管大多數文件系統代碼在內核中,但是圖 1 所示的體系結構顯示了用戶空間和內核中與文件系統相關的主要組件之間的關系。
用戶空間包含一些應用程序(例如,文件系統的使用者)和 GNU C 庫(glibc),它們為文件系統調用(打開、讀取、寫和關閉)提供用戶接口。系統調用接口的作用就像是交換器,它將系統調用從用戶空間發送到內核空間中的適當端點。
VFS 是底層文件系統的主要接口。這個組件導出一組接口,然後將它們抽象到各個文件系統,各個文件系統的行為可能差異很大。有兩個針對文件系統對象的緩存(inode 和 dentry)。它們緩存最近使用過的文件系統對象。
每個文件系統實現(比如 ext2、JFS 等等)導出一組通用接口,供 VFS 使用。緩沖區緩存會緩存文件系統和相關塊設備之間的請求。例如,對底層設備驅動程序的讀寫請求會通過緩沖區緩存來傳遞。這就允許在其中緩存請求,減少訪問物理設備的次數,加快訪問速度。以最近使用(LRU)列表的形式管理緩沖區緩存。注意,可以使用 sync 命令將緩沖區緩存中的請求發送到存儲媒體(迫使所有未寫的數據發送到設備驅動程序,進而發送到存儲設備)。
Linux 以一組通用對象的角度看待所有文件系統。這些對象是超級塊(superblock)、inode、dentry 和文件。超級塊在每個文件系統的根上,超級塊描述和維護文件系統的狀態。文件系統中管理的每個對象(文件或目錄)在 Linux 中表示為一個 inode。inode 包含管理文件系統中的對象所需的所有元數據(包括可以在對象上執行的操作)。另一組結構稱為 dentry,它們用來實現名稱和 inode 之間的映射,有一個目錄緩存用來保存最近使用的 dentry。dentry 還維護目錄和文件之間的關系,從而支持在文件系統中移動。最後,VFS 文件表示一個打開的文件(保存打開的文件的狀態,比如寫偏移量等等)。
VFS 作為文件系統接口的根層。VFS 記錄當前支持的文件系統以及當前掛裝的文件系統。
在注冊新的文件系統時,會把這個文件系統和它的相關信息添加到 file_systems 列表中( linux/include/linux/fs.h)。這個列表定義可以支持的文件系統。在命令行上輸入 cat /proc/filesystems,就可以查看這個列表。
linux/include/linux/fs.h
struct file_system_type { const char *name; int fs_flags; int (*get_sb) (struct file_system_type *, int, const char *, void *, struct vfsmount *); 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 list_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 i_lock_key; struct lock_class_key i_mutex_key; struct lock_class_key i_mutex_dir_key; struct lock_class_key i_alloc_sem_key; };
VFS 中維護的另一個結構是掛裝的文件系統(見下 )。這個結構提供當前掛裝的文件系統(見 linux/include/linux/mount.h)。它鏈接又超級塊結構。
struct vfsmount { struct list_head mnt_hash; struct vfsmount *mnt_parent; /* fs we are mounted on */ struct dentry *mnt_mountpoint; /* dentry of mountpoint */ struct dentry *mnt_root; /* root of the mounted tree */ struct super_block *mnt_sb; /* pointer to superblock超級塊 */ #ifdef CONFIG_SMP struct mnt_pcp __percpu *mnt_pcp; atomic_t mnt_longterm; /* how many of the refs are longterm */ #else int mnt_count; int mnt_writers; #endif struct list_head mnt_mounts; /* list of children, anchored here */ struct list_head mnt_child; /* and going through their mnt_child */ int mnt_flags; /* 4 bytes hole on 64bits arches without fsnotify */ #ifdef CONFIG_FSNOTIFY __u32 mnt_fsnotify_mask; struct hlist_head mnt_fsnotify_marks; #endif const char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ struct list_head mnt_list; struct list_head mnt_expire; /* link in fs-specific expiry list */ struct list_head mnt_share; /* circular list of shared mounts */ struct list_head mnt_slave_list;/* list of slave mounts */ struct list_head mnt_slave; /* slave list entry */ struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */ struct mnt_namespace *mnt_ns; /* containing namespace */ int mnt_id; /* mount identifier */ int mnt_group_id; /* peer group identifier */ int mnt_expiry_mark; /* true if marked for expiry */ int mnt_pinned; int mnt_ghosts; };
超級塊結構表示一個文件系統。它包含管理文件系統所需的信息,包括文件系統名稱(比如 ext2)、文件系統的大小和狀態、塊設備的引用和元數據信息(比如空閒列表等等)。超級塊通常存儲在存儲媒體上,但是如果超級塊不存在,也可以實時創建它。
/include/linux/fs.h
struct super_block { struct list_head s_list; /* Keep this first */ dev_t s_dev; /* search index; _not_ kdev_t */ unsigned char s_dirt; unsigned char s_blocksize_bits; unsigned long s_blocksize; loff_t s_maxbytes; /* Max file size */ 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; struct mutex s_lock; 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; #endif /* 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 */ struct block_device *s_bdev; struct backing_dev_info *s_bdi; struct mtd_info *s_mtd; struct list_head s_instances; struct quota_info s_dquot; /* Diskquota specific options */ int s_frozen; wait_queue_head_t s_wait_unfrozen; char s_id[32]; /* Informational name */ void *s_fs_info; /* Filesystem private info */ 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 */ };
本欄目更多精彩內容:http://www.bianceng.cn/OS/Linux/
超級塊中的一個重要元素是超級塊操作的定義。這個結構定義一組用來管理這個文件系統中的 inode 的函數。例如,可以用 alloc_inode 分配 inode,用 destroy_inode 刪除 inode。可以用 read_inode 和 write_inode 讀寫 inode,用 sync_fs 執行文件系統同步。可以在 ./linux/include/linux/fs.h 中找到 super_operations 結構。每個文件系統提供自己的 inode 方法,這些方法實現操作並向 VFS 層提供通用的抽象。
struct super_operations { struct inode *(*alloc_inode)(struct super_block *sb);//分配inode void (*destroy_inode)(struct inode *);//銷毀inode void (*dirty_inode) (struct inode *); 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 *); void (*write_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 vfsmount *); int (*show_stats)(struct seq_file *, struct vfsmount *); #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); };
inode 表示文件系統中的一個對象,它具有惟一標識符。各個文件系統提供將文件名映射為惟一 inode 標識符和 inode 引用的方法。圖 顯示 inode 結構的一部分以及兩個相關結構。請特別注意 inode_operations 和 file_operations。這些結構表示可以在這個 inode 上執行的操作。inode_operations 定義直接在 inode 上執行的操作,而 file_operations 定義與文件和目錄相關的方法(標准系統調用)。
inode結構體:
struct inode { /* RCU path lookup touches following: */ umode_t i_mode; uid_t i_uid; gid_t i_gid; const struct inode_operations *i_op;//inode操作實現方法 struct super_block *i_sb; spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ unsigned int i_flags; struct mutex i_mutex; unsigned long i_state; unsigned long dirtied_when; /* jiffies of first dirtying */ struct hlist_node i_hash; struct list_head i_wb_list; /* backing dev IO list */ struct list_head i_lru; /* inode LRU list */ struct list_head i_sb_list; union { struct list_head i_dentry; struct rcu_head i_rcu; }; unsigned long i_ino; atomic_t i_count; unsigned int i_nlink; dev_t i_rdev; unsigned int i_blkbits; u64 i_version; loff_t i_size; #ifdef __NEED_I_SIZE_ORDERED seqcount_t i_size_seqcount; #endif struct timespec i_atime; struct timespec i_mtime; struct timespec i_ctime; blkcnt_t i_blocks; unsigned short i_bytes; struct rw_semaphore i_alloc_sem; const struct file_operations *i_fop; /* former ->i_op->default_file_ops 文件操作實現方法*/ struct file_lock *i_flock; struct address_space *i_mapping; struct address_space i_data; #ifdef CONFIG_QUOTA struct dquot *i_dquot[MAXQUOTAS]; #endif struct list_head i_devices; union { struct pipe_inode_info *i_pipe; struct block_device *i_bdev; struct cdev *i_cdev; }; __u32 i_generation; #ifdef CONFIG_FSNOTIFY __u32 i_fsnotify_mask; /* all events this inode cares about */ struct hlist_head i_fsnotify_marks; #endif #ifdef CONFIG_IMA /* protected by i_lock */ unsigned int i_readcount; /* struct files open RO */ #endif atomic_t i_writecount; #ifdef CONFIG_SECURITY void *i_security; #endif #ifdef CONFIG_FS_POSIX_ACL struct posix_acl *i_acl; struct posix_acl *i_default_acl; #endif void *i_private; /* fs or device private pointer */ };
inode 和目錄緩存分別保存最近使用的 inode 和 dentry。注意,對於 inode 緩存中的每個 inode,在目錄緩存中都有一個對應的 dentry。可以在 ./linux/include/linux/fs.h 中找到 inode 和 dentry 結構。
除了各個文件系統實現(可以在 ./linux/fs 中找到)之外,文件系統層的底部是緩沖區緩存。這個組件跟蹤來自文件系統實現和物理設備(通過設備驅動程序)的讀寫請求。為了提高效率,Linux 對請求進行緩存,避免將所有請求發送到物理設備。緩存中緩存最近使用的緩沖區(頁面),這些緩沖區可以快速提供給各個文件系統。