| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- BFS
- RNN
- Linux
- Operating System
- Machine Learning
- Python
- System Call
- do it! 알고리즘 코딩테스트: c++편
- Optimization
- Seoul National University
- paper review
- Humble
- ROS2
- Data Science
- CPP
- 밑바닥부터 시작하는 딥러닝2
- CNN
- Baekjoon
- deep learning
- On-memory file system
- Gentoo2
- Multimedia
- file system
- DFS
- Process
- computer vision
- SQLD
- Robocup@Home 2026
- cs231n
- C++
- Today
- Total
newhaneul
[Operating System] Final Exam Class 2 Fall 2018 (Week 9-10, 11-12, 13-14: File System, On-Memory File System) 본문
[Operating System] Final Exam Class 2 Fall 2018 (Week 9-10, 11-12, 13-14: File System, On-Memory File System)
뉴하늘 2025. 12. 7. 15:25본 포스팅은 인하대학교 김기창 교수님의 [202502-EEC4406-001] Operating System을 수강하고 공부한 내용을 정리하기 위한 포스팅입니다.
Question:
1. Try "cp" command in "myfd" and show all the changes in the ext2 file system.
myfd 위에서 cp 명령을 실행해 보고, 그에 따라 ext2 파일 시스템 내부에서 어떤 변화들이 일어나는지 모두 보여라.

2. Make a new system call, "show_file_info(int x)" which will display the file name and file position for fd=x of the current process.
현재 프로세스의 파일 디스크립터가 x인 파일에 대해, 그 파일 이름과 파일 위치(file position) 를 출력하는 "show_file_info(int x)" 시스템 콜을 새로 만들라.
3. Modify the kernel such that it displays all page fault addresses caused by "ex1" process. Compare this result with the virtual address map (/proc/pid/maps) of “ex1” and explain why the page faults have happened for the faulted addresses. Write ex1 as follows:
커널을 수정하여 "ex1" 프로세스에서 발생하는 모든 페이지 폴트 주소를 출력하도록 하라. 그 다음 이 결과를 "ex1"의 가상 주소 맵(/proc/pid/maps)과 비교하고, 각 페이지 폴트가 왜 그 주소에서 발생했는지 설명하라.
void main(){
int x;
x=3;
for(;;);
}
(1) Answer:
1. myfd 디스크 생성

