xfs bmap实现简析

来源:互联网 发布:网络流行文化有哪些 编辑:程序博客网 时间:2024/05/23 01:04
1.xfs_bmap用于对用户数据进行存储管理,其中的重点有延时分配和预分配
    设计源码文件xfs_bmap.h xfs_bmap.c xfs_bmap_tree.h xfs_bmap_tree.c

2.依赖:
    xfs bmap和xfs bmap tree的实现依赖于xfs_btree的实现,独立分析。

3.头文件设计的核心数据结构及宏分析
xfs_bmap.h
    typedef struct xfs_bmap_free_item
    {
            xfs_fsblock_t           xbfi_startblock;/* starting fs block number */
            xfs_extlen_t            xbfi_blockcount;/* number of blocks in extent */
            struct xfs_bmap_free_item *xbfi_next;   /* link to next entry */
    } xfs_bmap_free_item_t;
    该结构用于稍后将释放的extent的map信息,根据xbfi_startblock排序

    typedef struct xfs_bmap_free
    {
            xfs_bmap_free_item_t    *xbf_first;     /* list of to-be-free extents */
            int                     xbf_count;      /* count of items on list */
            int                     xbf_low;        /* alloc in low mode */
    } xfs_bmap_free_t;
    即将释放的extent的链表头
    xbf_low:表示分配器启用低空间分配算法,what is lowspace algorithm?

    #define XFS_BMAP_MAX_NMAP       4

    #define XFS_BMAPI_ENTIRE        0x001   /* return entire extent, not trimmed */
    #define XFS_BMAPI_METADATA      0x002   /* mapping metadata not user data */
    #define XFS_BMAPI_ATTRFORK      0x004   /* use attribute fork not data */
    #define XFS_BMAPI_PREALLOC      0x008   /* preallocation op: unwritten space */
    #define XFS_BMAPI_IGSTATE       0x010   /* Ignore state - */
                                                                                /* combine contig. space */
    #define XFS_BMAPI_CONTIG        0x020   /* must allocate only one extent */

    /*
     * unwritten extent conversion - this needs write cache flushing and no additional
     * allocation alignments. When specified with XFS_BMAPI_PREALLOC it converts
     * from written to unwritten, otherwise convert from unwritten to written.
     */
    #define XFS_BMAPI_CONVERT       0x040
    #define XFS_BMAPI_STACK_SWITCH  0x080    /* 用于分配存储空间时调用__xfs_bmapi_allocate是直接调用
                                                                                            * 还是用分配工作队列,默认使用分配工作队列; 仅函数
                                                                                            * xfs_iomap_write_allocate使用该方法,用于延时分配
                                                                                            * 延时分配直接调用分配函数,已提高延时分配的效率 */

    #define DELAYSTARTBLOCK         ((xfs_fsblock_t)-1LL)
    #define HOLESTARTBLOCK          ((xfs_fsblock_t)-2LL)

    /*
     * Flags for xfs_bmap_add_extent*.
     */
    #define BMAP_LEFT_CONTIG        (1 << 0)
    #define BMAP_RIGHT_CONTIG       (1 << 1)
    #define BMAP_LEFT_FILLING       (1 << 2)
    #define BMAP_RIGHT_FILLING      (1 << 3)
    #define BMAP_LEFT_DELAY         (1 << 4)
    #define BMAP_RIGHT_DELAY        (1 << 5)
    #define BMAP_LEFT_VALID         (1 << 6)
    #define BMAP_RIGHT_VALID        (1 << 7)
    #define BMAP_ATTRFORK           (1 << 8)

    typedef struct xfs_bmalloca {
        xfs_fsblock_t           *firstblock; /* i/o first block allocated */
        struct xfs_bmap_free    *flist; /* bmap freelist */
        struct xfs_trans        *tp;    /* transaction pointer */
        struct xfs_inode        *ip;    /* incore inode pointer */
        struct xfs_bmbt_irec    prev;   /* extent before the new one */
        struct xfs_bmbt_irec    got;    /* extent after, or delayed */

        xfs_fileoff_t           offset; /* offset in file filling in */
        xfs_extlen_t            length; /* i/o length asked/allocated */
        xfs_fsblock_t           blkno;  /* starting block of new extent */

        struct xfs_btree_cur    *cur;   /* btree cursor */
        xfs_extnum_t            idx;    /* current extent index */
        int                     nallocs;/* number of extents alloc'd */
        int                     logflags;/* flags for transaction logging */

        xfs_extlen_t            total;  /* total blocks needed for xaction */
        xfs_extlen_t            minlen; /* minimum allocation size (blocks) */
        xfs_extlen_t            minleft; /* amount must be left after alloc */
        char                    eof;    /* set if allocating past last extent */
        char                    wasdel; /* replacing a delayed allocation */
        char                    userdata;/* set if is user data */
        char                    aeof;   /* allocated space at eof */
        char                    conv;   /* overwriting unwritten extents */
        char                    stack_switch; /* for delayed allocation, call directly function:__xfs_bmapi_allocate,
                                                                don't use allocate workqueue. Because of delayed allocation need to
                                                                response as fast as quickly */
        int                     flags;
        struct completion       *done;
        struct work_struct      work;
        int                     result;
    } xfs_bmalloca_t;

