为了实际测试这个pagecache和对裸盘操作的区别,我一不小心敲错命令,将一个磁盘的super_block给抹掉了,全是0,
dd if =/dev/zero of=/dev/sda2 bs=4096 count=1 seek=2234789
2234789是我的某个测试文件的起始块,debugfs看到的。
然后我手贱敲成:dd if =/dev/zero of=/dev/sda2 bs=4096 count=1 skip=2234789
太装逼的结果就是:我发现我的命令都无法使用了!!!
等我想备份的super_block拷贝回去的时候,发现dd命令用不了了,为了将损失
减少,我把这个磁盘挂掉其他服务器上,然后试图挂载,结果挂载不了,然后尝试恢复,在恢复过程中,环境又被人异常重启,等我第二次再去恢复的时候,很不幸,
恢复完了之后全部成了lost+found,
linux-a6me:~ # lsblk
NAME MAJ:MIN RM SIZE RO MOUNTPOINT
sdc : .1G
sdb : .1G
|-sdb1 : 2G [SWAP]
`-sdb2 : .1G /
sda : .1G
|-sda1 : 1G /root/test
|-sda2 : .1G
`-sda3 : 344K
linux-a6me:~ # mkdir /root/caq_home
linux-a6me:~ # mount -t ext4 /dev/sda2 /root/caq_home/
mount: warning: /root/caq_home/ seems to be mounted read-only.
linux-a6me:~ # cd /root/caq_home/
linux-a6me:~/caq_home # ls
lost+found

你没看错,所有的数据全部变成了lost+found.  297.1G 数据,哪怕就是一堆lost+found,结果filesystem的state还是: not clean with errors

dumpe2fs -h /dev/sda2
dumpe2fs 1.41. (-Aug-)
Filesystem volume name: <none>
Last mounted on: <not available>
Filesystem UUID: 20a05fdb--4f87-877d-4af17e31b76b
Filesystem magic number: 0xEF53
Filesystem revision #: (dynamic)
Filesystem features: ext_attr resize_inode dir_index filetype extent sparse_super large_file
Filesystem flags: signed_directory_hash
Default mount options: (none)
Filesystem state: not clean with errors
疼啊,功力不够能怪谁,所以简单看了关于super_block的内容,万一下次再遇到能好好处理下。
 
先看下super_block结构的成员有多么丰富,
crash> super_block
struct super_block {
struct list_head s_list;
dev_t s_dev;-------------------------------关联的设备
unsigned char s_blocksize_bits;-----------------块大小,转换为2的次方
unsigned long s_blocksize;---------------------块大小
loff_t s_maxbytes;
struct file_system_type *s_type;----------------文件系统类型,比如是xfs的还是ext4还是sockfs等
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;
void *s_security;
const struct xattr_handler **s_xattr;
struct list_head s_inodes;----------------------该super_block中所有inode的i_sb_list成员的双向链表
struct hlist_bl_head s_anon;
struct list_head *s_files_deprecated;
struct list_head s_mounts;
struct list_head s_dentry_lru;
int s_nr_dentry_unused;
spinlock_t s_inode_lru_lock;
struct list_head s_inode_lru;
int s_nr_inodes_unused;
struct block_device *s_bdev;-----------------这个是super_block对应的block_device,可以作为关键字用来比较相同fs_type的各个实例
struct backing_dev_info *s_bdi;
struct mtd_info *s_mtd;
struct hlist_node s_instances;---------------通过这个成员挂在同类型文件系统的hash链上,
struct quota_info s_dquot;
struct sb_writers s_writers;
char s_id[];-------------------------------挂载id,比如nvme1等
u8 s_uuid[];
void *s_fs_info;-----------------------------重点关注,指向私有机构,不同的fs_type有不同的解释,比如ext4指向 ext4_super_block,xfs指向xfs_mount等,
unsigned int s_max_links;
fmode_t s_mode;
u32 s_time_gran;
struct mutex s_vfs_rename_mutex;
char *s_subtype;
char *s_options;
const struct dentry_operations *s_d_op;
int cleancache_poolid;
struct shrinker s_shrink;
atomic_long_t s_remove_count;
int s_readonly_remount;
struct workqueue_struct *s_dio_done_wq;
struct callback_head rcu;
struct hlist_head s_pins;
}
SIZE:

一个文件系统,比如xfs,可能有多个superblock结构在内存中,比如两块硬盘,都是xfs格式,挂载之后就有两个superblock了。

