리눅스의 쓰기/읽기 단위
안녕하세요.
리눅스에서 하드디스크(블록디바이스)로의 쓰기 단위가 궁금합니다.
리눅스의 I/O unit은 bio 이고.. 이것이 메모리상에 관리되는것은 페이지 케쉬로 알고 있습니다.
하지만 페이지 캐쉬 이전에 buffer_head가 먼저라고 알고있습니다. logical block 은 buffer_head를 통해 유지되기 때문입니다.
이 buffer_head는 b_page와 b_data를 통해서 자기가 속한 페이지 내의 위치를 가지고 있구요.
하나의 page는 여러개의 buffer_head와 연간이 있을 수가 있습니다.
만약 page size와 logical block size가 같다면.. 하나의 page 구조체에는 하나의 buffer_head 와 연관이 있겠네요.
이렇게 이해하고있습니다. 맞는지는 모르겠지만.
여기서.. 하드디스크의 읽고 쓰는 단위가 항상 logical block 단위 인가요?? (즉 buffer_head의 b_size크기)
실질적으로 buffer_head가 bio로 변환되어서 디바이스에 씌여질때는
submit_bh()에 나와있듯이
bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
이렇게 logical block number가 physical sector number로 변환이 되고 있는데..
이뜻이. 무조건 logical block size에 align된 단위로 쓰기와 읽기가 실행되는지 궁금합니다.
즉. 만약에 logical block size 가 4kb 이면.. 0, 4096, 8192... 섹터번호 단위로 하드디스크에 접근되고,0,3,1033 등 4KB로 align 되지 않은
섹터번호로 쓰기와 읽기가 수행되지않는것인지
명확히 알고싶네요.
struct buffer_head, struct
struct buffer_head, struct bio 뿐만 아니라 struct page 도 좀 봐주시는게 좋을 듯 합니다.
Linux에서 대부분의 입출력은 파일을 통해서 이루어지고 그럴 경우 페이지 크기인 4KB 단위로 이루어집니다. (페이지 캐쉬, struct page 참조)
하지만 경우에 따라서 한 페이지 전체가 아닌 일부분만--일명 세그멘트???-- 입출력이 필요한 경우가 있는데--예를 들면 1KB (??)인 파일시스템 수퍼블락을 하드디스크로 쓸 경우-- 그럴 경우 추가로 struct buffer_head 구조체를 이용하여 1KB 씩 디스크에 입출력을 합니다. (버퍼 캐쉬, struct buffer_head 참조)
페이지 캐쉬나 버퍼 캐쉬를 통해 발생한 하드디스크로의 입출력 요구는 struct bio를 통해 처리됩니다.
하드디스크의 경우 512 KB인 섹터 단위로 입출력이 이루어 지므로 struct bio는 섹터 단위 입출력을 지원합니다.
오랜전에 본 거라 틀린 표현이 있을 수 있습니다. 크게 개념만 보세요.
regular file인것들에
regular file인것들에 대해서는 buffer_head의 b_size 가 4KB(PAGE_CACHE 크기와 같게 설정) 이고
regular file이외의 것(e.g. filesystem의 metadata) 에 대해서 b_size가 1KB 인 buffer_head가 유지된다고 어디서 읽은것같은데 출처는 모르겠네요.
파일이 수정되었다면. 수정된 부분만 섹터단위로 업데이트 되는게 아니라. 결국. 그 수정된 부분이 포함된 logical block 전체가 업데이트 되는게 맞다는 말씀이지요?
buffer_head의 b_size가
buffer_head의 b_size가 4KB일 경우는 없을 겁니다.
regular file 입출력은 보통 페이지 캐쉬를 통해 이루어지므로 4KB 단위입니다. 이 경우 struct buffer_head는 전혀 끼어들지 않습니다--slab으로부터 할당되지도 않습니다.
device file을 대상으로 한 경우에 1KB 단위로 입출력--말씀하신 대로 filesystem metadata 입출력이 대표적 예이겠네요--이 이루어지므로 이 경우에만 struct buffer_head가 할당되어 사용됩니다. 이 경우에도 struct page는 생성됩니다.
struct page와 struct buffer_head의 관계에 대해서 잠깐 말하자면, struct buffer_head는 꼭 필요할 때만 생성되며 그와 관련된 struct page가 반드시 있습니다. 하지만 각 struct page에 관련된 struct buffer_head는 있을 수도 있고 없을 수도 있습니다.
regular file I/O의 경우에도
regular file I/O의 경우에도 buffer_head는 항상 사용됩니다.
어느 경우에 쓰이는
file mapped I/O--용어가 맞나요?--를 하는 경우 페이지 캐쉬를 통해 regular file I/O 하는 것으로 알고있습니다. 이 경우라면 struct buffer_head가 필요없는 것으로 알고 있습니다. 적어도 이 경우엔 struct buffer_head 가 필요하진 않을 듯 한데요. 왜 반드시 필요하다고 하시는 건지 알 수 있을까요?
디스크 블록 매핑
파일 데이터는 디스크 상의 특정 블록에 존재하며
이들 간의 매핑 정보를 유지하고 있는 것이 바로 buffer_head입니다.
(get_block 루틴은 결과를 buffer_head에 저장하도록 되어있습니다.)
ext[234] 파일 시스템에서 aops->write_begin의 구현을 살펴보시면
page가 buffer_head를 가지고 있지 않은 경우
bio를 생성하기 전에 이를 할당하는 부분을 찾을 수 있습니다.
듣고 보니 저도 100%
듣고 보니 저도 100% 확신을 못하겠군요 ^^; 하지만 커널 개발자들이 불필요한 작업--여기서는 struct buffer_head 할당하는 짓--을 하는 코드를 만들지는 않았을 거라 생각합니다.
ULK "15.2 Storing Blocks in the Page Cache"를 찾아 읽어보니 '페이지'가 '데이타 버퍼'를 가지는 경우는 특별히 '버퍼 페이지'라 하고 있습니다.
커널이 버퍼 페이지를 만드는 경우는
1. 한 페이지가 연속적인 디스크 블록에 쓰여지지 않은 경우나
2. 단일 디스크 블록을 접근--예를 들면 수퍼블록이나 아이노드 블록을 접근--하는 경우
등이 있다고 적혀 있습니다.
즉, 좀 더 생각해보면 이 외에는 버퍼 페이지가 필요없다는--즉 struct buffer_head 를 유지할 필요가 없다는-- 의미인 것 같습니다.
시간이 된다면 mmap()으로 대표되는 memory mapping mode와 관련된 sync(), fsync() 등의 코드를 따라가 보고 싶군요.
댓글 잘 못 달아
댓글 잘 못 달아 삭제합니다.
댓글 달기