먼저 "myfd"의 디스크를 위와 같이 생성할 수 있습니다. 'dd bs=1024 count=1440 if=/dev/zero of=myfd' 명령어를 사용하여 생성할 수 있고, 디스크의 정보는 아래와 같습니다.
- block size = 1024 (=1K Bytes)
- count = 1440 (block 개수)
- if=/dev/zero (입력 파일)
- of=myfd (출력 파일 이름이 myfd인 디스크 생성
따라서 총 1.44 MB (1KB * 1440 = 1440KB) 크기의 디스크를 생성합니다.
2. 기본적인 디스크 구조
| Name | Super Block | Group Descriptor | DBM | IBM | Inode Table |
| Block Num | 1 | 2~7 | 8 | 9 | 10~32 |
| Address | 0x400 | 0x800 | 0x2000 | 0x2400 | 0x2800 |
처음에 디스크 안에 무수히 많은 0으로 채워진 "/dev/zero" 파일이 입력되었기 때문에 0x400에 위치하는 Super Block은 모두 0으로 되어져 있음을 확인할 수 있습니다.


이제 "mkfs -t ext2 myfd" 명령어를 이용해 myfd를 "ext2" 형식으로 변환해줍니다.

변환한 다음 myfd 디스크의 Super Block 위치를 다시 확인해보면, 이전과 다르게 정보들이 담겨져 있음을 확인할 수 있습니다.

Super Block이 시작되는 위치에서 값들의 의미들은 아래와 같습니다.
- 0~4Byte (b8 00 00 00): m_inodes_count에 해당되고, 10진수로 변환하면 184임을 알 수 있다. 즉, 최대 184개의 inodes를 사용할 수 있다.
- 5~8Byte (a0 05 00 00): m_blocks_count에 해당되고, 10진수로 변환하면 1440임을 알 수 있다. 즉, 블록 크기 1KB로 format했을 때의 총 Block 수와 일치한다.
- 9~12Byte (48 00 00 00)/ 13~16Byte (71 05 00 00): 각각 m_r_blocks_count와 m_free_blocks_count에 해당되고, 10진수로 변환하면 각각 72, 1393임을 알 수 있다.
3. mount

"temp" 디렉토리를 만들고 "mount -o loop myfd temp" 명령어를 통해 myfd 디스크와 temp 디렉토리를 서로 연결해주었습니다.
-------- 기본 가정 --------
지금까지가 문제의 파일 시스템 변화를 보기 전까지의 기본 가정입니다. 이 상태가 기본적으로 유지되었다고 전제 하에 디스크와 디렉토리를 서로 연결하고 디렉토리 내에 파일 변화를 준 뒤 파일 시스템을 분석하는 것입니다.
우선 디렉토리 안에 새로운 파일이나 디렉토리를 만들면 DBM (Data Bitmap), IBM (Inode Bitmap)의 비트가 1만큼 증가하게 됩니다. 그 변화를 먼저 확인해보겠습니다.
temp가 빈 디렉토리일 때의 DBM (0x2000)과 IBM (0x2400)을 분석합니다.

DBM (0x2000)

IBM (0x2400)

temp 디렉토리 안에 "f1" 파일을 새로 생성해주었습니다.

DBM (0x2000)

DBM의 경우 'ff ff ff ff ff 3f' → 'ff ff ff ff ff 7f'로 변화한 것을 확인할 수 있습니다.
변환을 진행하면 '3f ff ff ff ff' → '7f ff ff ff ff'이 되고, 16진수를 4비트로 변환하면
'0011 1111 1111 1111 1111 1111 1111 1111 1111 1111' → ' 0111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 '이 된다. 따라서 Block 개수는46개에서 47개로 바뀌었고 1 Block이 더 사용되었음을 알 수 있습니다.
IBM (0x2400)

IBM의 경우 'ff 07' → 'ff 0f'로 변화한 것을 확인할 수 있습니다.
변환을 진행하면 '07 ff' → '0f ff'이 되고, 16진수를 4비로 변환하면
'0000 0111 1111 1111' → '0000 1111 1111 1111'이 된다. 따라서 Block 개수는11개에서 12개로 바뀌었고 1 Block이 더 사용되었음을 알 수 있습니다.
root Inode table (0x2880)

root 디렉토리에 대한 정보를 확인하기 위해 Inode table의 주소인 0x2800으로 이동합니다. 이때 root 디렉토리는 inode table 2번에 위치하기 때문에 root 디렉토리의 inode table 주소는 0x2880입니다. 여기에서 확인해야할 것은 Block location을 가리키는 (2100 0000) 입니다.
root 디렉토리의 파일 위치는 앞서 확인한 block location을 사용하여 0x21 * 0x400 = 0x8400임을 계산할 수 있습니다.

0x8400을 확인해보니 root 디렉토리 안에 생성된 f1 파일이 존재함을 확인하였습니다. struct를 참고하여 해석해 보면
1)
m_inode = '02 00 00 00' → '00 00 00 02 ' → 2번 inode
m_inode = '0c 00' → '00 0c' → 12 recode length
m_name_len = '01' → 1 name length
m_file_type = '02' → 2 directory file
m_name = '2e 00 00 00' → “.” name
2)
m_inode = '02 00 00 00' → '00 00 00 02' → 2번 inode
m_inode = '0c 00' → '00 0c' → 12 recode length
m_name_len = '02' → 2 name length
m_file_type = '02' → 2 directory file
m_name = '2e 2e 00 00' → “..” name
3)
m_inode = '0b 00 00 00' → '00 00 00 0b' → 11번 inode
m_inode = '14 00' → '00 14' → 20 recode length
m_name_len = '0a' → 10 name length
m_file_type = '02' → 2 directory file
m_name = '6c 6f 73 74 2b 66 6f 75 6e 64' → “lost+found” name
4)
m_inode = '0c 00 00 00' → '00 00 00 0c' → 12번 inode
m_inode = 'd4 03' → '03 d4' → 980 recode length
m_name_len = '02' → 2 name length
m_file_type = '01' → 1 file
m_name = '66 31 00 00' → “f1” name
"f1" 파일의 inode가 12번임을 확인하였으니, 0x2800 + 0x80 * (12 - 1) = 0x2d80 계산을 통해 "f1" 파일의 inode table 주소로 이동합니다.
f1 Inode Table (0x2d80)