/**
*  sget    -   find or create a superblock
*  @type:  filesystem type superblock should belong to
*  @test:  comparison callback
*  @set:   setup callback
*  @flags: mount flags
*  @data:  argument to each of them
*/
struct super_block *sget(struct file_system_type *type,
            int (*test)(struct super_block *,void *),
            int (*set)(struct super_block *,void *),
            int flags,
            void *data)
{
/*查找过程*/
hlist_for_each_entry(old, &type->fs_supers, s_instances) {
。。。。
 
如果没找到,那么alloc一个super_block,并加入到下面list
list_add_tail(&s->s_list, &super_blocks);//superblock,通过s_list成员,全部挂在一个super_blocks的全局链表尾
hlist_add_head(&s->s_instances, &type->fs_supers);//同类型的superblock,通过s_instance成员,串在对应type的->fs_super成员哈希链表中
。。。。。
}

查看一下这个super_blocks的双链表:

crash> list -H super_blocks
ffff880157908800-------------
ffff880157909000
ffff880157909800
ffff88015790c800
ffff88013d5d8800
ffff8828b5290800
。。。。

crash> super_block.s_type ffff880157908800
s_type = 0xffffffff81aa4100 <sysfs_fs_type>

 

我们可以看到,第一个super_block的fs_type一般是sysfs_fs_type,这个类型应该是最早注册的。谁越早就越排在前面,除非重新unregister了。因为内核中我们使用 file_systems 这个全局

变量来管理注册的fs,但是越晚加入同类型的fs的hlist的位置在hlist中越靠前。

p file_systems
file_systems = $ = (struct file_system_type *) 0xffffffff81aa4100 <sysfs_fs_type> crash> list file_system_type.next -s file_system_type.name,fs_flags 0xffffffff81aa4100
ffffffff81aa4100
name = 0xffffffff8194bffc "sysfs"
fs_flags =
ffffffff81a12440
name = 0xffffffff8192eaba "rootfs"
fs_flags =
ffffffff81aa4ee0
name = 0xffffffff8193196c "ramfs"
fs_flags =
ffffffff81a9ede0
name = 0xffffffff8192ef3f "bdev"
fs_flags =
ffffffff81aa3ba0
name = 0xffffffff81921ccf "proc"
fs_flags =
。。。。。

ffffffffc012c920
name = 0xffffffffc0122933 "ext3"
fs_flags = 513
ffffffffc012c960
name = 0xffffffffc0122938 "ext2"
fs_flags = 513
ffffffffc012c020
name = 0xffffffffc01221e4 "ext4"
fs_flags = 1537

。。。。

ffffffffc08b2000
name = 0xffffffffc0897006 "xfs"-------------这个业务使用的xfs
fs_flags = 3841

 

同fs_type类型的superblock,通过s_instance成员,串在对应type的->fs_super成员哈希链表中,比如我们看到的sysfs的实例有多少个:

crash> file_system_type.fs_supers 0xffffffff81aa4100
fs_supers = {
first = 0xffff880135c90938
}

crash> list  0xffff880135c90938 -l super_block.s_instances -s super_block.s_type
ffff880135c90938
s_type = 0xffffffff81aa4100 <sysfs_fs_type>
ffff88017fdc8938
s_type = 0xffffffff81aa4100 <sysfs_fs_type>

可以看到sysfs的实例是两个。

看下我们实际使用的xfs的实例:

[root@localhost code]# df -hT |grep xfs
/dev/nvme2n1 xfs .5T .1T 459G % /mnt/S481NY0K400047
/dev/nvme1n1 xfs .5T .1T 461G % /mnt/S481NY0K400054
/dev/nvme0n1 xfs .5T .1T 454G % /mnt/S481NY0K400067
/dev/nvme3n1 xfs .5T .1T 445G % /mnt/S481NY0K400044
/dev/sda xfs .9T 33M .9T % /mnt/P6KUWGKV

看下内核中打印:

crash> file_system_type ffffffffc08b2000
struct file_system_type {
name = 0xffffffffc0897006 "xfs",
fs_flags = ,
mount = 0xffffffffc08672c0,
kill_sb = 0xffffffff8120b990 <kill_block_super>,
owner = 0xffffffffc08bd280,
next = 0x0,
fs_supers = {
first = 0xffff881dfa68e138
},
s_lock_key = {<No data fields>},
s_umount_key = {<No data fields>},
s_vfs_rename_key = {<No data fields>},
s_writers_key = 0xffffffffc08b2038,
i_lock_key = {<No data fields>},
i_mutex_key = {<No data fields>},
i_mutex_dir_key = {<No data fields>}
}
crash> list 0xffff881dfa68e138 -l super_block.s_instances -s super_block.s_type
ffff881dfa68e138
s_type = 0xffffffffc08b2000
ffff88013cf76138
s_type = 0xffffffffc08b2000
ffff88220430c938
s_type = 0xffffffffc08b2000
ffff884973a25138
s_type = 0xffffffffc08b2000
ffff8827caa56138
s_type = 0xffffffffc08b2000

发现我们xfs的s_type并没有显示为xfs,我们把xfs模块加载进来:

crash> mod |grep xfs
ffffffffc08bd280 xfs (not loaded) [CONFIG_KALLSYMS] crash> mod -s xfs
MODULE NAME SIZE OBJECT FILE
ffffffffc08bd280 xfs /usr/lib/debug/usr/lib/modules/3.10.-693.21..el7.x86_64/kernel/fs/xfs/xfs.ko.debug
crash>
crash>

crash> list 0xffff881dfa68e138 -l super_block.s_instances -s super_block.s_type,s_bdev,s_id
ffff881dfa68e138
s_type = 0xffffffffc08b2000 <xfs_fs_type>
s_bdev = 0xffff8857b5688340
s_id = "sda\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
ffff88013cf76138
s_type = 0xffffffffc08b2000 <xfs_fs_type>
s_bdev = 0xffff8857b5690000
s_id = "nvme3n1\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
ffff88220430c938
s_type = 0xffffffffc08b2000 <xfs_fs_type>
s_bdev = 0xffff8827d3068000
s_id = "nvme0n1\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
ffff884973a25138
s_type = 0xffffffffc08b2000 <xfs_fs_type>
s_bdev = 0xffff8857b5688000
s_id = "nvme1n1\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
ffff8827caa56138
s_type = 0xffffffffc08b2000 <xfs_fs_type>
s_bdev = 0xffff8857b5698000
s_id = "nvme2n1\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"

 

这次可以显示为xfs_fs_type了,刚好5个实例,和df -hT对的上,id也对得上。

比较典型fs的type比较多,你看连sock都是属于一个fs。还有,我们注册自己的fs的话,也会体现在这个链表中。

static struct file_system_type sock_fs_type = {
.name = "sockfs",
.mount = sockfs_mount,
.kill_sb = kill_anon_super,
}; static struct file_system_type xfs_fs_type = {
.owner = THIS_MODULE,
.name = "xfs",
.mount = xfs_fs_mount,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV | FS_HAS_RM_XQUOTA |
FS_HAS_INVALIDATE_RANGE | FS_HAS_DIO_IODONE2 |
FS_HAS_NEXTDQBLK,
};

super_block放在一起有哪些用处,比如当我们需要控制pagecache的时候,如果是控制某一个fs_type的缓存,则尽量从file_systems中去找这个

file_system_type,然后 利用  hlist_for_each_entry 遍历其 成员就行,然后在迭代这些super_block 去控制inode中的内存占用。如果直接使用 iterate_supers  来迭代的话,需要将

不同的fs_type的super_block 过滤掉,比较麻烦,毕竟super_block有可能很多,但是单个file_system中的s_instance 则很精确了,所以这个时候推荐使用 iterate_supers_type 来迭代,不过suse 3.0.101没有这个函数,所以只能自己合入。
 
前面说了半天的super_block,要知道这个定义只是vfs层的,那么对应磁盘上的物理超级块是哪个结构来描述呢?
  
比如对于ext3,ext4等,对应的结构就是 ext4_super_block ,它是使用super_block中的 s_fs_info 这个成员。
 
网上说的是这个指针一定指向具体文件系统的super_block的结构,其实不是的,比如xfs,对应的就是 xfs_mount 。
 
superblock跟一个东西永远不分家,那就是mount,在用户态,我们使用mount和umount命令才挂载和卸载一个目录,调用链为:

sys_mount - >

do_mount-->

do_new_mount--->vfs_kern_mount(type, flags, name, data);

来看下内核态相关的实现:
static struct file_system_type xfs_fs_type = {
.owner = THIS_MODULE,
.name = "xfs",
.mount = xfs_fs_mount,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV | FS_HAS_RM_XQUOTA |
FS_HAS_INVALIDATE_RANGE | FS_HAS_DIO_IODONE2 |
FS_HAS_NEXTDQBLK,
};
STATIC struct dentry *
xfs_fs_mount(
struct file_system_type *fs_type,
int flags,
const char *dev_name,
void *data)
{
return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super);
}

