linux 文件系统之superblock

摘要:
为了实际测试页面缓存和裸磁盘操作之间的差异,我无意中单击了错误的命令_块被擦除。它们都是0。ddif=/dev/zero=/dev/sda2bs=4096count=seek=22347892234789是我的一个测试文件的起始块,如debugfs所示。然后我键入它:ddif=/dev/zero=/dev/sda2bs=4096count=1skip=2234789!!!
为了实际测试这个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      8:32   0 298.1G  0
sdb      8:16   0 298.1G  0
|-sdb1   8:17   0     2G  0 [SWAP]
`-sdb2   8:18   0 296.1G  0 /
sda      8:0    0 298.1G  0
|-sda1   8:1    0     1G  0 /root/test
|-sda2   8:2    0 297.1G  0
`-sda3   8:3    0   344K  0
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.9 (22-Aug-2009)
Filesystem volume name:   <none>
Last mounted on:          <not available>
Filesystem UUID:          20a05fdb-4060-4f87-877d-4af17e31b76b
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (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[32];-------------------------------挂载id,比如nvme1等
    u8 s_uuid[16];
    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: 1088

一个文件系统,比如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 = $2 = (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 = 8
ffffffff81a12440
  name = 0xffffffff8192eaba "rootfs"
  fs_flags = 0
ffffffff81aa4ee0
  name = 0xffffffff8193196c "ramfs"
  fs_flags = 8
ffffffff81a9ede0
  name = 0xffffffff8192ef3f "bdev"
  fs_flags = 0
ffffffff81aa3ba0
  name = 0xffffffff81921ccf "proc"
  fs_flags = 8
。。。。。

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              3.5T  3.1T  459G  88% /mnt/S481NY0K400047
/dev/nvme1n1   xfs              3.5T  3.1T  461G  88% /mnt/S481NY0K400054
/dev/nvme0n1   xfs              3.5T  3.1T  454G  88% /mnt/S481NY0K400067
/dev/nvme3n1   xfs              3.5T  3.1T  445G  88% /mnt/S481NY0K400044
/dev/sda       xfs              1.9T   33M  1.9T   1% /mnt/P6KUWGKV

看下内核中打印:

crash> file_system_type ffffffffc08b2000
struct file_system_type {
  name = 0xffffffffc0897006 "xfs",
  fs_flags = 3841,
  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                  978100  (not loaded)  [CONFIG_KALLSYMS]

crash> mod -s xfs
     MODULE       NAME                   SIZE  OBJECT FILE
ffffffffc08bd280  xfs                  978100  /usr/lib/debug/usr/lib/modules/3.10.0-693.21.1.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

免责声明:内容来源于网络,仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇iOS开发UI篇—xib的简单使用binary hacks读数笔记(ld 链接讲解 二)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Linux进程调度与源码分析(三)——do_fork()的实现原理

        用户层的fork(),vfork(),clone()API函数在执行时,会触发系统调用完成从用户态陷入到内核态的过程,而上述函数的系统调用,最终实现都是通过内核函数do_fork()完成,本篇着重分析do_forkI()函数的实现过程。         Linux操作系统中,产生一个新的进程和产生一个新的线程对于内核来说,最为本质的区别在于...

Linux Makefile analysis for plain usr

一、本文主旨   笔者写了一篇linux内核Makefile整体分析 ,测重于理论分析,对于实际应用不算对头,所以需要写一篇实用性较强的文章,为以后内核、驱动移植做好铺垫。 二、本文内容概要 1、编译哪些文件 2、怎样编译这些文件 3、怎样连接这些文件,它们的顺序如何 三、编译哪些文件   本文的实验源码是对“linux-2.6.30.4”进行移植后的运行...

linux shell中读写操作mysql数据库

本文介绍了如何在shell中读写mysql数据库。主要介绍了如何在shell 中连接mysql数据库,如何在shell中创建数据库,创建表,插入csv文件,读取mysql数据库,导出mysql数据库为xml或html文件, 并分析了核心语句。本文介绍的方法适用于PostgreSQL ,相对mysql而言,shell 中读写PostgreSQL会更简单些。1...

Linux shell command line process(命令行处理流程)

Splits the command into tokens that are separated by the fixed set of metacharacters: SPACE, TAB, NEWLINE,;,(,),<,>,|, and&. Types of tokens include words, keywords,...

PostgreSQL在Linux上的RPM和源码安装

第一章 引言 此文档主要描述Postgre数据库,基于Red Hat Enterprise Linux Server release 6.5 的操作系统上安装Postgre数据库的文档衍生而来。此文档包括Postgre数据库的多种安装方式。 1.1 背景 本文档介绍Postgre 数据库基于linux 6.5平台的三种安装方式。 第二章 部署前规划...

linux下使用find xargs grep查找文件及文件内容

1,在某个路径下查文件。 在/etc下查找“*.log”的文件 find /etc -name “*.log” 2,扩展,列出某个路径下所有文件,包括子目录。 find /etc -name “*” 3,在某个路径下查找所有包含“hello abcserver”字符串的文件。 find /etc -name “*” | xargs grep “...