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);
}