mount_bdev 函数会根据mount的设备/dev/sdx,找到对应的block_device,

然后调用 前面刚介绍的 sget 函数来获取super_block,如果在全局链表中未找到的话,则申请一个super_block的结构,

并回调不同的fill_super 函数来填充这个super_block结构的相关成员,对于xfs是 xfs_fs_fill_super,

比如关键的s_op就是在此函数中设置的:

sb->s_fs_info = mp;
。。。 sb->s_op = &xfs_super_operations;

在读入物理设备上的superblock之前,会解析mount的参数,比如对于xfs,这个由 xfs_parseargs 负责:

xfs_init_mount_workqueues :每个xfs挂载设备,都会创建很多工作队列

xfs_init_percpu_counters :为了性能要求,创建percpu的计数器,

创建统计信息的结构,这个由 mp->m_stats.xs_stats = alloc_percpu(struct xfsstats);语句搞定:

xfs_readsb:准备工作完毕,开始真实的读取超级块的函数了,这个函数主要就是申请一个xfs_buf,然后构造bio,去读取指定位置的块,经过转换,把物理上的超级块结构转换为

内存中需要的一些结构,读取超级块,它的位置是0,注意这个0和mbr要区分开来,这个0的上下文是指这个分区的第0个块,而MBR在分区之外,事实上MBR中包含主引导程序和分区信息。

