zoukankan      html  css  js  c++  java
  • [ext4]13 空间管理

    

    作者:Younger Liu,

    本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。


        在ext4系统中,对于小文件和大文件的空间申请请求,都有不同的分配策略。

        对用小文件的空间请求,ext4尝试从一种叫per-CPU local group中分配空闲空间。Per-CPU Localgroup就是所有该CPU所执行的分配行为共享的空间,目的是保证这些小文件的聚集在一起,便于访问。Per-CPU Local group就是per-CPU prealloc空间。

    对于大文件的空间请求,ext4尝试从一种叫per-inode preallo空间中分配空闲空间。这点就像Ext3系统的保留空间一样,Ext4为每个文件在内存中维护一段预分配空间,用于解决并发分配情况下的碎片问题。

    Ext4系统维护这两个preallocation空间:per-inode preallocation空间和per-CPUpreallocation空间。

    而大小文件的鉴别标准,用户自己可以通过以下接口调整:

    /prof/fs/ext4/<partition>/stream_req

    默认为16,单位是block;如果totalsize小于stream_reqblock,则从per-CPU preallocation中分配。

    这里说明几个关键词:在本系列中,per-inode prealloc即是per-file 的,也称per-file preallocper-CPU prealloc即是locality group allocation


    1.  如何识别文件是大是小?


    刚才已经说过,根据文件的大小来选择是采用per-CPU allocation还是per-inode allocation。那么大小文件的鉴别标准是什么哪?

    这份工作是在ac初始化中由函数ext4_mb_group_or_file()完成的:

    size = ac->ac_o_ex.fe_logical + EXT4_C2B(sbi,ac->ac_o_ex.fe_len);

             isize= (i_size_read(ac->ac_inode) + ac->ac_sb->s_blocksize - 1)

                       >>bsbits;

             /*don't use group allocation for large files */

             size= max(size, isize);

             if(size > sbi->s_mb_stream_request) {

                       ac->ac_flags|= EXT4_MB_STREAM_ALLOC;

                       return;

             }

     

             BUG_ON(ac->ac_lg!= NULL);

             /*

              * locality group prealloc space are per cpu.The reason for having

              * per cpu locality group is to reduce thecontention between block

              * request from multiple CPUs.

              */

             ac->ac_lg= __this_cpu_ptr(sbi->s_locality_groups);

     

             /*we're going to use group allocation */

             ac->ac_flags|= EXT4_MB_HINT_GROUP_ALLOC;

    1. 估算出文件的大小size:i_sizesize

    2. 比较sizestream_req的大小;如果大于,则通过设置GROUP_ALLOC来标示per-CPU preallocation可用。

    需要注意的时,并不是仅仅检查这一项,还需要检查以下几项:

    1. 如果当前写操作是文件的最后的逻辑block、并且文件系统不忙及文件已经关闭,就不能再采取prealloc了。(该patchTed提交,解决问题“挂载、在目录中写4K文件,卸载;重复64次导致碎片化”)

             if((size == isize) &&

                 !ext4_fs_is_busy(sbi) &&

                (atomic_read(&ac->ac_inode->i_writecount) == 0)) {

                       ac->ac_flags|= EXT4_MB_HINT_NOPREALLOC;

                       return;

             }

    2.检查sbi->s_mb_group_prealloc是否小于等于0,如果是,采用

        sbi->s_mb_group_prealloc表示per-CPU prealloc的空间大小;默认值是512blocks(不考bigalloc),可通过/sys/fs/ext4/<partition>/mb_group_prealloc设置。

    sbi->s_mb_group_prealloc小于或等于0,表示无需per-CPU prealloc了。

             if(sbi->s_mb_group_prealloc <= 0) {

                       ac->ac_flags|= EXT4_MB_STREAM_ALLOC;

                       return;

             }

     

    既然知道了什么时候可以使用per-inode preallocper-CPU prealloc,那么接下来就来分析下,如何创建。


    2.  创建prealloc空间


    MultiBlockallocator分配器的主函数ext4_mb_new_blocks()中,当ac_b_ex extent的长度大于ac_o_ex extent(originextent)的长度时,multiblock allocator会调用函数ext4_mb_new_preallocation ()将多出来的空间以prealloc形式预留下来。当然,多出来的空间,multiblock allocator不舍得还给系统,只想保留下来备用;如果ac_b_exextent的长度不大于ac_o_ex extent的长度,那么即使multiblock allocator有预留的想法,也没有空间去prealloc了。

    【注:ac_b_ex,即best found extent,用于描述在分配中发现的最佳extent,并申请之,通过multiblock allocator分配给目标inodeac_o_ex,即origin extent,用于描述原始请求的一些信息。这些结构体都已经在[分配机制 - 关键的数据结构]中说明】

    ext4_mb_new_preallocation()函数中会涉及inode preallocper-CPU prealloc

    ext4_mb_new_preallocation()代码如下:

    static int ext4_mb_new_preallocation(structext4_allocation_context *ac)

    {

             interr;

     

             if(ac->ac_flags & EXT4_MB_HINT_GROUP_ALLOC)

                      err = ext4_mb_new_group_pa(ac);

             else

                       err= ext4_mb_new_inode_pa(ac);

             returnerr;

    }

    先来分析per-CPU prealloc空间的创建。

    在函数ext4_mb_new_group_pa()中,初始化一个prealloc描述符ext4_prealloc_space pa,用于存放prealloc的信息,完成赋值后,将将pa连接到链表ext4_group_info-> bb_prealloc_list上。由此可见,per-CPU prealloc是具有locality的,因为prealloc是挂载到group结构体中某个链表上

    当然,也许有要说,在初始化ext4_prealloc_space pa时有:

    pa->pa_len = ac->ac_b_ex.fe_len;

             pa->pa_free= pa->pa_len;

    这一点无需担心,pa_free会在ac释放时更新为空闲空间的长度。

        下面再说一下per-inode的创建,即函数ext4_mb_new_inode_pa()

    per-inode prealloc初始化中,还的得必须关注一个extent描述符ac->ac_g_ex,extent实例是描述由ext4_mb_normalize_request()normalizegoal extent

    首先比较分配的最佳ac_b_ex与目标ac_g_ex的长度,如果小于后者,说没有达标所要求的则需要更新ac_b_ex的起始逻辑块地址;如果不小于后者,则不但将该prealloc空间添加到链表ext4_group_info-> bb_prealloc_list,也会添加到ext4_inode_info->i_prealloc_list链表中。

    此时per-inode prealloc也初始化完毕。 


       空间有了,那就分析如何使用吧。

     

    3.  Prealloc空间的使用


    multiblock allocator在分配块时,首先考虑的都是prealloc空间,调用函数ext4_mb_use_preallocated()

    prealloc空间中分配块时,分配器先查看per-inode prealloc空间,即搜索链表ext4_inode_info ->i_prealloc_list,这个链表中包含于该inode有关的所有的prealloc空间。

    使用prealloce空间,是基于_logical_起始block的:只有当指定的逻辑块号落在了prealloc空间范围之内,分配器才会使用prealloc空间,这样可以保证文件空间物理地址的连续性。

    如果在per-inode prealloc空间中没有找到可用blocks,并且per-CPU preallocation分配器是可用的,则尝试从locality group prealloc空间中进行分配,就是per-CPUprealloc list

    ext4_sb_info.s_locality_groups[smp_processor_id()]

    per-CPU locality group的存在,可以减少CPU之间在空间分配过程中的资源竞争。 


        Prealloc空间毕竟是预留但未用的空间,所以必须是要释放的。

    4.  释放prealloc空间

    Prealloc空间有两种:per-inode prealloc空间、per-CPU prealloc空间。在创建那节已经讨论,per-CPU prealloc空间可以通过ext4_group_info-> bb_prealloc_list检索到,通过inode无法检索;而per-inode prealloc空间不但连接到ext4_inode_info-> i_prealloc_list链表上,也会连接到ext4_group_info-> bb_prealloc_list链表中检索到。

    1. 释放指定的prealloc空间,调用ext4_mb_release_inode_pa()ext4_mb_release_group_pa()函数实现。

    2. 基于给定的inode,销毁所有未用的prealloc空间,可使用函数ext4_discard_preallocations(),其思想如下:将inodei_prealloc_list链表上所有的prealloc空间移动到链表list上,之所以使用临时链表,减少竞争带来耗时。然后基于临时链表,先将prealloc空间从所属的ext4_group_info->bb_prealloc_list上删除,然后调用ext4_mb_release_inode_pa()释放该prealloc空间,然后从临时链表上将该prealloc空间节点删除。

    3. 基于给定的group,销毁与其有关的所有未用的prealloc空间,调用函数ext4_mb_discard_group_preallocations()实现,其思想与(2)方法一致。 

    关于Prealloc机制,就分析到此吧。


    作者:Younger Liu,

    本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。

  • 相关阅读:
    maven学习(四)maven的生命周期
    maven学习(六)依赖、聚合、继承
    Koa2学习(三)GET请求
    Koa2学习(二)async/await
    Koa2学习(一)环境搭建
    实现一个简易的express中间件
    js生成页面水印
    使用 dva + antd 快速开发react应用
    使用ab 进行并发压力测试
    python3 使用http.server模块 搭建一个简易的http服务器
  • 原文地址:https://www.cnblogs.com/youngerchina/p/5624474.html
Copyright © 2011-2022 走看看