Linux 페이지 캐시 일관성

Linux 페이지 캐시 일관성

Linux 페이지 캐싱에 대한 몇 가지 일반적인 질문이 있습니다. 내가 아는 한, 블록 장치의 블록을 페이지 캐시의 블록 버퍼와 연결하는 방법에는 (적어도) 세 가지가 있습니다.

  1. 디스크 장치 파일을 통해, 예:/dev/sda
  2. 예를 들어, 장치 파일을 분할하여/dev/sda1
  3. 일반 파일을 통해(예:/home/me/hello

/dev/sda1ext2와 같은 일반적인 Linux 파일 시스템이 마운트되어 /있고 /home그 안에 폴더가 있다고 가정합니다 .

이 세 가지 메서드의 address_space개체는 서로 다른 개체에 포함되어 있으므로 서로 다른 페이지 캐시를 갖습니다 inode.

  1. bdev특수 파일 inode시스템/dev/sda
  2. bdev특수 파일 inode시스템/dev/sda1
  3. ext2파일 시스템 inode/home/me/hello

이제 문제는 다음과 같습니다.

  1. super_block마운트된 파일 시스템에 대해서만 객체를 할당한 것 뿐이고 bdev실제로 어디에도 마운트되지 않았기 때문에 객체가 없는 것 같습니다 super_block. 그러면 writeback_inodes()객체를 반복 super_block하고 dirty 를 검색할 때 inode위 방법 1과 2의 페이지 캐시가 손실되므로 수동으로 디스크에 동기화해야 합니까?

  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 */
}

관련 정보