본문으로 이동
  • 현재 모든 문서는 작성 중입니다. 보시는 데 불편함이 있더라도 양해 부탁드립니다.

운영체제 기본/Linux의 파일시스템/procfs의 파일 읽기

~ldmsys
관리자 (토론 | 기여)님의 2026년 10월 31일 (토) 08:14 판 (procfs /proc/uptime: VFS read_iter 연결과 seq_file 기반 출력 생성)
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)

파일시스템 구현 목차 · 이전 ext4의 파일 읽기 · 다음 페이지 캐시

Linux v6.12의 /proc/uptime은 커널 상태를 문자열로 만들어 돌려준다. ext4의 저장된 파일과 같은 read() 인터페이스를 사용하지만, 내용을 제공하는 함수는 다르다.

같은 파일 객체, 다른 연산 구현

/proc에 procfs가 마운트되어 있다면 경로 탐색은 그 마운트를 통해 procfs의 이름 공간으로 들어간다. uptime도 inode로 표현되며, 열면 열린 파일을 나타내는 struct file과 파일 디스크립터를 얻는다. 파일 읽기에서 본 것처럼 프로그램은 파일 디스크립터, 받을 버퍼, 읽을 길이를 read()에 전달한다. 프로그램이 별도의 ‘커널 상태 읽기’ 시스템 콜을 선택할 필요는 없다.

달라지는 지점은 파일 객체에 연결된 연산이다. procfs에는 VFS가 호출하는 struct file_operations와 개별 항목이 제공하는 struct proc_ops가 따로 있다. 전자는 VFS 쪽 입구이며, 그 래퍼 함수가 후자의 콜백으로 요청을 넘긴다.[1]

uptime 항목이 읽기 함수와 연결되는 과정

초기화 함수 proc_uptime_init()은 다음 호출로 항목과 출력 함수를 등록한다.[2]

pde = proc_create_single("uptime", 0, NULL, uptime_proc_show);

proc_create_single()은 proc_create_single_data()로 이어진다. 이 함수는 single_show에 출력 함수 포인터를 저장하고 proc_ops에는 proc_single_ops를 연결한다. 그 테이블에서 이 예제의 핵심은 다음 두 항목이다.[3][4]

.proc_open      = proc_single_open,
.proc_read_iter = seq_read_iter,

여기에는 proc_read_iter가 있으므로 proc_get_inode()은 inode->i_fop에 proc_iter_file_ops를 선택한다. 이름이 비슷한 proc_reg_file_ops의 .read 경로가 아니다. 열기 과정에서는 proc_reg_open()이 proc_single_open()으로 넘기고, 이어지는 single_open()이 가변 길이의 출력과 읽기 위치를 관리하는 seq_file 상태와 출력 콜백을 준비한다. 열린 파일의 private_data는 이 읽기 상태를 가리킨다.[1][4][5]

커널 상태를 문자열로 만드는 읽기

이 파일에서 일반적인 동기식 read()의 핵심 호출 경로는 다음과 같다. vfs_read()는 .read 대신 .read_iter가 있는 경우 new_sync_read()를 통해 호출 형태를 맞춘다.[6]

read()
  -> vfs_read()
  -> new_sync_read()
  -> proc_reg_read_iter()
  -> seq_read_iter()
       -> 출력이 필요하면 uptime_proc_show()
       -> 버퍼의 바이트를 사용자 버퍼로 전달

uptime_proc_show()는 CPU별 유휴 시간을 합산하고, ktime_get_boottime_ts64()로 부팅 이후 시간을 얻는다. 부팅 시간에는 timens_add_boottime()으로 시간 이름 공간의 보정도 적용한다. 그런 다음 seq_printf()로 두 값을 소수점 아래 두 자리의 문자열로 만든다. 여기서 읽히는 것은 미리 저장된 텍스트 파일의 블록이 아니라 이 함수가 커널 상태를 표본으로 삼아 생성한 바이트다. 두 번째 값은 CPU별 유휴 시간의 합이므로 첫 번째 값보다 클 수도 있다.[2]

생성한 문자열에도 위치와 버퍼가 필요하다

한 번에 몇 바이트만 요청하는 프로그램도 이 파일을 읽을 수 있어야 한다. seq_read_iter()는 내부 버퍼에 생성한 출력을 담고, 요청한 범위만 복사하며, 남은 바이트와 읽기 위치를 관리한다. 따라서 짧게 나누어 읽는다고 매번 출력 함수를 새로 호출하는 것은 아니다. 반대로 위치를 되돌리거나 출력을 다시 구성하는 상황까지 포함하여 ‘열린 파일마다 출력 함수가 정확히 한 번 실행된다’고 보장하는 것도 아니다.[5][7]

이 버퍼는 ext4의 일반적인 버퍼드 읽기에서 파일 내용을 보관하는 페이지 캐시와 같은 역할의 저장 구조가 아니다. procfs도 메모리를 사용하지만, 이 예제는 디스크 파일의 페이지를 찾아 채우는 대신 출력 콜백과 seq_file 버퍼를 사용한다. 또한 모든 procfs 항목이 이 헬퍼를 사용하는 것은 아니며, 항목마다 자료원과 읽기 구현이 다르다. 이 함수 역시 여러 CPU의 통계와 시간을 순서대로 읽으므로 모든 값이 한 순간의 원자적 스냅샷이라고 해석해서는 안 된다.[2][5]

결국 ext4와 procfs가 공유하는 것은 이름, inode, 열린 파일, 읽기 요청이라는 틀이다. 그 요청을 저장된 내용으로 만족시킬지, 실행 중인 커널 상태로부터 생성한 내용으로 만족시킬지는 연결된 구현이 결정한다.

참고 자료

  1. ↑ 1.0 1.1 Linux v6.12 fs/proc/inode.c, proc_get_inode, proc_iter_file_ops, proc_reg_open, proc_reg_read_iter.
  2. ↑ 2.0 2.1 2.2 Linux v6.12 fs/proc/uptime.c, proc_uptime_init, uptime_proc_show.
  3. ↑ Linux v6.12 include/linux/proc_fs.h, proc_create_single.
  4. ↑ 4.0 4.1 Linux v6.12 fs/proc/generic.c, proc_create_single_data, proc_single_ops, proc_single_open.
  5. ↑ 5.0 5.1 5.2 Linux v6.12 fs/seq_file.c, seq_open, single_open, seq_read_iter.
  6. ↑ Linux v6.12 fs/read_write.c, vfs_read, new_sync_read.
  7. ↑ Linux v6.12 문서 The seq_file Interface.