read file page cache

read file page cache 

 

generic_file_buffered_read()里的index表示此次read文件的位置,在要读的某个文件里的位置,这个index是以page为单位的last_index表示此次read的结束位置,同样其单位是page

这两个变量的值分别是根据kiocb、iov_iter两个结构体来确定的

如果file.f_op.read没有实现,实现了file.f_op.read_iter,则vfs_read会调用new_sync_read(),在这个函数里,会构建一个kiocb struct,其中的ki_pos即是ppos,即read file的offset; new_sync_read()参数中的len将会被赋值给iov_iter.count:

fs/read_write.c

复制代码
static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
{
    struct iovec iov = { .iov_base = buf, .iov_len = len };
    struct kiocb kiocb;
    struct iov_iter iter;
    ssize_t ret;

    init_sync_kiocb(&kiocb, filp);
    kiocb.ki_pos = *ppos;
    iov_iter_init(&iter, READ, &iov, 1, len);

    ret = call_read_iter(filp, &kiocb, &iter);
    BUG_ON(ret == -EIOCBQUEUED);
    *ppos = kiocb.ki_pos;
    return ret;
}
复制代码

 

以ext4 fs为例,接下来它的call trace如下:

ext4_file_read_iter
generic_file_read_iter
generic_file_buffered_read

下面分析下generic_file_buffered_read()

 

static ssize_t generic_file_buffered_read(struct kiocb *iocb,
        struct iov_iter *iter, ssize_t written)
   loff_t *ppos = &iocb->ki_pos; index
= *ppos >> PAGE_SHIFT; prev_index = ra->prev_pos >> PAGE_SHIFT; prev_offset = ra->prev_pos & (PAGE_SIZE-1); last_index = (*ppos + iter->count + PAGE_SIZE-1) >> PAGE_SHIFT; offset = *ppos & ~PAGE_MASK; for (;;) { struct page *page; pgoff_t end_index; loff_t isize; unsigned long nr, ret; cond_resched(); find_page: if (fatal_signal_pending(current)) { error = -EINTR; goto out; } page = find_get_page(mapping, index); if (!page) { if (iocb->ki_flags & IOCB_NOWAIT) goto would_block; page_cache_sync_readahead(mapping, ra, filp, index, last_index - index); page = find_get_page(mapping, index); if (unlikely(page == NULL)) goto no_cached_page; } if (PageReadahead(page)) { page_cache_async_readahead(mapping, ra, filp, page, index, last_index - index); } if (!PageUptodate(page)) { if (iocb->ki_flags & IOCB_NOWAIT) { put_page(page); goto would_block; } /* * See comment in do_read_cache_page on why * wait_on_page_locked is used to avoid unnecessarily * serialisations and why it's safe. */ error = wait_on_page_locked_killable(page);

以第一次读一个文件为例,读的位置是0,find_get_page()是从page cache tree上查找这个page是否已经在page cache里了,针对目前的case,它将找不到这个page,所以调用page_cache_sync_readahead()进行同步读。

接下来再调用了find_get_page(),如果前面的page_cache_sync_readahead()成功了的话,此时是能find到这个page的,即能从page cache里find到这个page,注意能find到并不能说明这个page已经通过IO读到内存上来了。

接下来是判断这个page是否有readahead属性,如果有,则说明这个page是之前以read ahead的方式读取到的,则调用page_cache_async_readahead()进行异步再读;

接下来判断这个page是否是uptodate的,读一个page时默认是没有这个flag的,直到这个page通过IO方式读取到内存里来了才会将这个flag置上;

接下来是调用wait_on_page_locked_killable(),这个函数是先检查这个page是否有locked flag,如果有则会去等这个flag被clear,所以此时这个线程有可能会睡眠被调度出去,此时这个线程的状态被设置为TASK_KILLABLE,此后去查看这个线程的状态将是D状态。

 

 

 

 

https://blog.csdn.net/zouxiaoting/article/details/8738077

https://blog.csdn.net/u011649400/article/details/96560975

 

posted @ 2021-12-13 19:26  aspirs  阅读(114)  评论(0编辑  收藏  举报