xfs_finish_flags :将一些挂载参数,xfs_parseargs  分析完的这些参数,使用xfs_finish_flags 继续填充 xfs_mount 的 m_sb成员。

xfs_setup_devices:处理 m_ddev_targp,m_logdev_targp,m_rtdev_targp 三个成员相关信息,如果指定了log写在其他设备,则 m_logdev_targp 不会为NULL,比如你把sata盘的
xfs 相关log写在ssd之类的,可以提高元数据刷写的效率。
xfs_filestream_mount,简单封装 xfs_mru_cache_create,mru是最近最常使用算法的简写,利用 xfs_params 这个全局变量的一些配置,申请空间,然后做mru算法实现。主要为AG使用。
super_block其余的一些成员初始化,一些新的特性,比如DAX的mount支持,也在此完成。
xfs_mountfs:前面的一些函数,将该申请的内存申请了,该填充的成员填充了,这个时候才是真正往系统mount的函数,
    a.比如该super_block支持的最多的inode个数计算,xfs_set_maxicount 等,比如当文件很小,inode可能不够用,导致命名磁盘有空间,但也无法新创建文件。
    b.往sys的fs注册一些常用的统计等,主要利用 xfs_sysfs_init 函数,注册的结果可以参考如下:
[root@localhost xfs]# pwd
/sys/fs/xfs
[root@localhost xfs]# ls
nvme0n1 nvme1n1 nvme2n1 nvme3n1 sda stats
[root@localhost xfs]#
   一些error的统计如下:
[root@localhost error]# ls
fail_at_unmount metadata
[root@localhost error]# pwd
/sys/fs/xfs/nvme0n1/error

c.挂载带uuid与否的一些判断。

d. xfs_set_rw_sizes,设置默认的最小read和write的size。

e.xfs_rtmount_init 实时挂载模式的处理,比如带 rtdev=device 的一些处理。

