Linux 페이지 캐싱에 대한 몇 가지 일반적인 질문이 있습니다. 내가 아는 한, 블록 장치의 블록을 페이지 캐시의 블록 버퍼와 연결하는 방법에는 (적어도) 세 가지가 있습니다.
- 디스크 장치 파일을 통해, 예:
/dev/sda
- 예를 들어, 장치 파일을 분할하여
/dev/sda1
- 일반 파일을 통해(예:
/home/me/hello
/dev/sda1
ext2와 같은 일반적인 Linux 파일 시스템이 마운트되어 /
있고 /home
그 안에 폴더가 있다고 가정합니다 .
이 세 가지 메서드의 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
사용자가 위에 나열된 세 가지 방법 모두를 통해 파일에 속하는 디스크의 블록을 읽고 쓸 수 있어 세 페이지 캐시의 내용이 동기화되지 않을 수 있습니까 ? 커널 2.6.11 코드에서 방법 3에서 파일을 작성하는 데 노력이 필요하다는 것을 알 수 있습니다. 장치는 디스크 장치(방법 1) 또는 파티션일 수 있지만 계속하기 전에 장치 캐시가 동기화될 때까지 기다립니다. device (방법 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의 페이지 캐시가 손실됩니다 [...]
리눅스/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 */
}