2017-01-03

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如何 与 电梯 衔接的?
答:以上面的read
pages()为例, 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