Linux 커널 시스템 호출 구현을 어떻게 찾을 수 있습니까?


375

mkdir커널 소스를 보면서 함수가 어떻게 작동하는지 이해하려고합니다 . 이것은 커널 내부를 이해하고 다양한 기능을 탐색하려는 시도입니다. mkdir에 정의되어 있음을 알고 sys/stat.h있습니다. 프로토 타입을 찾았습니다.

/* Create a new directory named PATH, with permission bits MODE.  */
extern int mkdir (__const char *__path, __mode_t __mode)
     __THROW __nonnull ((1));

이제이 함수가 어느 C 파일에 구현되어 있는지 확인해야합니다. 소스 디렉토리에서 시도했습니다

ack "int mkdir"

어느 표시

security/inode.c
103:static int mkdir(struct inode *dir, struct dentry *dentry, int mode)

tools/perf/util/util.c
4:int mkdir_p(char *path, mode_t mode)

tools/perf/util/util.h
259:int mkdir_p(char *path, mode_t mode);

그러나 이들 중 어느 것도의 정의와 일치하지 않습니다 sys/stat.h.

질문

  1. 어떤 파일이 mkdir구현되어 있습니까?
  2. 위와 같은 함수 정의를 사용하여 어떤 파일이 구현되어 있는지 어떻게 알 수 있습니까? 메소드를 정의하고 구현할 때 커널이 따르는 패턴이 있습니까?

참고 : 커널 2.6.36-rc1 사용하고 있습니다.


2
그건 그렇고, 이것을 확인하십시오 : voinici.ceata.org/~tct/resurse/utlk.pdf
Tom Brito

답변:


386

시스템 호출은 일반 함수 호출처럼 처리되지 않습니다. 사용자 공간에서 커널 공간으로 전환하려면 특수 코드가 필요합니다. 기본적으로 호출 사이트에서 프로그램에 인라인 어셈블리 코드가 약간 주입됩니다. 시스템 호출을 "잡는"커널 사이드 코드는 최소한 처음에는 깊이 이해할 필요가없는 하위 수준의 것입니다.

에서 include/linux/syscalls.h커널 소스 디렉토리 아래에, 당신은이를 찾을 수 :

asmlinkage long sys_mkdir(const char __user *pathname, int mode);

그런 다음에서 /usr/include/asm*/unistd.h이것을 찾으십시오.

#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)

이 코드는 mkdir(2)시스템 호출 # 83입니다. 즉, 시스템 호출은 사용자 프로그램 내에서 일반적인 함수 호출이나 프로그램에 연결된 라이브러리의 함수와 같이 주소가 아닌 번호로 호출됩니다. 위에서 언급 한 인라인 어셈블리 글루 코드는이를 사용하여 매개 변수와 함께 사용자 공간에서 커널 공간으로 전환합니다.

여기에서 상황이 조금 이상하다는 또 다른 증거는 시스템 호출에 대해 항상 엄격한 매개 변수 목록이있는 것은 아니라는 것 open(2)입니다. 예를 들어, 2 또는 3 개의 매개 변수를 사용할 수 있습니다. 그 수단이 open(2)되어 과부하 , C ++이 아닌 C의 기능을 아직 콜 인터페이스는 C-호환됩니다. (이것은 C의 varargs 기능 과 동일하지 않으므로 단일 함수가 다양한 수의 인수를 취할 수 있습니다.)

첫 번째 질문에 대답하기 위해 mkdir()존재하는 단일 파일이 없습니다 . 리눅스는 많은 다른 파일 시스템을 지원하며 각각은 "mkdir"연산의 자체 구현을 가지고 있습니다. 커널이 단일 시스템 호출 뒤에있는 모든 것을 숨길 수있는 추상화 계층을 VFS 라고합니다 . 따라서을 (를 fs/namei.c) 사용하여 파기를 시작하고 싶을 것 입니다 vfs_mkdir(). 저수준 파일 시스템 수정 코드의 실제 구현은 다른 곳입니다. 예를 들어, ext4 구현은 ext4_mkdir()에 정의되어 fs/ext4/namei.c있습니다.

