이 포스팅을 읽는 분들 중에는 C프로그래밍으로 프로그램을 작성해본 적이 있는 분들이 있을 것입니다.
그리고 Kerenl Module을 작성하고 싶은 분들이 이 글을 읽고 있으시겠지요.
몇몇 분들의 C언어에서 하나의 Single Pointer가 core dumpe와 file system 을 돌아다니는 실제 활동 영역을 궁금해 하시는 분들도 있을테죠.
(core dump: memory dump, system dump 와 같은 의미의 단어로, 컴퓨터 프로그램이 특정 시점에 작업 중이던 메모리 상태를 기록 한 것이다.
보통, 프로그램이 비정상적으로 종료되었을 때 만들어진다.)
커널 모듈이란 정확히 무엇을 의미하는 걸까요?
모듈이란 커널에 로드되거나 언로드될 수 있는 코드 조각입니다.
모듈은 시스템을 리부트할 필요 없이 커널의 기능을 확장시킵니다.
예를 들어서, 디바이스 드라이버도 커널 모듈입니다.
디바이스 드라이버는 커널이 시스템에 연결된 하드웨어에 접근할 수 있도록 만들어줍니다.
모듈이 없다면 우리는 모놀리식 커널(단일 커널)을 만들어야할 것이고 직접적으로 커널에 새로운 기능을 추가해야합니다.
이렇게 된다면 매우 무거운 커널을 갖게 될 것입니다.
이 뿐만 아니라 커널에 매번 새로운 기능을 추가할 때마다, 커널을 새로 빌드하고 리부팅해야한다는 단점이 있습니다.
즉, 우리가 새로운 기능을 커널에 넣고 싶을 때마다 매번 빌드와 리부팅을 반복하는 번거로운 작업을 해야한다는 의미입니다.
현재 커널에 로드된 모듈들을 보려면 lsmod 라는 명령어를 실행하면 됩니다.
이 명령어는 /proc/modules 파일 내용을 출력하여 현재 로드된 모듈들을 보여줍니다.
그렇다면 어떻게 이러한 모듈은 커널에서 자신이 있어야할 곳을 찾는 것일까요?
커널은 자신에게 없는 새로운 기능이 필요할 때, 커널모듈데몬인 kmod이 modprobe라는 명령어를 실행하여, 필요한 모듈을 커널로 불러들입니다.
- modprobe란?
커널에 모듈을 추가, 제거하는 명령어이다.
일반적으로 시작 스크립트에서 자동으로 호출되는 모듈 로더이다.
<br/>
<br/>
- ismod와 modprobe의 차이점
ismode는 단일모듈, 지정된 모듈만 추가한다.
modprobe는 단일모듈과 의존성이 있는 모듈도 자동으로 추가한다.
사용: modprobe [options] module
ex: modprobe e1000
-> e1000 이라는 모듈을 추가한다.
옵션
-1 : 사용가능한 모든 모듈을 보여준다.
-r : rmmod 와 같다, 지정된 모듈을 제거한다.
한꺼번에 여러 모듈을 지정할 수 있으며, 의존성이 있는 모듈도 자동으로 제거한다.
-c: 기본값과 /etc/modules.cnf에 정의된 지시자를 포함한 완전한 모듈 설정을 보여준다.
옵션없이 사용할 때에는 모듈을 추가한다.
modprobe는 다음 두가지와 같은 형태로 된 문자열을 kmod에게 전달합닏..
1) softdog, ppp 와 같은 모듈 이름
2) char-major-10-30 과 같이 모듈에 대한 일반적인 식별자
만약 modprobe가 두번째와 같이 일반적인 식별자를 이용할 경우(kmod에게 전달할 경우),
제일먼저 하는 일은 이 식별자를 /etc/modprobe.conf 파일에서 찾는 것입니다.
modprobe.conf 파일은 모듈과 다음과 같은 형태로 그에 대응되는 일반적인 식별자에 대한 정보를 가지고 있습니다.
alias char-mojor-10-30 softdog
이를 통해서 char-major-10-30 이라는 일반적인 식별자가 softdog.ko라는 모듈을 의미한다는 것을 알 수 있습니다.
다음으로 modprobe는 /lib/modules/version/modules.dep파일을 살펴봅니다.
이 파일에는 모듈의 의존성에 대한 정보가 들어있어서 적재시키려는 모듈을 로드하기 전에 먼저 로드되어야하는 다른 모듈이 있는지를 확인할 수 있습니다.
modules.dep 파일은 depmod -a라는 명령을 통해서 만들 수 있습니다.
예를 들어서 msdos.ko 라는 모듈을 사용하기 위해서는 fat.ko라는 모듈이 먼저 커널에 로드되어있어야 합니다.
이와 같이 modrpobe가 적재하고자 하는 모듈이 사용하는 함수, 변수, 심볼들이 다른 모듈에 정의되어 있다면, 해당 모듈은 다른 모듈에 의존성을 가지고 있다는 뜻입니다.
마지막으로 modprobe는 insmod라는 명령어를 사용하여 원하는 모듈을 적재하기 위해 우선적으로 필요한 모듈들을 커널에 로드합니다.
modprobe는 insmod로 하여금 /lib/modules/version/을 직접 참조하게 하여 모듈을 적재합니다.
/lib/modules/version/은 모듈에 대한 standard directory 입니다.
insmod는 모듈의 위치에 대해서 잘 모르지만 modprobe가 모듈의 디폴트 위치를 알고 있습니다.
그렇기 때문에 modprobe는 모듈의 의존성을 알아내어 올바른 순서로 모듈들을 적재할 수 있습니다.
예를 들어서, msdos라는 모듈을 적재하고 싶다면 다음 명령어를 실행하면 됩니다.
insmod /lib/modules/2.6.11/kernel/fs/fat/fat.ko
insmod /lib/modules/2.6.11/kerenl/fs/msdos/msdos.ko
또는
modprobe msdos
우리가 여기서 알수 있는 것은 insmode를 사용하여 모듈을 적재하려면 로드하려는 모듈의 절대경로를 알아야 하며, insmode 명령어를 이용하여 적재하려는 모듈들을 올바른 순서대로 로드해야 합니다.
반면에, modprobe는 적재하고자 하는 모듈의 이름만 필요로 합니다. 해당 모듈이 로드되기 위해서 필요한 다른 것들은 modprobe가 lib/modules/version/module.dep를 파싱하여 알아내여 실행해줍니다.
Linux distros(리눅스 배포판들)는 modprobe, insmode, depmod를 module-init-tools라는 패키지로 제공합니다.
이전 버전에서는 이 패키지가 modutils로 불렸습니다.
일부 distros는 2.4버전 2.6버전 커널들을 올바르게 작동시키기 위해서 어떤 wrappter을 설정하여 두가지 패키지를 모두 설치되도록 합니다.
따라서 사용자들을 최신버전의 module-init-tools만 사용한다면 이 부분에 대해서 세세하게 걱정할 필요가 없습니다.
이제 여러분은 어떻게 모듈들이 커널에 로드되는지 알았습니다. 만약 여러분이 다른 모듈에 의존하는 모듈을 작성하고 싶다면 더 많은 설명이 필요합니다.
(이러한 모듈을 “stacking modules”라고 부릅니다.)
하지만 이후의 포스팅에서 다룰 것입니다. 이러한 모듈을 작성하기 전에 알아야할 것들을 먼저 다루어 보도록 하겠습니다.
우리가 세부적인 코드를 분석하기 전에 다루어야할 것들이 있습니다.
모든 사람들의 시스템은 다르고 사람들은 다다른 형태의 시슽메을 가지고 있습니다.
“hello world” 프로그램을 컴파일하고 올바르게 로드하기 위해서는 트릭이 가끔은 속임수도 필요합니다.
처음에는 조금은 어려울 수도 있는 이 과정을 해낸다면 그 이후로는 쉽게 속임수를 사용할 수 있습니다.
만약 여러분이 커널에 CONFIG_MODVERSIONS를 허용하지 않고 부팅할 경우에는, 특정한 커널을 위해 컴파일된 모듈은 여러분의 모듈에 로드되지 않을 것입니다.
제 포스팅에서 module versioning을 다루기 전에 나오는 예제들은 module verioning이 활성화되어있는 커널을 사용한다면 제대로 동작하지 않을 수 있습니다.
그러나 대부분의 내장된 Linux distro kernel들은 module versioning이 켜져있습니다.
만약 여러분이 예제 모듈들을 로딩하다가 문제를 격는다면 kernel의 modversioning을 비활성화하고 커널을 컴파일하시기 바랍니다.
이 포스팅에서 다루는 모든 예제들을 쳐보고, 컴파일하고 로드해보시는 것을 매우 추천합니다.
그리고 console에서 이 작업들을 할 것을 매우 추천합니다.
이 말은 여러분이 XWindow를 통해서 작업하지 않았으면 좋겠다는 말입니다.
모듈은 printf() 함수와 같이 스크린에 출력하지 못합니다.
대신에 정보와 경고를 로그남길 수 있으며 이것은 콘솔에서만 출력됩니다.
만약 여러분이 xterm을 통해서 한 모듈을 insmod한다면 (insmod 명령어를 이용해 로딩한다면)
이와 관련된 정보들은 모두 기록될 것인데 로그파일에만 기록될 것입니다. 따라서 로그파일을 열어보지 않는 이상 여러분들을 그 정보를 볼 수 없습니다.
이러한 정보를 빠르게 보기 위해서 모든 작업을 콘솔에서 할 것을 추천합니다.
매우 자주 리눅스 배포판들(Linux distor: Readhat Linux, Fedora, Ubunt…)들은 기준에 부합하지 않는 다양한 방법으로 패치된 커널 소스들을 배포합니다.
그렇기 때문에 이로인해서 문제가 발생할 수 있습니다.
자주 발생하는 문제들은 어떤 리눅스 배포판들은 불완전한 커널 헤더들을 배포합니다.
여러분은 이러한 불완전한 커널 헤더들을 가지고 있는 리눅스 커널들의 다양한 헤더 파일을 이용하여 여러분의 코드를 컴파일해야 합니다.
누락된 헤더들이 정확히 여러분의 모듈이 동작하기 위해 필요한 것일 때도 있습니다.
이러한 두가지 문제점을 피하기 위해서 리눅스 커널 미러 사이트에서 다운로드 받을 수 있는 최신 버전의 리눅스 커널에다가 모듈을 다운로드, 컴파일 및 부팅할 것을 추천합니다.
하지만 이 방법에서도 문제가 발생할 수 있습니다.
여러분의 시스템에 있는 gcc는 여러분이 새롭게 설치한 커널(/usr/src)이 아니라 default 위치에 있는 커널 헤더부터 찾기 때문입니다.
이 문제는 gcc의 -l switch 를 이용해서 해결할 수 있습니다.