0x2d80에서 "f1'의 block location을 확인한 결과 0x2f = 47번째 block에 위치하는 것을 알 수 있습니다.
따라서 "f1"의 파일 주소는 0x2f * 0x400 = 0xbc00에 존재하고 있습니다.
f1 File Location (0xbc00)

파일 주소로 이동하여 확인해본 결과, "hi f1" 텍스트가 존재함을 알 수 있습니다.
이제 문제에서 요구한대로 '/root/temp' 으로 이동하고 'cp f1 f2'를 진행하여 "f1" 파일을 "f2"에 복사하여 생성한 뒤 차이를 확인해보겠습니다.

DBM (0x2000)

DBM의 경우 'ff ff ff ff ff 7f ' → 'ff ff ff ff ff ff'로 변화한 것을 확인할 수 있습니다.
변환을 진행하면 '7f ff ff ff ff' → 'ff ff ff ff ff'이 되고, 16진수를 4비트로 변환하면
'0111 1111 1111 1111 1111 1111 1111 1111 1111 1111' → ' 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 '이 된다. 따라서 Block 개수는47개에서 48개로 바뀌었고 1 Block이 더 사용되었음을 알 수 있습니다.
IBM (0x2400)

IBM의 경우 'ff 0f' → 'ff 1f'로 변화한 것을 확인할 수 있습니다.
변환을 진행하면 '0f ff' → '1f ff'이 되고, 16진수를 4비트로 변환하면
'0000 1111 1111 1111' → '0001 1111 1111 1111'이 된다. 따라서 Block 개수는12개에서 13개로 바뀌었고 1 Block이 더 사용되었음을 알 수 있습니다
Root File Location (0x8400)

0x8400을 확인해보니 root 디렉토리 안에 생성된 f2 파일이 존재함을 확인하였습니다. struct를 참고하여 해석해 보면
5)
m_inode = '0d 00 00 00' → '00 00 00 0d' → 13번 inode
m_inode = 'c8 03' → '03 c8' → 968 recode length
m_name_len = '02' → 2 name length
m_file_type = '01' → 1 regular file
m_name = '66 32 00 00' → “f2” name
"/root/temp/f2" 파일의 inode가 13번임을 확인하였으니, 0x2800 + 0x80 * (13 - 1) = 0x2e00 계산을 통해 inode table 주소로 이동합니다.
f2 Inode Table (0x2e00)

0x2e00에서 "/root/temp/f2'의 block location을 확인한 결과 0x30 = 48번째 block에 위치하는 것을 알 수 있습니다.
따라서 "root/temp/f2"의 파일 주소는 0x30 * 0x400 = 0xc000에 존재하고 있습니다.
f2 File Location (0xc000)

파일 주소로 이동하여 확인해본 결과, '"hi f1" 텍스트가 "f2" 파일에도 존재함을 알 수 있습니다.
(2) Answer:
첫 번째 단계는 system call을 선언하는 것이다. 'arch/x86/kernel/syscall_table_32.S' 경로로 이동하여 31번 syscall을 수정한다.

31번 show_file_info으로 정의하였다.
두 번째 단계는 system call을 정의하는 것이다. 'fs/read_write.c' 경로로 이동하여 31번 syscall을 문제에서 요구한 사항을 만족하도록 구현한다.

syscall은 위와 같이 구현하였다. 현재 위치를 출력하기 위해 필요한 file, dentry 등의 자료구조는 아래와 같은 형태이다.
include/linux/sched.h

- current 포인터가 가리키는 데이터 타입에 해당된다.
include/linux/fs.h

- struct file 안에는 f_pos, f_op, f_dentry 등이 들어 있고, system call에서 사용하고 있는 f->f_pos, f->f_dentry가 이에 해당된다.
include/linux/dcache.h

- 'struct qstr d_name' 현재 엔트리의 이름이 들어있는 문자열이다.
- 따라서 'fs->pwd.dentry'가 가리키는 'dentry'의 'd_name' 안에 들어있는 'name'이 현재 디렉터리 이름이다.
- pwd.dentry->d_name.name: 현재 디렉터리 이름
- pwd.dentry->d_parent->d_name.name: 부모 디렉터리 이름
test4.c