두 번째 질문에 관해서는 그렇습니다.이 모든 것에 패턴이 있지만 단일 규칙은 아닙니다. 실제로 필요한 것은 특정 시스템 호출을 어디에서 찾아야하는지 파악하기 위해 커널이 작동하는 방식을 상당히 광범위하게 이해하는 것입니다. 모든 시스템 호출에 VFS가 포함되는 것은 아니므로 커널 측 호출 체인이 모두에서 시작되지는 않습니다 fs/namei.c. mmap(2)예를 들어, mm/mmap.c은 커널의 메모리 관리 ( "mm") 하위 시스템의 일부이기 때문에로 시작 합니다.

Bovet과 Cesati의 " Linux 커널 이해 "사본을받는 것이 좋습니다 .


아주 좋은 대답입니다. "리눅스 커널 이해하기"에 언급 된 책에 대한 한 가지 요점. 나는 그것을 가지고 있지 않지만 릴리스 날짜 (2000)와 TOC (oreilly 사이트)는 약 2.2 커널과 2.4 커널의 통찰력 (그러나 나는 틀렸다) 인 것처럼 보인다. 내 질문은 : 2.6 커널 내부를 다루는 동등한 책이 있습니까? (또는 2.2, 2.4 및 2.6보다 더 나은)?
DavAlPi

2
@DavAlPi : 내가 아는 한, Bovet & Cesati는 여전히이 주제에 대한 최고의 단일 책입니다. 최신 자료로 보완해야 할 때 Documentation작업중인 커널의 소스 트리 하위 디렉토리를 파고 들었습니다 .
워렌 영

1
실제로 open (2)는 varargs 함수입니다. 이를 호출하는 방법은 두 가지뿐이므로 맨 페이지는 이런 식으로 문서화합니다. 실제 프로토 타입에는 ...varargs 함수가 있습니다. 물론 이것은 libc 수준에서 구현됩니다. 세 번째 매개 변수를 사용하지 않으면 커널 ABI에 0 또는 가비지 값을 전달할 수 있습니다.
Random832

"이것은 당신이 이해할 필요가 없습니다". 이런 종류의 문장이 스택 교환 네트워크에서 찾을 수 없다면 세계가 더 나은 곳이 될 것입니다.
Petr

84

이것은 아마도 귀하의 질문에 직접 대답하지는 못하지만 strace, 가장 간단한 쉘 명령조차도 수행되는 기본 시스템 호출을 이해하려고 할 때 정말 멋지다 는 것을 알았 습니다. 예 :

strace -o trace.txt mkdir mynewdir

mkdir mynewdir사용자가보기에 편리하도록 시스템 명령 이 trace.txt에 덤프됩니다.


5
깔끔한 트릭 +1! 나는 전에 그것을 사용하지 않았다
David Oneill

3
더 나은 방법은 출력 파일을 trace.strace로 만들어 VIM에서 엽니 다. VIM은이를 강조하여 더 쉽게 읽을 수있게합니다.
Marcin

55

Linux 커널 소스를 읽기에 좋은 곳은 Linux 상호 참조 (LXR) ¹입니다. 검색은 자유 텍스트 검색 결과와 함께 유형이 일치하는 항목 (함수 프로토 타입, 변수 선언 등)을 반환하므로 단순한 grep보다 빠릅니다 (더 빠름).

LXR은 전 처리기 정의를 확장하지 않습니다. 시스템 호출의 이름은 모든 곳에서 전처리기에 의해 엉망이됩니다. 그러나 대부분의 시스템 호출은 SYSCALL_DEFINEx매크로 제품군 중 하나를 사용하여 정의됩니다 . 이후로는 mkdir두 개의 인수, 대한 검색 소요 SYSCALL_DEFINE2(mkdir받는 리드 의 선언 mkdir콜을 :

SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
{
    return sys_mkdirat(AT_FDCWD, pathname, mode);
}

좋아, sys_mkdirat그것이 mkdiratsyscall 이라는 것을 의미하므로 그것을 클릭하면의 선언으로 이어지지 include/linux/syscalls.h만 정의는 바로 위에 있습니다.

주요 작업은 mkdirat호출하는 것입니다 vfs_mkdir(VFS는 일반 파일 시스템 계층입니다). 그것에 대한 클릭하면 두 개의 검색 결과가 나타납니다 :의 선언 include/linux/fs.h과 위의 몇 줄의 정의. 의 주요 작업은 vfs_mkdir파일 시스템 별 구현을 호출하는 것 dir->i_op->mkdir입니다. 이것이 어떻게 구현 되는지 알아 보려면 개별 파일 시스템의 구현으로 전환해야하며, 빠르고 엄격한 규칙은 없으며 심지어 커널 트리 외부의 모듈 일 수도 있습니다.

¹ LXR은 인덱싱 프로그램입니다. LXR에 인터페이스를 제공하는 여러 웹 사이트가 있으며, 약간 다른 버전의 알려진 버전과 약간 다른 웹 인터페이스가 있습니다. 그것들은왔다 갔다하는 경향이 있으므로, 익숙한 것이 없다면, "linux cross-reference"를 웹 검색하여 다른 것을 찾으십시오.


그것은 자원 중 하나입니다. 좋은 대답입니다.
Stabledog

의 링크에서 "내부 서버 오류" linux.no .
Fredrick Gauss

@FredrickGauss 잠시 동안 lxr.linux.no는 LXR에 대한 가장 멋진 인터페이스 였지만 다운 타임이 자주 발생했습니다. 이제는 잘됐다고 생각합니다. 다른 LXR 인터페이스에 대한 첫 번째 링크를 교체했습니다.
Gilles

21

시스템 호출은 일반적으로 SYSCALL_DEFINEx()매크로에 싸여 있기 때문에 간단한 것으로 grep찾지 못합니다.

fs/namei.c:SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)