xfs_bmap_tree.h    
    /*
     * Bmap root header, on-disk form only.
     */
    typedef struct xfs_bmdr_block {
            __be16          bb_level;       /* 0 is a leaf */
            __be16          bb_numrecs;     /* current # of data records */
    } xfs_bmdr_block_t;

    /*
     * Bmap btree record and extent descriptor.
     *  l0:63 is an extent flag (value 1 indicates non-normal).
     *  l0:9-62 are startoff.
     *  l0:0-8 and l1:21-63 are startblock.
     *  l1:0-20 are blockcount.
     */
    #define BMBT_EXNTFLAG_BITLEN    1
    #define BMBT_STARTOFF_BITLEN    54
    #define BMBT_STARTBLOCK_BITLEN  52
    #define BMBT_BLOCKCOUNT_BITLEN  21

    记录在设备上的格式
    typedef struct xfs_bmbt_rec {
            __be64                  l0, l1;
    } xfs_bmbt_rec_t;
    typedef xfs_bmbt_rec_t xfs_bmdr_rec_t;
   
    记录在内存中的格式
    typedef struct xfs_bmbt_rec_host {
            __uint64_t              l0, l1;
    } xfs_bmbt_rec_host_t;

    /*
     * Incore version of above.
     */
    typedef struct xfs_bmbt_irec
    {
            xfs_fileoff_t   br_startoff;    /* starting file offset */
            xfs_fsblock_t   br_startblock;  /* starting block number */
            xfs_filblks_t   br_blockcount;  /* number of blocks */
            xfs_exntst_t    br_state;       /* extent state */
    } xfs_bmbt_irec_t;
   
    /*
     * Possible extent formats.
     */
    typedef enum {
            XFS_EXTFMT_NOSTATE = 0,
            XFS_EXTFMT_HASSTATE
    } xfs_exntfmt_t;

    /*
     * Possible extent states.
     */
    typedef enum {
            XFS_EXT_NORM, XFS_EXT_UNWRITTEN,
            XFS_EXT_DMAPI_OFFLINE, XFS_EXT_INVALID
    } xfs_exntst_t;

    /*
     * Key structure for non-leaf levels of the tree.
     */
    typedef struct xfs_bmbt_key {
            __be64          br_startoff;    /* starting file offset */
    } xfs_bmbt_key_t, xfs_bmdr_key_t;

    /* btree pointer type */
    typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
   
