readaheadシステムコール
readaheadシステムコールは、ユーザ空間から先読み処理を行います。先読み位置/サイズをpage単位に変化してdo_readahead()をコールされ、filp->f_modeの FMODE_RANDOMの有無に関係なくforce_page_cache_readahead()がコールされます。
先読みサイズ分 nr_to_readを、2Mバイト(512page)単位で先読みされます。__do_page_cache_readahead()で先読みするのですが、第4引数の先読みサイズが0と言うことです。すなわちreadaheadでの先読み領域は、先読み領域として管理されないと言う事です。(page->flagsにPG_readaheadが設定されない。)
readaheadシステムコールは意図的な先読みであり、do_generic_file_read()からこの領域を読み込んでも、通常のキャッシュpageを読み込みとになり、先読みサイズが更新されることもなく、又先読みもされません。
SYSCALL_DEFINE(readahead)(int fd, loff_t offset, size_t count) { ssize_t ret; struct file *file; ret = -EBADF; file = fget(fd); if (file) { if (file->f_mode & FMODE_READ) { struct address_space *mapping = file->f_mapping; pgoff_t start = offset >> PAGE_CACHE_SHIFT; pgoff_t end = (offset + count - 1) >> PAGE_CACHE_SHIFT; unsigned long len = end - start + 1; ret = do_readahead(mapping, file, start, len); } fput(file); } return ret; } do_readahead(struct address_space *mapping, struct file *filp, pgoff_t index, unsigned long nr) { if (!mapping || !mapping->a_ops || !mapping->a_ops->readpage) return -EINVAL; force_page_cache_readahead(mapping, filp, index, nr); return 0; }force_page_cache_readahead()はカーネルのファイル読み込みdo_generic_file_read()で行う先読み時、filp->f_mode & FMODE_RANDOM時にも先読みとしてコールされます。
先読みサイズ分 nr_to_readを、2Mバイト(512page)単位で先読みされます。__do_page_cache_readahead()で先読みするのですが、第4引数の先読みサイズが0と言うことです。すなわちreadaheadでの先読み領域は、先読み領域として管理されないと言う事です。(page->flagsにPG_readaheadが設定されない。)
readaheadシステムコールは意図的な先読みであり、do_generic_file_read()からこの領域を読み込んでも、通常のキャッシュpageを読み込みとになり、先読みサイズが更新されることもなく、又先読みもされません。
int force_page_cache_readahead(struct address_space *mapping, struct file *filp, pgoff_t offset, unsigned long nr_to_read) { int ret = 0; if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readpages)) return -EINVAL; nr_to_read = max_sane_readahead(nr_to_read); while (nr_to_read) { int err; unsigned long this_chunk = (2 * 1024 * 1024) / PAGE_CACHE_SIZE; if (this_chunk > nr_to_read) this_chunk = nr_to_read; err = __do_page_cache_readahead(mapping, filp, offset, this_chunk, 0); if (err < 0) { ret = err; break; } ret += err; offset += this_chunk; nr_to_read -= this_chunk; } return ret; }
補足
先読みサイズは、numa単位でファイルキャッシュ用pageの使用していないpageと空きpageの合計の半分以下となります。unsigned long max_sane_readahead(unsigned long nr) { return min(nr, (node_page_state(numa_node_id(), NR_INACTIVE_FILE) + node_page_state(numa_node_id(), NR_FREE_PAGES)) / 2); }