The Block I/O Layer

http://sylab-srv.cs.fiu.edu/lib/exe/fetch.php?media=paperclub:lkd3ch14.pdf
这里mark一些要点跟总结等。

Anatomy of a Block Device

  • 快设备最小寻址单位是sector, 多数是512bytes
  • kernel寻址单位block, 是sector大小的power-of-two倍数,不大于page size, 常见512B, 1KB, 4KB
  • 机械硬盘的扇区这些概念是对特定block设备的属性,kernel在sector上抽象block

Buffers and Buffer Heads

  • block在内存里变现为一个buffer
  • 每个buffer有一个buffer head 对应这个buffer的信息(哪个device, block等)
struct buffer_head {
  unsigned long b_state; /* buffer state flags */
  struct buffer_head *b_this_page; /* list of page’s buffers */
  struct page *b_page; /* associated page */
  sector_t b_blocknr; /* starting block number */
  size_t b_size; /* size of mapping */
  char *b_data; /* pointer to data within the page */
  struct block_device *b_bdev; /* associated block device */
  bh_end_io_t *b_end_io; /* I/O completion */
  void *b_private; /* reserved for b_end_io */
  struct list_head b_assoc_buffers; /* associated mappings */
  struct address_space *b_assoc_map; /* associated address space */
  atomic_t b_count; /* use count */
};

The bio Structure

struct bio {
    sector_t bi_sector; /* associated sector on disk */
    struct bio *bi_next; /* list of requests */
    struct block_device *bi_bdev; /* associated block device */
    unsigned long bi_flags; /* status and command flags */
    unsigned long bi_rw; /* read or write? */
    unsigned short bi_vcnt; /* number of bio_vecs off */
    unsigned short bi_idx; /* current index in bi_io_vec */
    unsigned short bi_phys_segments; /* number of segments */
    unsigned int bi_size; /* I/O count */
    unsigned int bi_seg_front_size; /* size of first segment */
    unsigned int bi_seg_back_size; /* size of last segment */
    unsigned int bi_max_vecs; /* maximum bio_vecs possible */
    unsigned int bi_comp_cpu; /* completion CPU */
    atomic_t bi_cnt; /* usage counter */
    struct bio_vec *bi_io_vec; /* bio_vec list */
    bio_end_io_t *bi_end_io; /* I/O completion method */
    void *bi_private; /* owner-private method */
    bio_destructor_t *bi_destructor; /* destructor method */
    struct bio_vec bi_inline_vecs[0]; /* inline bio vectors */
};
Figure 14.2
  • bio 替代buffer_head表示一次io 操作,buffer只跟block对应
  • The basic container for block I/O within the kernel is the bio structure。

The Old Versus the New

  • bio 可以容易表示high memory, bio处理对应物理page,不是pointer
  • 可以同时表示 normal page I/O 跟direct I/O
  • 容易处理涉及多个物理页的操作
  • 相比buffer head更轻量, 只包含一个block I/O操作需要的信息

buffer head的概念仍然需要,但只表示block到buffer的对应,bio表示in-flight I/O.

Request Queues

  • 设备维护一个request queues存储pending的block I/O request, 有定义在<linux/blkdev.h>里的request_queue structure表示,包含一个请求的双向链表跟相关信息。
  • request由高层的代码如文件系统添加。
  • queue非空快设备驱动就从queue里队首获取request提交到对应块设备。
  • 一个request由<linux/blkdev.h>里的struct request表示,可以包含多个bio, 因为一个request可以操作多个连续的disk blocks.

I/O Schedulers

如果kernel需要io request的时候就丢到queue的那么性能会很差(考虑磁盘seek操作)。所以kernel会有mergingsorting的操作来提升性能,提供这些操作的子系统就叫做 I/O scheduler

The Job of an I/O Scheduler

一个I/O scheduler管理块设备的request queue.它通过决定request被分发到块设备的顺序跟时间来提高整体的吞吐。

  • merging
    两个或多个request合并成一个。比如文件系统提交一个request,但queue里已经有一个request读取相邻的section,可以合并减少overhead&seed
  • sorting
    没有相邻的request不能合并,但有相近的section请求可以调整顺序。比如把读第3个sector的放在读第1个sector的请求后面。(想下电梯调度)

The Linus Elevator

Linus Elevator 是第一个I/Oscheduler, 2.4默认,2.6后被其它替代。

Linus Elevator会执行merging和sorting操作,但添加一个request是,会在queue里检查每个request看有没相邻(前或后相邻)的request合并。

如果不能merging会找一个sectorwise的合适位置插入,不然插入的队列末尾。另外如果有request在队列里超过了一定时间也会把当前request放到队列而不是插入到合适位置,这个为了比较某个位置的大量请求饿死其它位置的请求。

总的说当添加一个request有4个操作按序可能:

  • 队列里有相邻的request, 合并.
  • 队列里有相当old的request.没处理了, 把新的插到队尾防止饿死其它更老的requests.
  • 有合适的sector-wise位置在队列里插入到对应位置,让队列保持按磁盘物理顺序排序。
  • 没合适位置,简单插到队尾。

