Linuxページのキャッシュに関する一般的な質問がいくつかあります。私が知る限り、ブロックデバイスのブロックをページキャッシュのブロックバッファに関連付ける方法は(少なくとも)3つあります。
- ディスクデバイスファイルを介して、例:
/dev/sda
- たとえば、デバイスファイルを分割して
/dev/sda1
- 通常のファイルを介して(例:
/home/me/hello
/dev/sda1
ext2などの一般的なLinuxファイルシステムがマウントされており、/
その/home
中にフォルダがあるとします。
これら3つのメソッドのaddress_space
オブジェクトは異なるオブジェクトに含まれているため、異なるページキャッシュを持ちますinode
。
bdev
特殊ファイルinode
システム/dev/sda
bdev
特殊ファイルinode
システム/dev/sda1
ext2
ファイルシステムinode
の/home/me/hello
今問題は次のとおりです。
super_block
マウントされたファイルシステムにのみオブジェクトを割り当てただけで、bdev
実際にはどこにもマウントされていないため、オブジェクトがないようですsuper_block
。それでは、writeback_inodes()
オブジェクトを繰り返してsuper_block
dirtyを検索すると、上記のinode
方法1と2のページキャッシュが失われるため、手動でディスクに同期する必要がありますか?/home/me/hello
ユーザーが上記の3つの方法すべてを介してファイルに属するディスクのブロックを読み書きできるため、3ページのキャッシュの内容が同期されない可能性がありますか?カーネル2.6.11コードでは、方法3でファイルを書くのに努力が必要であることがわかります。デバイスはディスクデバイス(方法1)またはパーティションですが、続行する前にデバイスキャッシュが同期されるのを待ちます。デバイス(方法2))ですが、両方を持つことは不可能です。そしてカーネル5.3では同様のコードが見つかりませんでした。
デバイスキャッシュを待つコード:
static int __block_prepare_write(struct inode *inode, struct page *page,
unsigned from, unsigned to, get_block_t *get_block)
{
...
unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr);
...
}
void unmap_underlying_metadata(struct block_device *bdev, sector_t block)
{
...
old_bh = __find_get_block_slow(bdev, block, 0);
if (old_bh) {
clear_buffer_dirty(old_bh);
wait_on_buffer(old_bh);
clear_buffer_req(old_bh);
__brelse(old_bh);
}
}
まだLinuxカーネルに慣れていないので、これらの質問はあまり意味がないかもしれません...ポインターありがとうございます!
答え1
ファイルシステム内のファイルの書き込み(または読み取り)とファイルシステムを持つブロックデバイスへの書き込みを混在させることは一般的ではありません。後者は、パーティションの作成やパーティションへのファイルシステムの作成などの操作にのみ使用されます。
ファイルシステムが作成されマウントされたときにブロックデバイスに書き込むと、キャッシュは同期されない可能性がありますが、これは唯一の問題ではありません。ファイルシステムをバイパスし、ブロックデバイスに直接書き込むと、確実にファイルシステムが破損します。
ブロックデバイスへの書き込みは、ルートのみを実行できる操作です。 Linuxは、ルートが自分で足を撃つためのさまざまな方法を提供し、ルートはそうしないと信じることができると仮定しています。
答え2
Q1 [...]
bdev
実際にどこにもインストールされていないため、super_block
オブジェクトがありません。したがって、writeback_inodes()
super_blockオブジェクトを繰り返してdirtyを検索すると、inode
上記の方法1と2のページキャッシュが失われます[...]
Linux/v5.3/source/fs/block_dev.c:841
struct super_block *blockdev_superblock __read_mostly;
EXPORT_SYMBOL_GPL(blockdev_superblock);
void __init bdev_cache_init(void)
{
int err;
static struct vfsmount *bd_mnt;
bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode),
0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD|SLAB_ACCOUNT|SLAB_PANIC),
init_once);
err = register_filesystem(&bd_type);
if (err)
panic("Cannot register bdev pseudo-fs");
bd_mnt = kern_mount(&bd_type);
if (IS_ERR(bd_mnt))
panic("Cannot create bdev pseudo-fs");
blockdev_superblock = bd_mnt->mnt_sb; /* For writeback */
}