매크로가 확장 된 후의 최종 함수 이름은 sys_mkdir입니다. 이 SYSCALL_DEFINEx()매크로는 각 syscall 정의에 필요한 추적 코드와 같은 상용구를 추가합니다.


17

참고 : .h 파일은 기능을 정의 하지 않습니다 . 그건 선언 이 .H 파일에 다른 곳 (구현) 정의. 이를 통해 컴파일러는 함수의 서명 (프로토 타입)에 대한 정보를 포함하여 인수의 유형 검사를 허용하고 리턴 유형을 코드의 호출 컨텍스트와 일치시킬 수 있습니다.

일반적으로 C의 .h (헤더) 파일은 함수를 선언하고 매크로를 정의하는 데 사용됩니다.

mkdir특히 시스템 호출입니다. 해당 시스템 호출 주위에 GNU libc 래퍼 가있을 수 있습니다 (실제로 거의 있습니다). 실제 커널 구현은 mkdir커널 소스와 특히 시스템 호출을 검색하여 찾을 수 있습니다.

또한 각 파일 시스템마다 일종의 디렉토리 작성 코드가 구현됩니다. VFS (가상 파일 시스템) 계층은 시스템 호출 계층이 호출 할 수있는 공통 API를 제공합니다. 모든 파일 시스템은 VFS 계층이 호출 할 기능을 등록해야합니다. 이를 통해 다른 파일 시스템은 디렉토리가 어떻게 구조화되는지에 대한 고유 한 의미를 구현할 수 있습니다 (예 : 특정 항목을보다 효율적으로 검색하기 위해 일종의 해싱 구성표를 사용하여 저장 한 경우). Linux 커널 소스 트리를 검색하는 경우 이러한 파일 시스템 특정 디렉토리 작성 기능을 넘어갈 가능성이 있기 때문에 이것을 언급합니다.


8

찾은 구현 중 어느 것도 sys / stat.h의 프로토 타입과 일치하지 않습니다.이 헤더 파일을 사용하여 include 문을 검색하면 더 성공할 수 있습니까?


1
sys / stat.h에 설명 된대로 구현은 userland 및 libc의 비즈니스입니다. 커널 내부 작업 ( 실제로 수행되는 방식)은 커널 내부 비즈니스입니다. 모든 커널 해커의 관리를 위해 내부 기능을 xyzzy라고하며 5 개의 매개 변수를 사용할 수 있습니다. libc의 임무는 userland 호출을 가져 와서 커널 incantation이 필요한 것으로 번역하고, 발송하고 결과를 수집하는 것입니다.
vonbrand

6

다음은 저수준 커널 소스 코드를 사냥하는 다양한 기술을 설명하는 몇 가지 훌륭한 블로그 게시물입니다.


12
블로그 나 포럼에 대한 링크 만 게시하지 말고 내용을 요약하여 독자가 자신의 정보를 볼 수 있도록하고 사이트가 사라지면 뭔가 남게하세요. 또한 첫 번째 링크는 libc에 관한 것입니다.이 질문에 대한 주제가 아닙니다.
Gilles
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.