作者: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_req个block,则从per-CPU
preallocation中分配。

这里说明几个关键词:在本系列中,per-inode prealloc即是per-file
的,也称per-file prealloc;per-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_size或size

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

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

1.
如果当前写操作是文件的最后的逻辑block、并且文件系统不忙及文件已经关闭,就不能再采取prealloc了。(该patch是Ted提交,解决问题“挂载、在目录中写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 prealloc、per-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分配给目标inode。ac_o_ex,即origin
extent,用于描述原始请求的一些信息。这些结构体都已经在[分配机制 -
关键的数据结构]中说明】

ext4_mb_new_preallocation()函数中会涉及inode prealloc和per-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()normalize后goal
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(),其思想如下:将inode的i_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 未本地化版本许可协议进行许可。

[ext4]13 空间管理 - Prealloc分配机制的更多相关文章

  1. [ext4]空间管理 - 与分配相关的关键数据结构

     在块分配机制中,涉及到几个主要的数据结构. 通过ext4_allocation_request描述块请求,然后基于块查找结果即上层需求来决定是否执行块分配操作. 在分配过程中,为了更好执行分配, ...

  2. [ext4]空间管理 - 分配机制

     在Ext4系统中,存在很多分配策略,比如预分配.多块分配.延迟分配等   Prealloc预分配 在ext4系统中,对于小文件和大文件的空间申请请求,都有不同的分配策略.对用小文件的空间请求,e ...

  3. 【oracle11g,13】表空间管理2:undo表空间管理(调优) ,闪回原理

    一.undo空间原理: dml操作会产生undo数据. update时,sever process 会在databuffer 中找到该记录的buffer块,没有就从datafile中找并读入data ...

  4. 本地管理表空间(LMT)与自动段空间管理(ASSM)概念

    创建表空间时,extent management local 定义本地管理表空间(LMT),segment space management auto 定义自动段空间管理(ASSM). extent ...

  5. ORACLE表空间管理维护

    1:表空间概念 在ORACLE数据库中,所有数据从逻辑结构上看都是存放在表空间当中,当然表空间下还有段.区.块等逻辑结构.从物理结构上看是放在数据文件中.一个表空间可由多个数据文件组成. 如下图所示, ...

  6. Oracle表空间管理

    oracle表空间相关常用命令小结: 1.ALTER DATABASE SET DEFAULT BIGFILE TABLESPACE;              //修改表空间数据文件类型 2.ALT ...

  7. Linux内存管理3---分页机制

    1.前言 本文所述关于内存管理的系列文章主要是对陈莉君老师所讲述的内存管理知识讲座的整理. 本讲座主要分三个主题展开对内存管理进行讲解:内存管理的硬件基础.虚拟地址空间的管理.物理地址空间的管理. 本 ...

  8. JVM内存管理及GC机制

    一.概述 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露 ...

  9. Memcache简介 & 内存分配机制

            关于这个东西里面到底应该存放数据网上一直有很多种说法,有的说sql进行md5之后作为键值,结果作为内容存放,也有人说按照业务逻辑错放,反正是炒的不亦乐乎.        本人经过将近2 ...

随机推荐

  1. python中try except处理程序异常的三种常用方法

    如果你在写python程序时遇到异常后想进行如下处理的话,一般用try来处理异常,假设有下面的一段程序: try: 语句1 语句2 . . 语句N except .........: do somet ...

  2. adt的问题An internal error has occurred. After scene creation, #init() must be called

    这个问题困扰了我好久,我也尝试去百度.google无济于事啊,让我寝食难安,太难受了,我把它贴出来,希望后人不绕弯子... 解决办法: 即可,解决这一个问题,现在酣畅淋漓,挥洒自如的capy代码了

  3. C++ Primer 5 CH2 变量和基本类型

    C++ 是一种静态数据类型语言,它的类型检查发生在编译时.因此,编译器需要知道每一个变量对应的数据类型. 2.1 基本内置类型 算术类型 C++ 标准并没有规定带符号类型应如何表示,但是约定了在表示范 ...

  4. Redis构建分布式锁

    1.前言 为什么要构建锁呢?因为构建合适的锁可以在高并发下能够保持数据的一致性,即客户端在执行连贯的命令时上锁的数据不会被别的客户端的更改而发生错误.同时还能够保证命令执行的成功率. 看到这里你不禁要 ...

  5. 转:java实例化对象的过程

    学习JAVA这门面向对象的语言,实质就是不断地创建类,并把类实例化为对象并调用方法.对于初学JAVA的人总搞清楚对象是如何实例化的,假如类之间存在继承关系,那就更糊涂了.下面我们通过两个例题来说明对象 ...

  6. 从今天开始学习Java了

    //今天第一天学习了Java的起源兴起和用途,Java的特点和优势,又重新练习了hello world, public class Hello{ public static void main(Str ...

  7. Akari谜题(关灯问题)的开灯解法

    提高解时预处理的速度 本方法的结果是得到满足所有黑色有数字方块的一个带有未照亮的块的可能解集. 解集大小为 4~(3号块数量+1号块数量)+6~(2号块数量)-灯互相照射到的解的集合.集合中的灯为黄色 ...

  8. 【Egret】2D 使用中的一些疑难解决技巧!

    1.问题:声音在ios上无法播放    解决方法:①首先需要预加载一个声音                        ②然后目前只有点击之后才能播放声音,不能默认播放 2.问题:滚动条问题   解 ...

  9. 测试开发Python培训:抓取新浪微博评论提取目标数据-技术篇

    测试开发Python培训:抓取新浪微博评论提取目标数据-技术篇   在前面我分享了几个新浪微博的自动化脚本的实现,下面我们继续实现新的需求,功能需求如下: 1,登陆微博 2,抓取评论页内容3,用正则表 ...

  10. 第一章开发简单的Java应用程序

    1.什么是程序? 程序一词来源于生活,通俗点讲就是把生活的的事用程序编写出来 并执行. 2.为什么要学习Java呢? Java是Sun Microsystems于1995年推出的高级编程语言 Java ...