The Deadline I/O Scheduler

Deadline I/O Scheduler用来解决Linux Elevator产生的饥饿问题。为了减少seeks的时间,大量同一区域的磁盘操作容易饿死距离较远的request, 这不公平。

更糟糕的是,上面的request 饥饿问题会产生write starving reads.写request当丢到队列就可以当提交了,对应用异步。读当应用提交request, 应用会block到reqeust处理完拿到数据。这样read lantency对上层应用很重要,虽然希望对于写 lantency也不能太大。

读请求更加趋向于互相依赖。例如读取大量文件,每个读在一个很小的buffered chunks。应用不会读取下个chunk(活着说下个文件),知道前一个chunk已经读取并返回到应用,更糟糕的是写也要读(文件系统读取元数据如inode)。读取这些block会串行化I/O。因此,每个读请求都饥饿的化对于应用操作的lantency会很大。Deadline I/O scheduler实现若干特性来确保读饥饿最小化。

要知道减少读饥饿会带来全局吞吐下降的问题。Linux Elevator也是这样,Linux Elevator提供更好的吞吐(通过更大力度的减小 seeks)。Deadline I/O scheduler通过努力限制饥饿同时提供好的全局吞吐。

在Deadline I/O scheduler每个request会有一个超时时间。默认读500ms, 写5s。如图Deadline scheduler会维护一个类似the Linux Elevator的队列,这个队列按磁盘物理排序,同样会执行mergingsorting的操作。同时根据读或者写的类型插入对另一对应队列(FIFO, 即按时间排序)。Deadline scheduler从sorted queue垃取request到dispatch queue给磁盘驱动消费,这个最小化seeks次数时间。

当在read queue或write queue的request超时了的时候,Deadline scheduler 就从这些FIFO的队列拿取request而不是sorted queue。通过如此,Deadline scheduler尝试确保没有请求远大于它的超时时间。

所以不确保在超时时间内处理,但通过给读请求一个相当小的超时时间这可以防止write starve read, 读会提供更好的lantency。

The Anticipatory I/O Scheduler

The Complete Fair Queuing I/O Scheduler

CFQ类似the Linux Elevator,但是每个进程维护一个queue, 分别merge跟sort, round robin处理每个进程(默认每次获取4个request)。
为多媒体workload设计,但对于多数情景也很好。
(应该是2.6的默认scheduler)

The Noop I/O Scheduler

会做merging但不sorted,基本没什么操作,对于random-access的设备比较好。

Conclusion

  • bio 表示 in-flight I/O
  • buffer_head 表示一个block-to-page mapping
  • request structure 表示一个特定的I/O请求。
    request最后到scheduler处理调度,由driver处理。

一般来说 NOOP 调度器最适合于固态硬盘,DeadLine 调度器适用于写入较多的文件服务器,比如Web服务器,数据库应用等,而CFQ 调度器适合于桌面多任务及媒体应用。


看最新linux(4.12)代码下有的I/O scheduler

➜  linux git:(master) ✗ ll block/*iosched.c
-rw-r--r--  1 huangjiahao  staff   162K May 23  2017 block/bfq-iosched.c
-rw-r--r--  1 huangjiahao  staff   127K May 23  2017 block/cfq-iosched.c
-rw-r--r--  1 huangjiahao  staff    11K May 23  2017 block/deadline-iosched.c
-rw-r--r--  1 huangjiahao  staff    21K May 23  2017 block/kyber-iosched.c
-rw-r--r--  1 huangjiahao  staff   2.6K May 23  2017 block/noop-iosched.c

bfq跟kyber应该是4.12才加入的,参见:https://lwn.net/Articles/720675/

看完可能想看下当前硬盘上用什么调度器了

➜  ~ cat /sys/block/sda/queue/scheduler
noop deadline [cfq]

括号起来的cfq就是当前用的,当前有3种可以配置使用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容

  • 本篇文章是基于谷歌有关Graphic的一篇概览文章的翻译:http://source.android.com/de...
    lee_3do阅读 7,079评论 2 21
  • 文件系统优化 ** 动态调整请求队列数来提高效率,默认请求队列数为:128, 可配置512 **[root@c37...
    肖金光xjg阅读 4,773评论 1 8
  • 35种失眠的方式 1 没有蛙声的春天 真是一败涂地 要用一大片空白来掩盖一小块空白 整个夜晚 我们都在思考被隐藏的...
    桑子简书阅读 304评论 0 1
  • 蚕 不是 你想象中的那般柔弱 每一次的休眠 都是在积蓄力量 只为 那破茧而出的一刻 开始她生命的另一个起点 自缚 ...
    云霄飞鸟阅读 311评论 1 5
  • 难忘。难受,难过也是属于难忘的一种吧。远行,多远才是远?还是说不管到了多远的地方,需以足下步数为准,那最远的,就称...
    潺禅阅读 504评论 2 0