今回のまとめ
- msync(MS_ASYNC)は、何もしないを実行する(意味不明)
msyncの闇に足を踏み込もう
この場合、メモリ領域がディスクへ書き戻す必要があることを通知するのはmsync(2)です。MS_ASYNCを指定すると、通知するだけでシステムコールは終了します。MS_SYNCを指定すると、通知に加え、内部でfsync(2)相当の処理も行われ、ディスクにまで書き戻します。
このあたりのソースコードを読んでいく。
Linux Kernelのコメント
/*
- MS_SYNC syncs the entire file - including mappings.
- MS_ASYNC does not start I/O (it used to, up to 2.5.67).
- Nor does it marks the relevant pages dirty (it used to up to 2.6.17).
- Now it doesn't do anything, since dirty pages are properly tracked.
- The application may now run fsync() to
- write out the dirty pages and wait on the writeout and check the result.
- Or the application may run fadvise(FADV_DONTNEED) against the fd to start
- async writeout immediately.
- So by not starting I/O in MS_ASYNC we provide complete flexibility to
- applications.
*/
MS_SYNC は、mappingを含むすべてのファイルを同期を取る。
MS_ASYNCは、I/Oを開始しません(2.5.67以前までは利用していました)。
更に、dirty pagesと関連付けてマークすることもしません(2.6.17以前まではマークしていました)。
現時点では、ダーティページは適切に追跡されるので、今は何もしていません。
アプリケーションは、dirty pagesを書きだすため、書き込みが終わるあるいは結果をチェックするためにfsync()を実行できる。
あるいは、アプリケーションは即座に非同期に書き出すために、fadvise(FADV_DONTNEED)を実行できる。
したがって、MS_ASYNCにおいて、I/Oを開始しないことによって、アプリケーションに対して完全な柔軟性を提供できる。
実際のソースコードを見てみる
重要な部分だけを抜き出すと、
/*
* If the interval [start,end) covers some unmapped address ranges,
* just ignore them, but return -ENOMEM at the end.
*/
down_read(&mm->mmap_sem);
vma = find_vma(mm, start);
for (;;) {
<略>
start = vma->vm_end;
if ((flags & MS_SYNC) && file &&
(vma->vm_flags & VM_SHARED)) {
get_file(file);
up_read(&mm->mmap_sem);
error = vfs_fsync_range(file, fstart, fend, 1);
fput(file);
if (error || start >= end)
goto out;
down_read(&mm->mmap_sem);
vma = find_vma(mm, start);
} else {
if (start >= end) {
error = 0;
goto out_unlock;
}
vma = vma->vm_next;
}
}
ということで、MS_SYNCが指定されていてマッピングできていれば、vfs_fsync_range()とfput(file)によって反映させる。
そうでない場合には、本当に何もしません、と。
そうしたら、MS_ASYNC指定したら、いつ反映されるのか?は、dirty pageの扱いで、pdflush()によるデフォルト5秒ごとの更新、と。
きれいにしたのはこちらのパッチ
どうやら、dirty statusのハンドリングが自動化できるようになったので、わざわざフラグ設定するのはムダになった、を含めてリファクタリングしたようでございますね。なるほどなるほど。
[PATCH] mm: msync() cleanup
With the tracking of dirty pages properly done now, msync doesn't need to scan the PTEs anymore to determine the dirty status.From: Hugh Dickins
In looking to do that, I made some other tidyups: can remove several #includes, and sys_msync loop termination not quite right.
Most of those points are criticisms of the existing sys_msync, not of your patch.
In particular, the loop termination errors were introduced in 2.6.17: I did notice this shortly before it came out, but decided I was more likely to get it wrong myself, and make matters worse if I tried to rush a last-minute fix in. And it's not terribly likely to go wrong, nor disastrous if it does go wrong (may miss reporting an unmapped area; may also fsync file of a following vma).
ダーティページの追跡が適切に行うようになったため、msyncではdirty statusを判別するために、PTEをスキャンする必要がなくなりました。
From: Hugh Dickins
これを実行するためには、私は不要なinludeを削除するなどいくつかの整理を行いました。そして、sys_nsyncのループ終了条件が正しくありませんでした。
これらの点のほとんどは、あなたのパッチではなく、既存のsys_msyncへの問題指摘です。特に、ループ終了エラーについては2.6.17で導入されていました。この問題が起きる少し前に気が付きましたが、自分で間違える可能性が高く、土壇場で修正をすると自体がさらに悪化する事になりました。それはうまくいきませんでした(マップされていない領域の報告を見逃す可能性があります、また次のvmaのfsyncファイルもある可能性があります)。