do_generic_file_read中的readahead
1. readahead
dogenericfile_read 中有两个ahead相关的函数:
do_generic_file_read -> page_cache_sync_readahead
generic_file_aio_read -> do_generic_file_read -> page_cache_async_readahead
问:pagecachesyncreadahead 和 pagecacheasyncreadahead 的差别在哪里? sync和async体现在哪?
答: 一个当前page cache中没有所需的数据, 发起的是对当下要用的数据的读取;
另一个是page cache中有所需的数据, 发起对后面可能要用的数据的读取.
linux-3.10.86/mm/filemap.c
do_generic_file_read
{
page = find_get_page(mapping, index);
if (!page){
page_cache_sync_readahead(...)
...
}
if (PageReadahead(page)) {
page_cache_async_readahead(...)
}
...
}
sync体现在:
do_generic_file_read
{
page = find_get_page(mapping, index);
if (!page){
page_cache_sync_readahead(...)
...
}
if (!PageUptodate(page)) {
if (!trylock_page(page)) //锁失败
goto page_not_up_to_date;
...
}
page_not_up_to_date:
/*这里等待io complete handler释放锁.*/
/* Get exclusive access to the page ... */
error = lock_page_killable(page);
}
2. how readahead works
ondemandreadahead -> _dopagecachereadahead -> readpages
read_pages
{
...
blk_start_plug(&plug);
mapping->a_ops->readpages()
blk_finish_plug(&plug);
}
blk_start_plug(struct blk_plug *plug)
{
...
if (!tsk->plug)
tsk->plug = plug;
}
linux-3.10.86/include/linux/sched.h
struct task_struct {
...
/* stacked block device info */
struct bio_list *bio_list;
}
linux-3.10.86/include/linux/blkdev.h
struct blk_plug {
unsigned long magic; /* detect uninitialized use-cases */
/* 先尝试和current->plug这个struct blk_plug中的struct request合并
失败后, 才尝试电梯调度.
see blk_queue_bio -> attempt_plug_merge()*/
struct list_head list; /* requests */
/*entry为struct blk_plug_cb, see flush_plug_callbacks()*/
struct list_head cb_list; /* md requires an unplug callback */
};
问题:
1. 若不经过struct blkplug, 直接放入电梯调度, 也能够顺利合并啊, 为何非要引入struct blkplug呢?
2. struct blkplug如何 与 电梯 衔接的?
答:以上面的readpages()为例, blkstartplug()后, :
->readpages -> submit_bio -> generic_make_request -> blk_queue_bio
|--(无锁) attempt_plug_merge
|--fall back to
| |--spin_lock_irq(q->queue_lock);
| |--elv_merge /*没有进行队列的插入操作, 仅判断是否能够完成merge.*/
| | |--elv_rqhash_find //尝试back merge, 不依赖于 具体的iosched.
| | |--fall back: e->type->ops.elevator_merge_fn //依赖于 具体的iosched
blkfinishplug -> blkflushpluglist 这里对struct blkplug的操作无需加锁, 因为是属于current的, 并不会多人同时操作.
elvmerge要加锁, 且要判断的内容 比 attemptplugmerge 多不少. 所以, attemptplug_merge比较快.
本文地址: https://awakening-fong.github.io/posts/io/readahead
转载请注明出处: https://awakening-fong.github.io
若无法评论, 请打开JavaScript, 并通过proxy.
blog comments powered by Disqus