시스템 호출에서 파일 설명자를 사용하고 싶다고 가정해 보겠습니다(fd 번호는 매개변수를 통해 제공됩니다). 사용자 공간 프로그램이 이 시스템 호출을 사용하면 어떻게 되나요? OS는 이 특정 fd를 어디에서 찾습니까? 현재 프로세스의 파일 설명자에 있나요? 아니면 다른 곳에 있나요?
아래에서는 이 점을 설명하려고 합니다.
+--------------+ +----++--------------+
| Kernel space | | fd || User space |
| | |list|| |
| handler <---------------- syscall(fd) |
| | | || |
+--------------+ +----++--------------+
답변1
파일 디스크립터는 특정 프로세스에서 열린 모든 파일 중 하나의 파일을 참조하는 정수입니다. 일반적으로 이는 파일 설명자를 테이블에 대한 인덱스로 처리하여 커널에 의해 수행됩니다.
내 대답의 나머지 부분은 Linux에 적용됩니다.
Linux에서 각 유효한 파일 설명자는 와 연결됩니다 struct file
. 이 구조에는 inode(파일의 데이터 및 메타데이터)에 대한 포인터, 파일에서 프로세스의 현재 위치, 작업 목록(실제로는 파일이 있는 파일에 대한 포인터)이 포함되어 있습니다. 파일이 위치함) 시스템에 의해 구현된 기능에 대한 포인터) 등
file
파일 설명자에서 구조를 얻으려면 Linux 커널이 다음과 같이 진행됩니다. 여기서는 시스템 호출을 예로 들겠습니다 read
.
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
struct fd f = fdget_pos(fd);
ssize_t ret = -EBADF;
if (f.file) {
loff_t pos = file_pos_read(f.file);
ret = vfs_read(f.file, buf, count, &pos);
if (ret >= 0)
file_pos_write(f.file, pos);
fdput_pos(f);
}
return ret;
}
첫 번째 작업은 fdget_pos
사용자 공간의 호출자로부터 파일 설명자를 매개변수로 가져와 다음과 같이 정의된 file
파일을 반환합니다.struct fd
struct fd {
struct file *file;
unsigned int flags;
};
이것은 기본적으로 struct file
구조를 다시 넣을 때 필요한 작업을 기억하는 몇 가지 플래그가 있는 하나입니다.
자, fdget_pos
그것이 어떻게 작동하는지. 실제로는 이상한 방식으로 복잡하지만 두 가지 기본 작업으로 요약됩니다(단순화를 위해 여기서는 더 많은 확인 사항을 표시하지 않습니다).
첫 번째는 프로세스의 파일 테이블을 가져오는 것입니다. 테이블은 호출자의 프로세스 구조에 있는 포인터를 통해 사용할 수 있습니다(다음을 통해 액세스 가능) current
.
struct files_struct *files = current->files;
다음 작업에는 파일 설명자의 유효성을 확인하는 작업이 포함됩니다.
if (fd < files->fdt->max_fds) // first of all, if the file descriptor is too big, then it cannot be valid
return files->fdt->fd[fd]; // otherwise, we return the pointer stored in the table of file descriptors (may be NULL)
return NULL;
이 포인터는 함수가 반환되기 전에 제거될 수 있습니다(예를 들어 프로세스의 한 스레드가 read
동일한 파일 설명자에서 동시에 다른 스레드를 실행하는 경우). close
커널은 이 문제를 처리하는 역할을 담당합니다.
struct file
반환된 포인터가 fdget_pos
이면 시스템 NULL
호출에 전달된 파일 설명자가 유효하지 않음을 의미합니다. 이 경우 시스템 호출은 오류 코드 EBADF
("잘못된 파일 설명자")를 반환합니다.
요약하자면, 파일 설명자는 각 프로세스의 파일 설명자 테이블에 대한 색인일 뿐입니다. 그러나 단순히 역참조하는 것만으로는 충분하지 않습니다 NULL
. 왜냐하면 파일 테이블의 항목은 .