세 번째 단계는 사용자 정의 파일 'test4.c'를 구현하는 것이다. 'test4.c'를 문제에서 요구한 사항을 만족하도록 구현한다. 사용자 정의 파일은 위와 같이 “f1” 파일을 읽기 전과 후에 ‘show_file_info()’ 함수를 호출하도록 구현하였습니다.
f1

현재 “f1” 파일에는 “final_exam_2025”가 저장되어 있고, “f1”에는 5byte를 초과하는 텍스트가 저장되어져 있습니다.
“test4.c” 파일을 컴파일하고 실행한 결과는 아래와 같습니다.

“f1” 파일을 5 byte를 읽기 때문에 system call을 호출하기 전과 후로 f_pos가 0 → 5로 증가한 것을 확인할 수 있습니다.
(3) Answer:
1. 프로그램 구조
void main(){
int x;
x=3;
for(;;);
}
- int x: main() 안의 지역 변수이므로 stack 영역을 사용한다.
- main() code: 실행 코드는 code 영역을 사용한다.
페이지 크기는 4KB (0x1000)이며, 총 code/stack 2개의 페이지에 접근한다.
2. Page Fault가 발생하는 순서
(1) code page
프로세스가 시작하면, CPU가 main()의 명령어를 가져와야 하므로 code page에 접근해야 한다. 만약 code page가 메모리에 없다면 첫 번째 page fault가 발생한다.
→ 한 개의 page fault가 발생한다.
(2) stack page
main()이 호출되면, 지역 변수 x를 할당하기 위해 stack에 공간을 만든다. 이때 stack page에 접근할 때, 아직 stack page가 메모리에 없다면 두 번째 page fault가 발생한다.
→ 한 개의 page fault가 발생한다.
3. Page Fault 주소 출력
arch/x86/mm/fault.c

...

page fault는 INTERRUPT 14번 이므로 ‘do_page_fault()’가 호출됨을 알 수 있습니다. 따라서 해당 함수에서 tsk->comm이 "ex1"과 같은 경우에는 현재 page fault 주소를 출력하도록 구현하였습니다.
ex1.c

사용자 정의 파일은 위와 같이 구현하였습니다
컴파일 및 재부팅 후 현재 커널 레벨을 조절하고 컴파일 및 재부팅 후 'dmesg > x;, vi x' 를 통해 실행 결과를 확인하였습니다.
4. 실행 결과 분석
dmesg > x; vi x



dmesg에 찍힌 page fault 주소와 매칭해보면 아래와 같다.
(1) 0x08048034
- code page
- main()이 들어있는 code page가 처음 실행될 때 발생한 page fault이다.
(2) 0x804a014
- data page
- ex1.c 코드 상에 직접 선언한 전역 변수는 없지만 컴파일러가 내부적으로 사용하는 데이터에 의해 발생한 page fault로 해석된다.
(3) 0xbff307eb
- stack page
- 지역 변수 x가 들어 있는 stack page가 처음 실행될 때 발생한 page fault이다.
(4) 0xb7e*****, 0xb7f*****
- "/lib/ld-2.6.1.so", "glibc"과 같은 공유 라이브러리 페이지에서 발생한 page fault이다.
- 이는 #include 를 통한 library 파일의 영역을 include 하면서 발생된 page fault 로 해석된다.
(6) 0x8049f20 / 0x8049f6c
- main()을 초기화 하는 과정에서 발생하는 page fault로 해석된다
cat /proc/PID/maps

(1) code page
- &main = 0x8048034
- 0x8048000 <= addr < 0x8049000
- → page number = 0x8048
(2) stack page
- &x = 0xbff307eb
- 0xbff1d000 <= addr < 0xbff32000
- → page number = 0xbff3
(3) data page
- 0x804a000 <= addr < 0x804b000
- → page number = 0x804a
따라서, 예측한 페이지(code, data, stack)에 대해 실제 page fault 주소가 존재함을 확인했으며, 나머지 page fault는 라이브러리 및 초기화 코드에 의한 것으로 해석하였습니다.