| Write/Read/Open 처리 과정 이해

[정리]

1. 주제

- Linux Write/Read/Open의 처리 과정에 대한 이해

2. 전체 내용 요약

1) Write

 

[1) Write]

I/O에 대해 크게 2가지로 direct i/o와 buffered i/o 나눠짐

무조건적으로 block layer를 거치는 것은 아님. buffered I/O를 하게 되면 block layer를 접근하지 않음 

buffered 되는 것들은 크게 두 가지로 data block과 meta 정보임

이 두개의 정보를 buffering하기 위해 page cache를 할당 받아 사용

앞 시간에서 배운 anonymous page와 page cache의 차이점은 아래와 같음

anonymous page : file과는 상관 없으며, stack, heap 같은 것이 예임

page cache: disk block이 유지되는 곳. data block의 내용일 수도 있고, inode 같은 meta 정보일 수도 있음

pagecache: buffers + cached, 파일 관련된 내용이 저장된 곳이며, anonymous page와 구분해 파악 필요

 

 

## 하나의 task가 anonymous page를 차지하고 있는 크기 확인 법
$ cat /proc/$$/status | grep An

$$는 현재 bash의 pid 번호를 나타내며, 현재 bash가 차지하고 있는 anonymous page의 크기를 RssAnon과 같음

 

B. Buffered write

Buffered I/O의 3단계는 아래와 같으며 이후에선 buffered I/O에 대해 실습을 진행 함

1) write_begin : pagecache 준비

2) user data copy : pagecache 쓰기

3) write_end : pagecache dirty 작업

 

<Buffered i/o write 실습>

 

<buffered i/o write 실습>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void main()
{
    FILE *fp = fopen("hello.txt", "w");

    if (fp) {
        fprintf(fp, "hello linux filesystem\n");
        fclose(fp);
        sync();
    }
}
$ sudo uftrace record -K 30 -d write.uftrace.data ./write
$ uftrace tui (기존에는 replay로 봤는데, tui로 접었다 폈다를 할 수 있음)

fwrite 부분에 sys_write가 없는 이유는? 왜 fclose 부분에 있을까?

fwrite는 sys_write를 호출 안하는 것이 아님. 상황마다 상이함. 어떤 경우에선 fclose에, 어떤 경우에는 fwrite에 sys_write가 존재 할 수 있음. printf가 compile 시점에 여러가지 방법으로 설정되듯이 sys_write도 fopen/fclose 모두에서 호출될 수 있음

generic_perform_write는 bufferd_i/o를 실행시키는 핵심 함수.

앞에서 언급된 fs의 write_begin과 write_end가 포함되어 있음

mark_buffer_dirty : dirty bit 체크 하는 부분 (data)

mark_inode_dirty : dirty bit 체크 하는 부분 (inode)

stat을 통해 file의 변경사항을 볼 수 있음

 

<위의 과정에 tracing 결과에 실제 코드로 확인 실습>

sys_write -> ... -> __vfs_write -> .. -> file->f_op->write_iter => ext4_file_write_iter를 호출 함

ext4_file_write_iter -> __generic_file_write_iter -> generic_perform_write

최종 generic_perform_write에서 write_begin과 copy_from_user 그리고 write_end가 존재한다.

 

밑의 세 가지 부분에 대해 코드 상으로 더 확인할 것이다. 

1) write_begin : ext4_da_write_begin

- page caching을 위해 page buffer가 write_begin에서 어디 부분에서 할당되는지

2) copy from user : iov_iter_copy_from_user_atomic

- copy_from_user 부분에서 실제 write가 어디에서 진행되는지

3) write_end : ext4_da_write_end

- write_end에서 data (+meta)가 어디에서 dirty가 체크 되는지 

 

1) page caching을 위해 실제 page buffer를 할당 받는 위치는create_page_buffers이다.

 

2) kmap으로 addr 할당 받은 후 memcpy_from_page를 통해 copy from user를 수행 한다. 

 

 

...

3-1) Data에 대한 dirty 체크

...

3-2) inode에 대한 dirty 체크

 

write 추적에 대한 uftrace 첨부 파일

write.uftrace.data.taraa
10.00MB

 

write.uftrace.data.tarab
10.00MB
write.uftrace.data.tarac
0.05MB

+ Recent posts