ブロックデバイスのキャッシュとファイルシステム

ブロックデバイスのキャッシュとファイルシステム

ブロック装置はバッファリングを提供する。。これはwrite()、カーネルがデバイスにデータを書き込む前にブロックデバイスから成功を返す可能性があることを意味します。プログラムはを呼び出して、すべてのバッファリングされた書き込みを待つことができますfsync()

dd(または)を使用してcatファイルシステムイメージをデバイスに書き込みました。これらのコマンドはデフォルトでは呼び出されませんfsync()

mount次に、ブロックデバイスにファイルシステムとして書きたいとします。

私の考えの最も安全な方法は、syncインストールする前にこのコマンドを使用することです。しかし、ブロックデバイスを同期しないとどうなりますか?ファイルシステムがまだデバイスに書き込まれていないいくつかのブロックを読み取ろうとする可能性はありますか?それでは、ファイルシステムイメージの正しいデータの代わりにデバイスの以前の内容を読み取ることができますか?

私の主な関心はLinuxの動作です。 (StackExchangeは私に特定の質問をするように勧めましたが、代替または歴史的措置に賛成票を与えることもできます:-)。

答え1

プログラムがブロックデバイスファイルを閉じると、Linuxは関連キャッシュをフラッシュしてプログラムを待機します。ただし、これは最後の項目にのみ適用されますclose()。他のデバイスがまだブロックデバイスを開いたままにしている場合、これは発生しません。次の場合を含めるすべてのパーティション同じ機器がまだ開いています。

したがって、通常、どのような方法でもデバイスを同期することをお勧めします。

安全のためにデバイスを同期する方法は、ddoptionsでコマンドを実行することですconv=fsync。これがなければ、カーネルは書き込みエラーを返しません。したがって、カーネルログ()を見るとdmesgエラーだけがわかります。

キャッシュされたすべての書き込みを待つだけでなく、最後の書き込みはすべてのclose()キャッシュを破棄します(kill_bdev())。私はコマンドの出力を観察してこれを直接確認しましたfree

linux-4.20/fs/block_dev.c:1778

static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
{
    struct gendisk *disk = bdev->bd_disk;
    struct block_device *victim = NULL;

    mutex_lock_nested(&bdev->bd_mutex, for_part);
    if (for_part)
        bdev->bd_part_count--;

    if (!--bdev->bd_openers) {
        WARN_ON_ONCE(bdev->bd_holders);
        sync_blockdev(bdev);
        kill_bdev(bdev);

Cコードに慣れていない場合、上記の最後のブロックは次のようになります。

    bdev->bd_openers = bdev->bd_openers - 1;
    if (bdev->bd_openers == 0) {
        WARN_ON_ONCE(bdev->bd_holders);
        sync_blockdev(bdev);
        kill_bdev(bdev);

答え2

システムの競合を適切に処理するにはsync/が必要です。fsync

カーネルは一貫性を提供します。すべての書き込みはディスクにフラッシュされるまでダーティバッファに保持され、すべての読み取りはこれらのダーティバッファで最初に承認されます。

ただし、同期前に電源が切れると、カーネルバッファが消え、dd(1)の一部は保持されません。これはぎこちないかもしれません。

衝突に加えて、カーネルはすべてを透過的に処理するので、基本的にバッファリングを忘れることができます。

関連情報