4.xfs_bmap实现概要分析
    xfs_bmap实现文件系统地址到设备块地址的映射管理,包括设备空间的分配和释放;XFS设备空间分配包括延时分配和预分配。
    分配信息由struct xfs_bmalloca统一管理,传递给xfs_alloc.c中的函数,实现实际的空间分配操作。
    xfs_bmap信息由xfs_bmap_tree管理,struct xfs_bmdr_block表示设备上的映射信息;struct xfs_bmbt_irec表示内存中的映射 信息;
    bmap_tree的根节点由struct xfs_btree_block表示即struct xfs_inode->struct xfs_ifork->struct xfs_btree_block[Generic btree header]。
    每个xfs的inode有两个分支,分别是数据分支和属性分支,inodep->i_dp和inodep->i_afp。通过下面的操作获取到头节点的设备地址编号:
    block = ifp->if_broot;
    pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
    bno = be64_to_cpu(*pp);
    通过根节点,遍历整个inode的数据。
   
    xfs_bmap实现如下分析:
        xfs_bmbt_disk_set_allf :将数据(文件偏移、起始地址、块个数和状态)以设备格式保存
        xfs_bmap_worst_indlen:对于延时分配计算指定len需要的文件块个数
        xfs_default_attroffset:计算新创建的inode的默认属性的偏移位置,主要根据inode size为256或者更大的空间
        xfs_bmap_forkoff_reset:当inode的数据格式由LOCAL转换为EXTENT时,重新计算ATTR的数据偏移
        xfs_bmap_count_leaves:统计一定范围的数据使用的设备块个数,通过xfs_iext_get_ext获取xfs_bmbt_rec_host_t信息,并调用xfs_bmbt_get_blockcount解析数据
        xfs_bmap_disk_count_leaves:同xfs_bmap_count_leaves,但数据格式为disk格式
        xfs_bmap_count_tree:递归函数,获取一个文件所占用的所有设备空间
        xfs_bmap_count_blocks:统计一个xfs_inode的特定fork的空间
        DEBUG部分miss
        /* xfs bmap free list管理*/       
        xfs_bmap_add_free:通过文件系统起始bno和len,增加一个extent信息到bmap_free链表,等在结束一个transactions时完成实际的释放操作
        xfs_bmap_del_free:从bmap_free链表中删除一个extent信息
        xfs_bmap_finish:对于xfs_bmapi, xfs_bunmapi,在事务结束时释放所有的extents[[续详细分析]]
        xfs_bmap_cancel:取消释放映射的操作
        
        /* xfs inode fork format manipulation(local extent btree之间的切换) */
        xfs_bmap_btree_to_extents:将xfs的inode数据格式由btree转换为extent
        xfs_bmap_extents_to_btree:将xfs的inode数据格式由extents转化为btree       
        xfs_bmap_local_to_extents_empty:将xfs的inode数据格式由local转化为extents
        xfs_bmap_local_to_extents:
       
        /* 为xfs_inode增加属性分支,根据inode的数据分支格式 */
        xfs_bmap_add_attrfork_btree:为inode增加属性存储空间,btree格式, call from xfs_bmap_add_attrfork
        xfs_bmap_add_attrfork_extents:为inode增加属性存储空间,extents格式
        xfs_bmap_add_attrfork_local:为inode增加属性存储空间,locals格式
        xfs_bmap_add_attrfork:为inode增加属性存储空间,xfs的事务、日志的整个流程都包含

        /* extents和btree的相关操作 */
        xfs_bmap_read_extents:读取xfs的extents或btree信息到内存
        xfs_bmap_search_multi_extents:搜索特定块号的extents信息,并extents前后extents和是否达到文件尾的标志
        xfs_bmap_search_extents:搜索特定分支的特定块号的extents信息
        xfs_bmap_first_unused:返回相对与inode地址块号最近的未被使用的地址
        xfs_bmap_last_before:返回inode现有地址最后block的下一个地址
        xfs_bmap_last_extent:返回inode的最后一个extents
        xfs_bmap_isaeof:判断释放到达文件尾
        xfs_bmap_eof:判断指定的文件位置到达了现有的extents的最后一个extent
        xfs_bmap_last_offset:返回文件最后位置的偏移号
        xfs_bmap_one_block:判断文件某分支数据是否在一个block中
       
        /* extent tree manipulation during allocation */
        xfs_bmap_add_extent_delay_real:转化一个延时分配到实地址分配即为延时分配分配实际的地址空间,须仔细分析
        xfs_bmap_add_extent_unwritten_real:为預分配分配空间,须仔细分析
        xfs_bmap_add_extent_hole_delay:为文件洞或延时分配分配空间,须仔细分析
        xfs_bmap_add_extent_hole_real:为文件洞分配空间,须仔细分析
        
        xfs_bmap_extsize_align:判断新分配的extent是否满足基于底层设备对齐要求
        xfs_bmap_adjacent:分配相邻的块
        xfs_bmap_rtalloc:在实时设备上分配extent
        xfs_bmap_btalloc_nullfb:
        xfs_bmap_btalloc:在数据设备上分配extent
        xfs_bmap_alloc:有xfs_bmapi,为inode分配一个extent
        xfs_bmapi_trim_map:将地址映射区间压缩到最小请求区间
        xfs_bmapi_update_map:?
        xfs_bmapi_read:读取inode的空间映射信息
        xfs_bmapi_reserve_delalloc:为延时分配的预留空间分配实际的空间(?)
        xfs_bmapi_delay:延时的分配空间
        __xfs_bmapi_allocate:执行实际的分配工作,将调用xfs_alloc.c中的函数
        xfs_bmapi_allocate_worker:bmap分配工作者线程执行函数
        xfs_bmapi_allocate:bmap分配的外部可调用函数
        xfs_bmapi_convert_unwritten:将为预分配信息分配实际的空间
        xfs_bmapi_write:映射文件块到文件系统块,分配extents或转换extents状态
        xfs_bmap_del_extent:移除或取消延时分配
        xfs_bunmapi:移除文件blocks
        xfs_getbmapx_fix_eof_hole:
        xfs_getbmap:
        xfs_bmap_punch_delalloc_range:

    xfs_bmap_btree实现概要分析
        xfs_bmap_btree作为设备地址空间管理接口,由xfs_btree.c调用,导出API:struct xfs_btree_ops xfs_bmbt_ops
            static const struct xfs_btree_ops xfs_bmbt_ops = {
            .rec_len                = sizeof(xfs_bmbt_rec_t),
            .key_len                = sizeof(xfs_bmbt_key_t),

            .dup_cursor             = xfs_bmbt_dup_cursor,
            .update_cursor          = xfs_bmbt_update_cursor,
            .alloc_block            = xfs_bmbt_alloc_block,
            .free_block             = xfs_bmbt_free_block,
            .get_maxrecs            = xfs_bmbt_get_maxrecs,
            .get_minrecs            = xfs_bmbt_get_minrecs,
            .get_dmaxrecs           = xfs_bmbt_get_dmaxrecs,
            .init_key_from_rec      = xfs_bmbt_init_key_from_rec,
            .init_rec_from_key      = xfs_bmbt_init_rec_from_key,
            .init_rec_from_cur      = xfs_bmbt_init_rec_from_cur,
            .init_ptr_from_cur      = xfs_bmbt_init_ptr_from_cur,
            .key_diff               = xfs_bmbt_key_diff,
            .buf_ops                = &xfs_bmbt_buf_ops,
    #if defined(DEBUG) || defined(XFS_WARN)
            .keys_inorder           = xfs_bmbt_keys_inorder,
            .recs_inorder           = xfs_bmbt_recs_inorder,
    #endif
        };
        xfs_btree处理的外部接口:struct xfs_btree_cur
        当xfs_bmap需要分配空间时,调用xfs_bmbt_init_cursor初始化xfs_btree_cur并设置bc_ops。
    然后调用xfs_btree.c导出的接口如xfs_btree_new_iroot,在xfs_btree中将调用指定模块的API。

        xfs_extent_state:返回extent的状态,正常的extent状态:NORM和UNWRITTEN
        xfs_bmdr_to_bmbt:转换磁盘格式的btree root为主机格式,磁盘格式为小端字节序,主机格式为大端字节序(?)
        __xfs_bmbt_get_all:转换压缩的bmap extent为非压缩的bmap extent(how to compressed?)
        xfs_bmbt_get_all:call __xfs_bmbt_get_all
        xfs_bmbt_get_blockcount:获取extent的所包含的block count
        xfs_bmbt_get_startblock:获取extent的起始block number
        xfs_bmbt_get_startoff:获取extent所属文件的offset
        xfs_bmbt_get_state:获取extent的状态
        xfs_bmbt_disk_get_blockcount:从磁盘格式的extent中获取block count
        xfs_bmbt_disk_get_startoff:
        xfs_bmbt_set_allf:从参数中设置xfs_bmbt_rec_host_t
        xfs_bmbt_set_all:call xfs_bmbt_set_allf
        xfs_bmbt_disk_set_allf:设置磁盘格式的extent
        xfs_bmbt_disk_set_all:
        xfs_bmbt_to_bmdr:将btree root从主机格式转换设备格式
        xfs_check_nostate_extents:检测extent信息
        xfs_bmbt_dup_cursor:btree的核心数据结构之一,见btree节分析。
        xfs_bmbt_update_cursor:
        xfs_bmbt_alloc_block:
       
