目录
8.4 处理VFS对象
8.4.1 文件系统操作
本专栏文章将有70篇左右,欢迎+关注,查看后续文章。
8.4 处理VFS对象
8.4.1 文件系统操作
文件系统可以编译为模块。
使用文件系统前需先注册。
1. 注册文件系统
int register_filesystem( struct file_system_type *fs )
注册文件系统,将加入全局文件系统链表。
通过遍历全局链表,查找文件系统名称字符串,可确定是否已注册。
struct file_system_type {
const char *name; //如"ext3","nfs","ubifs"。
int fs_flags; //是否只读、禁止setuid、禁止setgid。
struct module *owner; //当文件系统编译为模块时有效。
struct dentry *(*mount) (struct file_system_type *, int, const char *, void *);
//挂载文件系统时调用。
void (*kill_sb) (struct super_block *);
//卸载文件系统时调用。
struct hlist_head fs_supers;
//不同目录可装载了相同文件系统。
//所有相同文件系统连接到fs_supers为表头的链表。
struct file_system_type *next; //连接其他文件系统
};
成员介绍:
fs_supers:
不同目录可装载了相同文件系统。
所有相同文件系统连接同一链表,fs_supers就是表头。
使用举例:
hlist_add_head( &s->s_instances, &type->fs_supers );
hlist_for_each_entry( old, &type->fs_supers, s_instances ) {
}
2. 装载卸载
mount命令:查看系统装载的文件系统。
vfsmount 结构
每一个装载的文件系统都有一个 vfsmount 实例。
struct vfsmount {
struct dentry *mnt_root; //文件系统装载的根目录的dentry。
struct super_block *mnt_sb; //对应超级块。
int mnt_flags;
};
setuid:执行程序时,可将进程有效用户ID设置为文件所有者ID,但有安全隐患。
mnt_flags 有:
#define MNT_NOSUID 0x01 // 禁止setuid执行。
#define MNT_NODEV 0x02 // 虚拟文件系统。
#define MNT_NOEXEC 0x04 // 禁止执行程序文件。
#define MNT_READONLY 0x40 // 挂载为只读文件系统。
超级块管理
装载一个文件系统时,还将初始化一个 struct super_block 实例。
其中包含文件系统信息,装载点信息。
struct super_block {
struct list_head s_list; // 连接系统所有超级块。
dev_t s_dev; // 文件系统所在块设备标识符。
struct block_device *s_bdev; // 文件系统所在块设备。
unsigned char s_blocksize_bits; // 文件系统块大小,单位:bit。
unsigned long s_blocksize; // 文件系统块大小,单位:字节。
loff_t s_maxbytes; // 文件系统中文件最大长度。
struct file_system_type *s_type;
struct super_operations *s_op;
struct dentry *s_root; // 根目录的dentry,用于检查文件系统是否装载。
struct hlist_node s_instances; // 连接到file_system_type中fs_supers链表。
void *s_fs_info; // 私有信息。
u32 s_time_gran; // 支持的时间戳最大粒度,单位:ns。
struct list_head s_inodes; // 文件系统中所有inode。
struct list_head s_files; // 文件系统中所有打开的文件。
struct list_head s_inodes_wb; // 文件系统中正在回写的inode。
unsigned char s_dirt; // 文件系统是否脏。
};
struct super_operations { //管理 inode
struct inode *(*alloc_inode)(struct super_block *sb);
//分配一个 inode 结构体。
void (*destroy_inode)(struct inode *);
// 释放 inode 结构体。
void (*free_inode)(struct inode *);
void (*dirty_inode) (struct inode *, int flags);
// 将一个 inode 标记为脏。
int (*write_inode) (struct inode *, struct writeback_control *wbc);
//将 inode 结构体写回磁盘。
int (*drop_inode) (struct inode *);
//引用计数为 0 时释放 inode 结构体。
void (*put_super) (struct super_block *);
//释放超级块占用的资源。
int (*sync_fs)(struct super_block *sb, int wait);
//将文件系统中未写入磁盘的数据都写回磁盘。
int (*statfs) (struct dentry *, struct kstatfs *);
//返回统计信息。包括:使用和未使用数据块数目等。
int (*remount_fs) (struct super_block *, int *, char *);
// 重新挂载文件系统。
};
mount 系统调用
根据不同选项,do_mount调用不同函数:
MS_REMOUNT 选项:
do_remount () //修改一个已装载的文件系统。
MS_MOVE 选项:
do_move_mount () //移动一个已装载文件系统。
默认选项:
do_new_mount () //普通装载,使用最多。
do_new_mount 流程:
共享子树
Linux 扩展的装载选项:
1. MS_SHARED,共享装载:
对挂载点的更改,将传播给所有共享的的其他挂载点。
2. MS_PRIVATE,私有装载:
私有挂载点的更改,不会传播给其他挂载点。
3. MS_SLAVE,从属装载:
跟随其上级挂载点的共享或私有状态。
4. MS_UNBINDABLE,不可绑定的装载:
不可将其绑定或移动到其他挂载点。
do_mount 中:
if ( flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
do_change_type( &path, flags ); //改变装载类型。
umount 系统调用
卸载文件系统。
装载的自动过期
使用场景:网络文件系统会使用。
将该装载从vfsmount树中移除。
伪文件系统
一个文件系统不一定需要底层块设备,如。
内存为后备存储器:ramfs,tmpfs。
无后备存储器:procfs,sysfs。
伪文件系统:应用层不可见,不能卸载。主要为了组织 inode,如:
bdev:管理块设备inode。
pipefs:处理管道。
sockfs:处理套接字。
cat /proc/filesystem:
可查看所有文件系统,包括伪文件系统。
标志 MS_NOUSER:
表示为伪文件系统,可防止被装载, 其余操作和普通文件系统一致。