readaheadシステムコール


readaheadシステムコールは、ユーザ空間から先読み処理を行います。先読み位置/サイズをpage単位に変化してdo_readahead()をコールされ、filp->f_modeの FMODE_RANDOMの有無に関係なくforce_page_cache_readahead()がコールされます。
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);
}

最終更新 2014/12/30 14:48:27 - north
(2014/12/30 14:48:27 作成)


検索

アクセス数
3676052
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。