5.XFS延时分配实现
    传统的设备地址分配是在
    xfs_vm_write_begin
        status = __block_write_begin(page, pos, len, xfs_get_blocks);
        #        if (!buffer_mapped(bh)) {
        #                WARN_ON(bh->b_size != blocksize);
        #               err = get_block(inode, block, bh, 1);
        #                ......
        #        }
        __xfs_get_blocks
            xfs_iomap_write_delay
                xfs_iomap_eof_want_preallocate
                xfs_bmapi_delay
                    xfs_bmapi_reserve_delalloc    # 为延时分配预留空间
                        大致流程:
                            xfs_get_extsz_hint:
                                获取底层设备块大小对齐,对于realtime设备,需要按照realtime设备的chunk大小分配空间;当底层设备是raid时,需要案子条带大小分配
                            xfs_trans_reserve_quota_nblks:
                                如果配置了quota,为ionde的使用qutoa值设置预留值
                            xfs_mod_incore_sb/xfs_icsb_modify_counters:
                                修改超级块可使用空间的可使用值
                            xfs_bmap_add_extent_hole_delay:
                                完成实际的inode的延时分配,大致流程:
                                    如果新的延时分配请求可以和与左边或右边的延时分配记录合并,则更新xfs_bmbt_irec_t记录;否则则调用函数xfs_iext_insert,在inode的extents记录中新增加一个xfs_bmbt_irec_t记录
                            xfs_bmbt_get_all:
                                更新延时分配的extent信息,如果在xfs_bmap_add_extent_hole_delay检测可合并,则更新extents信息为合并后的信息

           何时为延时分配分配实际的存储空间:
                在刷新脏数据时调用xfs_vm_writepage
                    大致流程:
                        xfs_map_blocks
                            if (type == XFS_IO_DELALLOC &&
                                (!nimaps || isnullstartblock(imap->br_startblock))) {
                                    error = xfs_iomap_write_allocate(ip, offset, count, imap);
                                    ......
                            }

        结论:根据设备空间分配的时机可有效的提高数据存储地址的连续性,通过預读可有效的提高读的性能。

6.XFS預分配实现
    文件系统的預分配是在创建文件后,在写数据之前,调用fallocate或posix_fallocate实现设备空间的分配;可有效保证数据的连续性,ftp服务、smb服务在传输文件时都使用了預分配接口;
    預分配与fseek有这本质的区别

    xfs的预分配内核函数xfs_file_fallocate
        大致流程:
           调用 xfs_change_file_space(ip, cmd, &bf, 0, attr_flags);cmd为XFS_IOC_RESVSP
                xfs_alloc_file_space        # flags == XFS_BMAPI_PREALLOC
                    xfs_bmapi_allocate
           
            何时转化預分配的extents元数据信息:
            xfs_bmap_add_extent_unwritten_real
                该函数主要是修改的extents的btree或extents元数据信息
0 0
原创粉丝点击