1. 虚拟文档系统
虚拟文档系统(VFS)是内核子系统,是内核中文档系统的抽象层,为用户空间提供文档系统相关接口。
通过虚拟文档系统,进程可以利用标准Linux文档系统调用在不同的文档系统中进行交互和操作。
文档系统层次结构
VFS目录树结构
2. 挂载文档系统
挂载文档系统的过程是将某一设备(dev_name)上某一文档系统(file_system_type)安装到VFS目录树上的某一安装点(dir_name)。
挂载过程实际上将表示各实际文档系统的 struct file_system_type 数据结构的实例化形成一个链表,内核中用一个名为 file_systems 的全局变量来指向该链表的表头。
1
2
3
4
5
6
7
8struct file_system_type {
const char *name;
int fs_flags;
struct super_block *(*read_super) (struct super_block *, void *, int);
struct module *owner;
struct file_system_type * next;
struct list_head fs_supers;
};
初始过程由sys_mount() 系统调用函数发起,例如将/dev/sdb挂载到/sdb目录:
1sys_mount("sdb","/sdb ","ext4",…);
挂载之后对/sdb目录的操作最后会转化成ext4文档系统提供的接口调用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29write --> system_write --> vfs_write --> __vfs_write
ssize_t __vfs_write(struct file *file, const char __user *p, size_t count,
loff_t *pos)
{
if (file->f_op->write)
return file->f_op->write(file, p, count, pos);
else if (file->f_op->write_iter)
return new_sync_write(file, p, count, pos);
else
return -EINVAL;
}
const struct file_operations ext4_file_operations = {
.llseek= ext4_llseek,
.read_iter= ext4_file_read_iter,
.write_iter= ext4_file_write_iter,
.unlocked_ioctl = ext4_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl= ext4_compat_ioctl,
#endif
.mmap= ext4_file_mmap,
.open= ext4_file_open,
.release= ext4_release_file,
.fsync= ext4_sync_file,
.get_unmapped_area = thp_get_unmapped_area,
.splice_read= generic_file_splice_read,
.splice_write= iter_file_splice_write,
.fallocate= ext4_fallocate,
};
3. Page Cache and Buffer Cache
Linux内核中设有缓冲区高速缓存或页面高速缓存,大多数磁盘I/O都通过缓冲进行。当将数据写入文档时,内核通常先将该数据复制到其中一个缓冲区中,如果该缓冲区尚未写满,则并不将其排入输出队列,而是等待其写满或者当内核需要重用该缓冲区以便存放其他磁盘块数据时,再将该缓冲排入输出队列,然后待其到达队首时,才进行实际的I/O操作。这种输出方式被称为延迟写(delayed write)。
Page cache是vfs文档系统层的cache,每个文档都会有一棵radix树管理文档的缓存页,这些被管理的缓存页被称之为page cache。
Buffer cache是针对设备的,每个设备都会有一棵radix树管理数据缓存块。
写入Page Cache的数据会导致大量的脏页, 在内存中累积起来的脏页必须被写回到磁盘,在一下两种情况下,脏页会被pdflush后台回写进程写回到磁盘:在空闲内存低于一个特定的阈值时,内核必须将脏页写回磁盘,以便释放内存。
当脏页在内存中驻留超过一定的阈值时,内核必须将超时的脏页写会磁盘,以确保脏页不会无限期地驻留在内存中。
用户进程显示调用sync()和fsync()系统调用时,内核也会按要求将数据回写进磁盘。
sync函数只是将所有修改过的块缓冲区排入写队列,然后就返回,它并不等待实际写磁盘操作结束。
系统对Page Cache会维护两个list:active list, 记录当前hot的cache
inactive list,记录当前不hot的cache。 如果一个page长时间未操作,它会从active list移到inactive list。 在系统内存不够用,或者超过一定时间之后,list中cache会被系统回收。1
2
3
4
5
6
7
8
9
10
11total used free shared buffers cached
Mem: 1990 561 1428 8 125 151
-/+ buffers/cache: 284 1705
Swap: 2063 0 2063
Dirty: 8 kB
[[email protected] sdb]# cat /proc/meminfo | grep Dirty
Dirty: 0 kB
4.文档系统恢复
4.1 文档系统损坏
所有的对文档系统metadata的修改首先是修改其在内存中的拷贝,然后才会被写到磁盘上去。其中一部分是立即写到磁盘上,其他的则是在调用sync的时候才会被写到磁盘上。
在系统突然关机时(内核panic或突然断电)可能出现文档系统损坏或者文档未正常链接。
举一个例子: rm file命令会引起以下的一些改变:file的目录的条目被清除。
用来描述file的 inode 被释放
用来索引剩余数据块和剩余
inode 的映射图被更新
超级块中的剩余数据块的数量和inode的数量被更新
如果在进行这些过程中系统突然崩溃,就会使metadata数据产生不一致。
例如: 如果file的目录条目已经被清除, 但是inode还没有被释放, 结果就是一个inode有一个链接, 但是并没有目录结构指向这个inode。 这就是不一致的metadata。
4.2 文档系统修复
fsck或其他同类工具都可以检查损害的文档系统,并尽可能恢复其中的数据。
fsck.ext4 /dev/sdb
为了修正文档系统的错误,fsck会删除一个或者多个文档,观察fsck输出的”REMOVE”的信息,确保从硬盘上恢复受影响的文档。
4.3 lost+found目录孤儿文档(orphan files): 正确的文档系统,分区中每个扇区都被编档,要么为空闲,要么被文档占用。 出错后,当fsck发现某些扇区并非空闲,但其所属文档并未编辑在册,或者说是黑户,fsck便为其命名并编入lost+found目录。
/lost+found:存储fsck用的孤儿文档,和其他有问题的文档
如果你不小心删除了lost+found目录,不用使用mkdir命令创建lost+found目录,应该使用 mklost+found命令创建。