zoukankan      html  css  js  c++  java
  • JBD日志的定位、分析和恢复

     在上一篇中,我们介绍了Ext3文件系统的日志可以看做一个文件,由JBD进行管理。自然而然引出如下这些问题:

    1)如何定位ext3日志文件和查看日志文件的裸数据?

    2)ext3日志文件数据在物理上是如何布局的?

    3)JBD如何利用日志文件进行数据恢复?

    带着这些问题,开始这次探索之旅。

    JBD日志定位

    首先找到ext3 日志文件的inode

    / # /dumpe2fs /dev/sda1
    dumpe2fs 1.42 (29-Nov-2011)
    Filesystem volume name:   shouxian<none>
    Last mounted on:          <not available>
    Filesystem UUID:          513c186a-108b-4840-ad98-aa8e8f62d4c8
    Filesystem magic number:  0xEF53
    Filesystem revision #:    1 (dynamic)
    Filesystem features:      has_journal ext_attr resize_inode dir_index filetype sparse_super large_file
    Filesystem flags:         signed_directory_hash
    Default mount options:    user_xattr acl
    Filesystem state:         clean
    Errors behavior:          Continue
    Filesystem OS type:       Linux
    Inode count:              513072
    Block count:              2048276
    Reserved block count:     102413
    Free blocks:              1978758
    Free inodes:              513061
    First block:              0
    Block size:               4096
    Fragment size:            4096
    Reserved GDT blocks:      500
    Blocks per group:         32768
    Fragments per group:      32768
    Inodes per group:         8144
    Inode blocks per group:   509
    Filesystem created:       Sat Mar 21 11:39:13 2015
    Last mount time:          n/a
    Last write time:          Sat Mar 21 11:39:14 2015
    Mount count:              0
    Maximum mount count:      -1
    Last checked:             Sat Mar 21 11:39:13 2015
    Check interval:           0 (<none>)
    Reserved blocks uid:      0 (user root)
    Reserved blocks gid:      0 (group root)
    First inode:              11
    Inode size:               256
    Required extra isize:     28
    Desired extra isize:      28
    Journal inode:            8
    Default directory hash:   half_md4
    Directory Hash Seed:      08091c3c-7a35-4f5b-8477-7af597c5eb50
    Journal backup:           inode blocks
    Journal features:         (none)
    Journal size:             128M
    Journal length:           32768
    Journal sequence:         0x00000001
    Journal start:            0
    

      

    然后找到inode所在的数据块

    # /debugfs -R 'imap <8>' /dev/sda1
    debugfs 1.42 (29-Nov-2011)
    Inode 8 is part of block group 0
            located at block 504, offset 0x0700
    

    根据块号、块大小和偏移,换算出inode所在数据块的物理偏移(以256B为单位)

    >>> (504*4096+0x700)/256.
    8071.0
    

    读出这个inode的数据

    # dd if=/dev/sda1 of=inode.8 bs=256 count=1 skip=8071
    1+0 records in
    1+0 records out
    256 bytes (256B) copied, 0.000955 seconds, 261.8KB/s
    
    /usr/lib # hexdump inode.8
    0000000 8081 0000 0000 0008 6258 0d55 6258 0d55
    0000010 6258 0d55 0000 0000 0000 0100 0801 0400
    0000020 0000 0000 0000 0000 ff01 0f00 0002 0f00
    0000030 0102 0f00 0202 0f00 0302 0f00 0402 0f00
    0000040 0502 0f00 0602 0f00 0702 0f00 0802 0f00
    0000050 0902 0f00 0a02 0f00 0b02 0f00 0c06 0f00
    0000060 0000 0000 0000 0000 0000 0000 0000 0000
    *
    0000080 1c00 0000 0000 0000 0000 0000 0000 0000
    0000090 6258 0d55 0000 0000 0000 0000 0000 0000
    00000a0 0000 0000 0000 0000 0000 0000 0000 0000
    *
    0000100
    

    对照inode数据结构,找到其管理的数据块块号(蓝色标示),前12映射槽是直接映射,直接管理的数据块块号从0x0f01ff(983551)到0x0f020b,属于group 30。

    Group 30: (Blocks 983040-1015807)
      Block bitmap at 983040 (+0), Inode bitmap at 983041 (+1)
      Inode table at 983042-983550 (+2)
      0 free blocks, 8144 free inodes, 0 directories
      Free blocks:
      Free inodes: 244321-252464
     
    

    至此,终于可以dump出日志文件数据块内容。

    # dd if=/dev/sda1 of=inode.8.data bs=4096 count=12 skip=983551
    1+0 records in
    1+0 records out
    4096 bytes (4.0KB) copied, 0.000942 seconds, 4.1MB/s
    
    0000000 c03b 3998 0000 0004 0000 0000 0000 1000
    0000010 0000 8000 0000 0001 0000 0002 0000 0001
    0000020 0000 0000 0000 0000 0000 0000 0000 0000
    0000030 513c 186a 108b 4840 ad98 aa8e 8f62 d4c8
    0000040 0000 0001 0000 0000 0000 0000 0000 0000
    0000050 0000 0000 0000 0000 0000 0000 0000 0000
    *
    0001000 c03b 3998 0000 0001 0000 0002 0000 01f8
    0001010 0000 0008 0000 0000 0000 0000 0000 0000
    0001020 0000 0000 0000 0000 0000 0000 0000 0000
    *
    0002000 0000 0000 0000 0000 6158 0d55 6158 0d55
    0002010 6158 0d55 0000 0000 0000 0000 0000 0000
    0002020 0000 0000 0000 0000 0000 0000 0000 0000
    *
    0002100 ed41 0000 0010 0000 d75d 0d55 6158 0d55    
    0002110 6158 0d55 0000 0000 0000 0300 0800 0000
    0002120 0000 0000 0000 0000 f503 0000 0000 0000
    0002130 0000 0000 0000 0000 0000 0000 0000 0000
    *
    0002180 1c00 0000 0000 0000 0000 0000 0000 0000
    0002190 6158 0d55 0000 0000 0000 0000 0000 0000
    00021a0 0000 0000 0000 0000 0000 0000 0000 0000
    *
    0002600 8081 0000 00c0 4000 6158 0d55 6158 0d55
    0002610 6158 0d55 0000 0000 0000 0100 a88c 0000
    0002620 0000 0000 0000 0000 0000 0000 0000 0000
    *
    0002650 0000 0000 0000 0000 0000 0000 fa03 0000
    0002660 0000 0000 0000 0000 0000 0000 0100 0000
    0002670 0000 0000 0000 0000 0000 0000 0000 0000
    0002680 1c00 0000 0000 0000 0000 0000 0000 0000
    0002690 6158 0d55 0000 0000 0000 0000 0000 0000
    00026a0 0000 0000 0000 0000 0000 0000 0000 0000
    *
    0002700 8081 0000 0000 0008 6258 0d55 6258 0d55
    0002710 6258 0d55 0000 0000 0000 0100 0801 0400
    0002720 0000 0000 0000 0000 ff01 0f00 0002 0f00
    0002730 0102 0f00 0202 0f00 0302 0f00 0402 0f00
    0002740 0502 0f00 0602 0f00 0702 0f00 0802 0f00
    0002750 0902 0f00 0a02 0f00 0b02 0f00 0c06 0f00
    0002760 0000 0000 0000 0000 0000 0000 0000 0000
    *
    0002780 1c00 0000 0000 0000 0000 0000 0000 0000
    0002790 6258 0d55 0000 0000 0000 0000 0000 0000
    00027a0 0000 0000 0000 0000 0000 0000 0000 0000
    *
    0002a00 c041 0000 0040 0000 6158 0d55 6158 0d55
    0002a10 6158 0d55 0000 0000 0000 0200 2000 0000
    0002a20 0000 0000 0000 0000 f603 0000 f703 0000
    0002a30 f803 0000 f903 0000 0000 0000 0000 0000
    0002a40 0000 0000 0000 0000 0000 0000 0000 0000
    *
    0002a80 1c00 0000 0000 0000 0000 0000 0000 0000
    0002a90 6158 0d55 0000 0000 0000 0000 0000 0000
    0002aa0 0000 0000 0000 0000 0000 0000 0000 0000
    *
    0003000 c03b 3998 0000 0002 0000 0002 0000 0000     
    0003010 0000 0000 0000 0000 0000 0000 0000 0000
    *
    以下略
    

    JBD日志分析

    0000000 -- 0001000 数据块:

      日志超级块段,存储的是journal_superblock_t数据,从中可以看出块类型为JFS_SUPERBLOCK_V2(4),日志块大小: 0x1000; 日志块个数: 0x8000。进而可以计算出日志总大小为:0x1000 * 0x8000 = 128M。

    /*
    * Standard header for all descriptor blocks:
    */
    typedef struct journal_header_s
    {
    __be32	h_magic;
    __be32	h_blocktype;
    __be32	h_sequence;
    } journal_header_t;
    
    /*
     * The journal superblock.  All fields are in big-endian byte order.
     */
    typedef struct journal_superblock_s
    {
    /* 0x0000 */
    	journal_header_t s_header;
    
    /* 0x000C */
    	/* Static information describing the journal */
    	__be32	s_blocksize;		/* journal device blocksize */
    	__be32	s_maxlen;		/* total blocks in journal file */
    	__be32	s_first;		/* first block of log information */
    
    /* 0x0018 */
    	/* Dynamic information describing the current state of the log */
    	__be32	s_sequence;		/* first commit ID expected in log */
    	__be32	s_start;		/* blocknr of start of log */
    
    /* 0x0020 */
    	/* Error value, as set by journal_abort(). */
    	__be32	s_errno;
    
    /* 0x0024 */
    	/* Remaining fields are only valid in a version-2 superblock */
    	__be32	s_feature_compat;	/* compatible feature set */
    	__be32	s_feature_incompat;	/* incompatible feature set */
    	__be32	s_feature_ro_compat;	/* readonly-compatible feature set */
    /* 0x0030 */
    	__u8	s_uuid[16];		/* 128-bit uuid for journal */
    
    /* 0x0040 */
    	__be32	s_nr_users;		/* Nr of filesystems sharing log */
    
    	__be32	s_dynsuper;		/* Blocknr of dynamic superblock copy*/
    
    /* 0x0048 */
    	__be32	s_max_transaction;	/* Limit of journal blocks per trans.*/
    	__be32	s_max_trans_data;	/* Limit of data blocks per trans. */
    
    /* 0x0050 */
    	__u32	s_padding[44];
    
    /* 0x0100 */
    	__u8	s_users[16*48];		/* ids of all fs'es sharing the log */
    /* 0x0400 */
    } journal_superblock_t;
    

    0001000 -- 0002000 数据块:

      日志描述符块,开头存储的是journal_header_t,然后紧跟着journal_block_tag_t数据表。从中可以看出块类型为JFS_DESCRIPTOR_BLOCK(1), transaction id为2。只有一个tag,tag的block号为0x1f8, flag为JFS_FLAG_LAST_TAG(8)。此外,第一个tag后面会额外跟着一个16个字节的j_uuid,具有相同uuid的tag以JFS_FLAG_SAME_UUID(2)标示,最后一个tag flag以JFS_FLAG_LAST_TAG置位标示。

    /*
     * The block tag: used to describe a single buffer in the journal
     */
    typedef struct journal_block_tag_s
    {
    	__be32		t_blocknr;	/* The on-disk block number */
    	__be32		t_flags;	/* See below */
    } journal_block_tag_t;
    

    0002000 -- 0003000 数据块:

      元数据块,紧跟着DESCRIPTOR_BLOCK,一个tag对应一个块,块的个数由tag的个数决定。此示例中只有一个tag,所以只有一个数据块。这个块中的数据,在日志恢复或journal load时会写到存储设备文件系统的真实物理块(即tag的t_blocknr)上。

    0003000 -- 0004000 数据块:

      日志提交块。表示一个完整的transaction。从中可以看出块类型为JFS_COMMIT_BLOCK(2), transaction id为2,与前面的日志描述块匹配。

    JBD日志恢复

     如果文件系统崩溃或者unclean umount 重启造成文件系统损坏,当再次mount日志文件系统后,ext3文件系统会根据JBD日志文件进行日志恢复动作。

    JBD的日志恢复分3个阶段:
    第一个阶段PASS_SCAN
      完成日志一致性检查,查找日志尾部,获取start_transaction和end_transaction ID等信息;
    第二个阶段PASS_REVOKE
      搜索revoke块(revoke块中存储需要丢弃的块号),统计nr_revokes个数,构造revoke块hash表;避免回放revoke块,破坏数据块内容,造成文件系统损坏;
    第三个阶段PASS_REPLAY
      对日志中满足条件的数据块进行回放;拷贝日志中的数据块到文件系统真实位置:
      1)块号不在revoke块hash表中;
      2)此数据块所在的描述块commit ID大于revoke块的commit ID,即在revoke块后面;

    然后设置日志的j_transaction_sequence为下个transaction ID,保证日志中已存在的日志记录都无效;
    清空revoke块列表,同步存储设备,至此ext3日志完成恢复。

    --EOF--

  • 相关阅读:
    Android动画系列
    Handler处理机制
    cp命令覆盖文件时不用按Y来确认的方法
    phantomjs
    无界面模式
    win10上安装keras
    MongoDB 排序
    MongoDB 条件操作符
    MongoDB 对象操作
    SQL 和 NoSQL 的区别
  • 原文地址:https://www.cnblogs.com/wahaha02/p/4812860.html
Copyright © 2011-2022 走看看