Linux에는 파일 열기를 처리하는 시스템 계층/스크립트가 있습니까?

Linux에는 파일 열기를 처리하는 시스템 계층/스크립트가 있습니까?

Linux에는 파일 열기에 대한 프로그램 요청을 처리하는 레이어/스크립트가 있습니까?

Bash에서 파일 설명자를 열 때와 같습니다. exec 3 <>/documents/foo.txt또는 텍스트 편집기가 열릴 때와 같습니다./documents/foo.txt

편집자가 자체적으로 읽기/쓰기 액세스를 위해 "파일을 열" 수 있다는 것을 믿을 수 없습니다.

오히려 이것이 "레이어"에 대한 요청이라고 생각합니다(init.d 스크립트?), 처음에는 특정 수의 파일만 열 수 있으며 액세스 유형, 파일을 연 프로세스 등에 따라 열려는 파일을 면밀히 관찰할 수 있습니다.

답변1

이 계층은 Linux 및 기타 시스템의 커널 내부에 있으며 (대부분의 비 Unix 운영 체제와 마찬가지로) 역사적인 Unix 설계와 크게 다르지 않습니다.

커널의 이 부분을 커널이라고 합니다.VFS(가상 파일 시스템) 계층. VFS의 기능은 열린 파일의 정보(파일 간 대응)를 관리하는 것입니다.파일 설명자,파일 설명 열기및 디렉터리 항목), 파일 경로를 확인하고(및 해석 /) 디렉터리 항목에 대한 작업을 올바른 파일 시스템 드라이버에 전달합니다....

대부분의 파일 시스템 드라이버도 커널에 있지만퓨즈파일 시스템 드라이버를 사용하면 이 기능을 커널 외부에 위임할 수 있습니다. 예를 들어 디스크 파일 시스템이 있는 경우와 같이 낮은 수준의 저장소에서 수행되는 경우 파일 시스템 작업에는 사용자 도메인 코드가 포함될 수도 있습니다.순환 장치.

답변2

Linux에서 파일 열기는 커널에 의해 직접 처리됩니다.그러나 프로세스에 영향을 미치고 연구하기 위해 할 수 있는 일이 있습니다.


Linux 스토리지 스택 다이어그램


시스템 호출

맨 위에서부터 애플리케이션이 파일과 상호 작용하는 데 사용하는 인터페이스가 다음과 같은 것을 볼 수 있습니다.시스템 호출.

열려 있는,읽다그리고쓰다그 동안 기대하는 대로 해라통계자료파일을 열지 않고 파일에 대한 정보를 반환합니다.

strace를 사용하여 프로그램의 파일 관련 시스템 호출 사용을 조사할 수 있습니다.

$ strace -e trace=%file /bin/ls /etc
[...]
stat("/etc", {st_mode=S_IFDIR|0755,  ...}) = 0
openat(AT_FDCWD, "/etc", O_RDONLY...) = 3

이는 결과 시스템 호출을 분석하여 디렉토리에서 및 가 호출 되고 있음 ls /etc을 보여줍니다 .statopenat/etc

디렉토리에서 파일 작업을 호출하는 이유가 궁금할 것입니다. UNIX에서는 디렉토리도 파일입니다. 실제로모든 것이 파일이다!


파일 설명자

openat() = 3위의 출력 내용이 무엇인지 궁금할 것입니다 .

UNIX에서는 파일이 다음으로 열립니다.파일 설명자, 이는 프로세스에서 연 파일의 유일한 표현입니다. 파일 설명자 0, 1, 2는 일반적으로 예약되어 있습니다.표준 스트림(사용자 입력/출력)이므로 처음으로 열리는 파일은 3이 됩니다.

다음을 사용하여 특정 프로세스에 대해 열린 파일 설명자 목록을 얻을 수 있습니다.lsof(에스에프섬):

$ cat /dev/urandom > /dev/null &
[1] 3242
$ lsof -p 3242
COMMAND  PID      USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
...
cat     3242 user         0u   CHR  136,0      0t0      3 /dev/pts/0
cat     3242 user         1w   CHR    1,3      0t0   1028 /dev/null
cat     3242 user         2u   CHR  136,0      0t0      3 /dev/pts/0
cat     3242 user         3r   CHR    1,9      0t0   1033 /dev/urandom

FD열에는 파일 설명자 번호와 액세스 권한이 표시됩니다.

당신은 또한 사용할 수 있습니다fuser특정 파일을 저장하는 프로세스를 검색합니다.

$ fuser /dev/urandom
/dev/urandom:         ...  3242  ...

프로세스 정보 의사 파일 시스템-/proc

이제 당신은 궁금할 것입니다:하지만 무엇을 해야할지 lsof하지만 먼저?

자, 한번 살펴보자!