linux 文件系统之superblock的更多相关文章

  1. # linux文件系统(inode block superblock)

    先说一下格式化:每种操作系统所设置的文件属性/权限并不相同,为了存放这些文件所需的数据,因此就需要将分区格式化,以成为操作系统能够利用的文件系统格式.linux的文件格式为Ext2/Ext3,现在好像 ...

  2. Linux基础篇学习——Linux文件系统之文件存储与读取:inode,block,superblock

    Linux文件类型 代表符号 含义 - 常规文件,即file d directory,目录文件 b block device,块设备文件,支持以"block"为单位进行随机访问 c ...

  3. linux文件系统体系结构 和 虚拟文件系统(VFS)

    图 1. Linux 文件系统组件的体系结构 用户空间包含一些应用程序(例如,文件系统的使用者)和 GNU C 库(glibc),它们为文件系统调用(打开.读取.写和关闭)提供用户接口.系统调用接口的 ...

  4. linux 文件系统(inode和block)

    linux文件系统(inode block superblock)   先说一下格式化:每种操作系统所设置的文件属性/权限并不相同,为了存放这些文件所需的数据,因此就需要将分区格式化,以成为操作系统能 ...

  5. linux源代码阅读笔记 linux文件系统(转)

    linux文件系统:   操作系统的文件数据除了文件实际内容外,还有非常多的属性,如文件权限(rwx)与文件属性(所有者.群组.时间参数等).   文件系统通常将这两部分数据存放在不同的块.权限属性放 ...

  6. 【转】linux文件系统之mount流程分析

    本质上,Ext3 mount的过程实际上是inode被替代的过程. 例如,/dev/sdb块设备被mount到/mnt/alan目录.命令:mount -t ext3 /dev/sdb /mnt/al ...

  7. 理解Linux文件系统之inode

    很少转发别人的文章,但是这篇写的太好了. 理解inode   作者: 阮一峰 inode是一个重要概念,是理解Unix/Linux文件系统和硬盘储存的基础. 我觉得,理解inode,不仅有助于提高系统 ...

  8. (转)Linux文件系统的实现

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! Linux文件管理从用户的层面介绍了Linux管理文件的方式.Linux有一个树状 ...

  9. Linux 文件系统剖析

    [转自]https://www.ibm.com/developerworks/cn/linux/l-linux-filesystem/ 按照分层结构讨论 Linux 文件系统 在文件系统方面,Linu ...

随机推荐

  1. 集合--(List、Set、Map)遍历、删除、比较元素时的小陷阱

    6,Map集合遍历的4中方法? 5,List遍历时如何remove元素 4.漏网之鱼-for循环递增下标方式遍历集合,并删除元素 如果你用for循环递增下标方式遍历集合,在遍历过程中删除元素,你可能会 ...

  2. 代码整洁之道Clean Code 读后感After Reading

    1.有意义的命名 名副其实,避免误导 做有意义的区分,简单明了2.函数 短小,职责单一 别重复自己3.注释 用代码来阐述 可怕的废话4.格式 垂直格式,垂直距离,空范围 横向格式,水平对齐,缩进5.错 ...

  3. 第10课 std::bind和std::function(1)_可调用对象

    1. 几种可调用对象(Callable Objects) (1)普通函数指针或类成员的函数指针 (2)具有operator()成员函数的类对象(仿函数).如c++11中的std::function类模 ...

  4. mac gcc develop

    1:check version gcc -v   /   g++ -v 2:compile gcc *.c   / g++ *.cpp outfile: a.out 3:excute ./a.out ...

  5. Don't afraid point

    int p; int *p; int p[3]; int *p[3];分析方式:首先从P开始分析,先与[]结合因为其优先级比*高,所以p是一个数组,然后再与*结合,说明数组里的元素是指针类型,然后再与 ...

  6. MySQL--局域网、外网访问MySQL

    一.局域网.外网访问 1. 打开CMD,导航到当前MySQL的bin路径,如下图: 2. 访问MySQL:输入MySQL -u root -p,点击Enter键,即可看到密码输入框: 输入密码,点需E ...

  7. vue 整合element-ui

    本文主要介绍如何在vue框架中结合elementUI. 本文主要参考: http://element-cn.eleme.io/#/zh-CN/component/quickstart   1.阅读本文 ...

  8. oracle提高查询效率的34个方面全解析

    oracle提高查询效率的34个方面全解析   在一个数据库中进行操作的时候,效率是很重要的,那么,如何提高oracle的查询效率呢?笔者将从以下几个方面进行详细解析: 1.选择最有效率的表名顺序(只 ...

  9. 背景图片的移动----background-attach-----background-repeat

    background-repeat:默认是平铺的,也即是还有空间的话将一张接着一张显示 设置为 no-repeat  就最多显示一张 background-attachment:设置是否固定图片,在有 ...

  10. 20165205 2017-2018-2 《Java程序设计》第九周学习总结

    20165205 2017-2018-2 <Java程序设计>第九周学习总结 教材学习内容总结 掌握URL类的使用方法 URL类的构造方法: public URL(String spec) ...