$ strace -e trace=%file lsof -p 3242
...
stat("/proc/3242/", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
openat(AT_FDCWD, "/proc/3242/stat", O_RDONLY) = 4
...
openat(AT_FDCWD, "/proc/3242/fd", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
readlink("/proc/3242/fd/0", "/dev/pts/0", 4096) = 10
lstat("/proc/3242/fd/0", {st_mode=S_IFLNK|0700, st_size=64, ...}) = 0
stat("/proc/3242/fd/0", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
openat(AT_FDCWD, "/proc/3242/fdinfo/0", O_RDONLY) = 7
...

따라서 lsof어떤 파일을 열지 알아보세요. 더 많은 파일을 읽어보세요! 특히, 디렉토리 /proc/3242/fd아래의 모든 것은 /proc커널이 보유하는 "가짜" 파일 시스템입니다. ls -l쭉 보시면서 그 구조를 보실 수 있습니다 .


파일 열기에 영향을 미칩니다

파일 열기에 영향을 주는 데 사용할 수 있는 방법은 여러 가지가 있지만 일부 스크립트를 바꾸는 것만큼 간단하지는 않습니다.

암호화 제공, 캐싱, 여러 디스크에 파일 분산 등 파일 저장 또는 액세스 방식을 변경하려는 경우 기존에장치 매퍼귀하의 요구에 적합합니다.

특정 디렉터리/마운트에서 파일 열기를 세밀하게 제어하려면 다음과 같이 간단하게 작성할 수 있습니다.퓨즈파일 시스템을 마운트하고 마운트합니다.

프로그램/프로세스 수준에서 다음을 사용할 수 있습니다.LD_예압C 라이브러리 호출을 변경하고 정상적인 시스템 호출이 실행되지 않도록 합니다.

가장 어렵지만 가장 유연한 방법은 자신만의 파일 시스템 드라이버를 작성하는 것입니다.

답변3

파일에 대한 액세스를 관리하는 것은 운영 체제의 첫 번째이자 가장 중요한 기능입니다. DOS는 개인용 컴퓨터에서 가장 오래된 운영 체제 중 하나이며 디스크 운영 체제를 의미합니다. 대부분의 경우 프로그램이 하드웨어에 직접 액세스할 수 있지만 파일에는 액세스할 수 없습니다. 프로그램은 DOS 호출을 사용해야 하며 DOS는 프로그램이 데이터를 넣거나 빼는 파일을 관리합니다. 디스크 유틸리티만 DOS에서 하드 드라이브와 파일에 직접 액세스할 수 있습니다.

최신 보호 모드 운영 체제(예: Linux)는 DOS처럼 파일 액세스를 처리하지만 프로그램 자체(또는 메모리를 공유하도록 구성된 다른 프로그램) 외부의 모든 액세스는 커널( 리눅스는 커널이다.)

Linux의 프로그램은 C 라이브러리의 함수를 호출하여 파일 데이터를 읽거나 파일에 데이터를 쓸 수 있습니다. 그런 다음 C 라이브러리는 프로그램과 동일한 컨텍스트에서 계속 실행되는 동안 파일의 데이터에 대한 액세스를 구성하는 역할을 수행합니다. 그런 다음 C 라이브러리는 커널(Linux)에 대한 올바른 함수 호출을 사용하여 파일에 액세스하고 CPU를 링 0 또는 권한 모드로 전환합니다. 이제 CPU는 Linux 파일 시스템 드라이버와 하드 디스크 드라이버 소프트웨어를 권한 모드로 실행하여 하드웨어에 직접 액세스하여 파일에 액세스합니다. 데이터는 C 라이브러리가 Linux에 데이터를 배치하도록 지시하고 CPU가 사용자 모드로 다시 전환되어 프로그램의 보안 컨텍스트를 가지며 C 라이브러리가 재개되어 필요한 모든 처리를 수행하는 메모리 영역에 복사됩니다. 그런 다음 이 데이터는 실행을 위해 프로그램으로 반환됩니다.

답변4

간단히 말해서, 이것은 프로그램이 파일에 쓸 때 일어나는 일입니다.

  1. 프로그램은 open쓰기 위해 커널의 경로로 지정된 파일을 요청합니다.
  2. 커널은 일부 내부 구조를 설정하고 파일을 여는 일부 작업을 파일 시스템 유형과 관련된 드라이버에 위임합니다. 그런 다음 커널은 정수(예: 3)인 파일 설명자를 프로그램에 반환합니다.
  3. write프로그램은 파일 설명자가 참조하는 파일에 일련의 바이트(예: 문자열)를 추가 하도록 커널에 요청합니다 .
  4. 커널은 다시 작업을 드라이버에 위임합니다.
  5. 3단계와 4단계는 여러 번 반복될 수 있습니다.
  6. close프로그램은 파일 설명자가 참조하는 파일을 커널에 요청합니다 .
  7. 커널은 다시 작업을 드라이버에 위임한 다음 내부 구조를 파괴합니다.

다음은 Greeting.txt 파일에 "Hello World!"를 작성하는 매우 간단한 어셈블러 프로그램입니다.

.text
.globl _start

_start:
    # Open and possible create file
    mov $2,             %rax        # syscall 'open'
    mov $path_start,    %rdi        # path
    mov $0101,          %rsi        # create + write
    mov $400,           %edx        # only user gets read permissions
    syscall

    mov %rax,           %r10        # file descriptor

    # Write string to file
    mov $1,             %rax        # syscall 'write'
    mov %r10,           %rdi        # file descriptor
    mov $msg_start,     %rsi        # start of data
    mov $msg_length,    %edx        # length of data
    syscall                         # perform syscall

    # Close file
    mov $3,             %rax        # syscall 'close'
    mov %r10,           %rdi        # file descriptor
    syscall

    # Exit program
    mov $60,            %rax        # syscall 'exit'
    syscall                         # perform syscall


.section .rodata

path_start:
    .string "greeting.txt\0"
path_end:
path_length = path_end - path_start


msg_start:
    .string "Hello World!\n"
msg_end:
msg_length = msg_end - msg_start

코드를 write.s에 저장하고 다음으로 빌드하세요.

as -o write.o write.s
ld -o write   write.o

그런 다음 실행

./write

모든 것이 괜찮기를 바랍니다.

(참고: 오류 처리를 수행하지 않습니다. 이것은 단지 장난감 코드일 뿐입니다.)

관련 정보