You are on page 1of 85

Linux

Kernel newbie's manual


....................................................................................................................... 3
1. Linux..................................................................................................... 7
1.1. Linux...................................................................................7
1.1.1. Linux Unix....................... 8
1.1.2. ........................10
1.1.3. ..................................................................11
1.1.4. .............................................................................................12
1.2. ..............................................................................................................14
1.2.1. .............................................................................................. 14
1.2.2. ...............................................................................17
1.2.3. .............................................................18
1.2.4. diff patch................................................................................ 21
1.3. ............................................................................................. 22
2. Linux................................................................................ 24
2.1. ......................................................................................... 24
2.1.1. Linux.....................................................................24
2.1.2. ..................................................... 28
2.2. Linux........................................................................ 31
2.2.1. .....................................................................................31
2.2.2. .......................................................33
2.2.3. ......................................................................... 37
2.3. ......................................................................................................... 40
2.3.1. Linux.....................................................................................40
2.3.2. .......................................................... 47
2.3.3. ........................................................... 51
2.4. (VFS)..........................................................55
2.4.1. VFS...................................................................................... 55
2.4.2. .................................................................. 62
2.5. procfs................................................................................ 73
2.5.1. /proc/........................................................................................... 73
2.5.2. procfs..........................................................................................75
2.6. ............................................................................................. 80
.................................................................................................................82
....................................................................... 84


, ,
Windows Microsoft. ,
, Windows
. , 60-
XX , ,
,
. , , Unix,

. Unix
. ,
,

Minix Linux. Minix


Linux . Linux
IBM PC
.
,
,
.
Minix ,
,
.
, . [17]

. , Minix,
USENET.
,
3

, .
, . [17]
,
Linux?
:
1. .
, Unix
.
Lions' Commentary on Unix ( 1977 ),
, Unix.

. , Unix
,
,
. [17]
, ,
,
, ,
.

. [3]
2. .

. , ,
.
. ,
.
, C, Cobol
4

Fortran, ,
.
, ,
,
. [3]

Linux .
: , ,
" , ".
, ,
,
, .
,
Linux Novell.
,
,

.
,
,
.

.
:

Linux.

,
.

1. Linux
1.1. Linux
Linux
Unix, Bell Laboratories AT&T. 1969

Unix

PDP-7. 1971 Unix


PDP-11, 1973 C.
Unix, Bell Laboratories, Unix
System 6 (V6).
Unix
. ,
. 1977
Unix System III, 1982 AT&T
System V.
Unix Version 7
. ,
Unix Version 7 Minix
. Minix
, .
, Minix
.

Minix.
, Linux.
Linux
( Minix).
Linux .
7

Linux ,
: Intel, Intel IA-64, AMD x86-64, PowerPC, Compaq Alpha, SPARC
.
Linux Unix,
Unix, API Unix ( POSIX),
Unix,
(, *BSD). , ,
Linux , ,
Unix.
Linux, Linux,

GPL. , Linux
GNU/Linux,
, GNU (GNU's Not Unix
). Linux,
, . [10, 17]
1.1.1. Linux Unix
API,
Unix .
.
,
. Unix
(MMU, Memory Management Unit);

. Linux
- Unix, ,
. Linux
Unix: [10]
8

. Linux

.
0.99 -. [8]
.

Linux
(SMP). Unix SMP,
.

Linux .
, .
Unix Solaris,
IRIX, Unix.

Linux :
.
, .

Linux Unix,
(, STREAMS).

Linux GNU C.
C ISO C99,
(
static inline), (
asm()), ( likely() unlikely()
;
) . [14]

Linux . , GNU/Linux
()
, () ,
. , , Red Hat
, Slackware
9

. [18]
Linux 2.6.18.
1.1.2.

. : [10]

C.
.
.
, , . ,
lib/string.c.

.
,
.
, .
: ,
.


, .

. ,
.
,
( )
static. [16] ,
.

10

. ,
8 32- 16 64 -.

. - , C,

.

1.1.3.
,
1.1. :
COPYING

MAINTAINERS

CREDITS

, Makefile .
1.1 Linux 2.6.18

arch

block

crypto

API

Documentation

drivers

fs

VFS

include

init

ipc

kernel

( .)

lib

mm

net

scripts

security

Linux

11

sound

usr

1.1.4.
, Linux ,
.
.
, .
.
.

.
( "Hello, world").
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
void sayHello()
{
printk(KERN_INFO"Hello, world\n");
}
EXPORT_SYMBOL(sayHello);
static int __init hello_init(void)
{
sayHello();
return 0;
}
static void __exit hello_exit(void)
{
12

printk(KERN_INFO"Goodbye, world\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
, static int __init.
.
, static void __exit.
printk()
( 2.6.18 8
, include/linux/kernel.h).
, /var/log/messages.
, ,
, .
linux/module.h.
linux/kernel.h printk(),
KERN_INFO. linux/init.h
__init __exit.
C EXPORT_SYMBOL()
. ,
. EXPORT_SYMBOL_GPL()
, ,
GPL. sayHello()
. MODULE_LICENSE()
, .

GPL (,
). [2, 10]

13

1.2.
1.2.1.

Linux 2.6.18.
1
Linux.

make.
linux-2.6.18.tar.bz2,
( /usr/src/)
tar (,
):
tar -C /usr/src/ -xjvf linux-2.6.18.tar.bz2
/usr/src/linux-2.6.18/:
cd /usr/src/linux-2.6.18/
make defconfig " "
. ,

make menuconfig.
make README.
, ,
IDE "Device
Drivers -> ATA/ATAPI/MFM/RLL support -> PCI IDE chipset support" (
make defconfig VIA82CXXX). "File systems"
(
ext2).
14

make. ,
make -j2. -j2
( ).
, make modules_install
/lib/modules/2.6.18/kernel/.
make -j2
make modules_install
arch/i386/boot/bzImage.
System.map , ,
. [11]
/boot/:
cp ./arch/i386/boot/bzImage /boot/vmlinuz-2.6.18
cp ./System.map /boot/System.map-2.6.18
(,
, ), ram-
. ram-
-, chroot
(, RAID).
[11] ram- mkinitrd.
mkinitrd .
Fedora Core, Mandriva:
mkinitrd /boot/initrd-2.6.18 2.6.18
openSUSE ( System.map):
mkinitrd -k /boot/vmlinuz-2.6.18 -M /boot/System.map-2.6.18 -i /boot/initrd2.6.18

man mkinitrd.
( LILO
GRUB) .
15

,
.
2.6.x.
2.4.x make. 2.4.x
2.6.x, .

Slackware

Linux,

.
( )
QEMU VMware.
: (/dev/hda1),
(/dev/hda2), ext2 (
). QEMU
( VMware) IDE: "Device Drivers
-> ATA/ATAPI/MFM/RLL support -> PCI IDE chipset support -> Intel PIIXn
chipset support".
20 .
, " ", ram
, .

mcedit .
Slackware Linux LILO.
16

LILO /etc/lilo.conf. mcedit /etc/lilo.conf


. :
image = /boot/vmlinuz-2.6.18
root = /dev/hda2
label = linux-2.6.18
read-only
vga,
normal.
framebuffer.
framebuffer , vga
.
vga = normal
LILO /sbin/lilo.
1.2.2.
2
hello.

make.
Makefile. ,

hello.c. Makefile :
obj-m += hello.o
Makefile hello.c .
:
make -C /usr/src/linux-2.6.18 SUBDIRS=$PWD modules

( /usr/src/). -C make,
17

-
(
). make ,
hello.ko.
insmod < > (
insmod hello.ko).
/proc/modules. rmmod
< > (rmmod hello.ko).
.

,
sayHello().
1.2.3.
3
hello.

Linux
"kbuild". , ,
"Kernel hacking".
Kconfig*.
arch/i386/Kconfig.debug :
config MYKERNEL
bool "My kernel modules"
default y
help
This is my kernel modules
18

if MYKERNEL
config MYKERNEL_SAYHELLO
bool "sayHello() function"
default y
help
Simple function sayHello() that say "Hello, world".
endif
"Kernel hacking"
CONFIG_MYKERNEL ( Kconfig* CONFIG_).
, ,
if MYKERNEL. .config.
bool , : Y/N.
tristate , : Y/N/M.
default .
:

Y .
, , ,
,
.

M
.

N .

, ,
.
( hello.c) c Makefile kernel/hello/
. kernel/Makefile :
obj-$(CONFIG_MYKERNEL_SAYHELLO) += hello/
hello Y M,

CONFIG_MYKERNEL_SAYHELLO,
19

Y M . , M,
hello.ko make modules_install
/lib/modules/2.6.18/kernel/. ,
Makefile kernel/,
kernel/hello/ :
/lib/modules/2.6.18/kerne/kernel/hello/hello.ko

. , Fedora Core 6,
Linux 2.6.18, 2.6.18-1.2798.fc6

EXTRAVERSION Makefile . , Fedora Core 6:


EXTRAVERSION = -1.2798.fc6
EXTRAVERSION,
. :
EXTRAVERSION = mykernel

.
CONFIG_HELLO tristate.
:
tristate "sayHello() function"
default m

arch/i386/Kconfig.debug.

, kernel/hello/Kconfig
. arch/i386/Kconfig.debug
:
source "kernel/hello/Kconfig"

20

Kconfig*

.
Makefile',
Makefile.
EXTRAVERSION,
, uname -r ( ) 2.6.18-mykernel.
1.2.4. diff patch
(patch).
diff ,
patch. ,
: ,
. , /usr/src/.
diff :
diff -ruN linux-2.6.18/ linux-2.6.18-2/ > mykernel.patch
-r ,
.

-u

diff.

. -N , ,
, .
diff :
diff -u linux-2.6.18/file linux-2.6.18-2/file > file.patch
diff ,
. . ,
, patch
(
/usr/src/linux-2.6.18/):
patch -p1 < /usr/src/mykernel.patch

21

/usr/src/. -p1 ,
,
.
, ,
.
diffstat ,
( ).
:
diffstat -p1 /usr/src/mykernel.patch
(Linux Kernel
Mailing List, lkml). patch ,
diff, .
,
,

mykernel.patch

, , "Kernel
hacking". ,
, i386, Alpha SPARC.

i386.

"Processor type
and features -> Processor family -> 386" "Processor type and features ->
Subarchitecture type -> PC-compatible".

1.3.
1

Linux

Unix- .
1.1 ,
,
.
22

1.2

, ,
.

23

2. Linux
2.1.
2.1.1. Linux
, ,
,
, . ,

.
.
,

.

(Application Programming Interface, API).
,
, . POSIX,
WinAPI API. API
, .
, Linux FreeBSD
POSIX (Linux 100% POSIX 1003.1 [9]),
, FreeBSD,
Linux .
.
C.
, printf()

24

write(),
( ).

printf()

printf()
C

write()
C


write()

. 2.1. , C
printf()
C
API- POSIX. strace
,
( ). [10]

( Linux syscall)
long.
.
errno.
errno
perror(), , ,

.
getuid() ( kernel/timer.c),
uid :
asmlinkage long sys_getuid(void)
{
return current->uid;
}

25

asmlinkage ,
.
long. getuid() sys_getuid().
, Linux.
Linux
(syscall number).
, .

. Linux
2.6.18 318 i386 (
NR_syscalls).
include/asm/unistd.h.
include/asm-i386/unistd.h

asm-< > asm


( include/asm
include/asm-i386/).

asm/

asm-i386/.
Linux " " ("not implemented")
sys_ni_syscall(), , ,
, -ENOSYS ,
.
.

(syscall table). ,
sys_call_table. i386
( )
arch/i386/kernel/syscall_table.S. [10]

26


,
, .
:
(exception),
.
(system call heandler)
system_call()

arch/i386/kernel/entry.S).

,
. i386
eax. eax
. system_call()
NR_syscalls.
NR_syscalls, -ENOSYS,
:
call *sys_call_table(,%eax,4)

.
. i386 ebx, ecx,
edx, esi, edi .
,
, .
.
i386 eax. [10]

27

2.1.2.
1
.
.

THREAD_SIZE,
include/asm/thread_info.h. .
#include <asm/thread_info.h>
asmlinkage long sys_getstsize(void)
{
return THREAD_SIZE;
}
.
.
arch/i386/kernel/new_calls.c. ,
. ,
new_calls.c ,
arch/i386/kernel/Makefile
obj-y += new_calls.o

arch/i386/kernel/syscall_table.S. ,
( ,
i386). .
.long sys_tee

/* 315 */
28

.long sys_vmsplice
.long sys_move_pages
.long sys_ getstsize

unistd.h

include/asm/unistd.h).
#define __NR_tee

315

#define __NR_vmsplice

316

#define __NR_move_pages

317

#define __NR_ getstsize

318

NR_syscalls (
1).
#define NR_syscalls 319
.

C.
Linux syscall(),
. syscall()
,
. syscall() 4.0BSD
( man 2 syscall).
sys/syscall.h.
#include <sys/syscall.h>
, open(),
.
29

long open(const char *filename, int flags, int mode)


syscall() .
#define __NR_open 5
syscall(__NR_open, filename, flags, mode)
__NR_open ,
include/asm/unistd.h.
2
. ,
.

C:
#include <sys/syscall.h>
#include <stdio.h>
#define __NR_getstsize 318
int main()
{
long stsize;
stsize = syscall(__NR_getstsize);
printf("Kernel stack size = %ld bytes\n", stsize);
return 0;
}
stsize long
getstsize() .
30

, , ,
.
# gcc getstsize.c -o getstsize; ./getstsize
Kernel stack size = 8192 bytes
getstsize.c .
new_calls.c .

Linux (, gcc).
[6, 13].

mcedit

mc).

2.2. Linux
2.2.1.

. ,
, (MMU)
. MMU
.
. 32-
4 , 64- 8 .
, 32- 1
262.144 .

31

page
page,
include/linux/mm.h. , page
, . ,
, ,
. 40 .
1 262.144 * 40 = 10.485.760 ,
10 . [10]

-
.
.
.
.
, :

(DMA,
Direct Memory Access) .


, .
.

ZONE_DMA. , DMA.

ZONE_NORMAL.

ZONE_HIGHMEM. " ", ,


.

. i386
ZONE_DMA 16 , ZONE_HIGHMEM ,
32

896 , ZONE_NORMAL (16-896 ).


ZONE_HIGHMEM " " (high memory),
" "(low memory).
,
. include/linux/mmzone.h
zone. (unsigned
long free_pages), (char *name, : "DMA", "Normal",
"HighMem") . [10]
2.2.2.
kmalloc() kfree()
kmalloc() ( include/linux/slab.h) malloc()
flags.
kmalloc() .
.
void *kmalloc(size_t size, gfp_t flags)
size
. NULL.
kfree() ( include/linux/slab.h)
, kmalloc() ( kfree() ,
kmalloc()).
void kfree(const void *);

kfree(NULL)

. :
struct some * p;
p = kmalloc(sizeof(some), GFP_KERNEL);
if (!p)
/* */
33

else {
/*- */
kfree(p);
}
vmalloc() vfree()
vmalloc() include/linux/vmalloc.h.
size .
NULL.
void *vmalloc(unsigned long size)
kmalloc(), ,
, .
vmalloc() kmalloc(),
, vmalloc(),
. TLB (.
" "). vmalloc()
. ,
vmalloc().

vmalloc(),

vfree() ( include/linux/vmalloc.h):
void vfree(void *addr)
, addr,
vmalloc(). .
gfp_mask

:

. ,
.
34

. , .

. .

include/linux/gfp.h.
2.1

__GFP_WAIT

__GFP_HIGH

__GFP_IO

__GFP_FS

__GFP_COLD

,
(cache cold)

__GFP_NOWARN

__GFP_REPEAT

__GFP_NOFAIL


__GFP_NORETRY

__GFP_COMP

(compound)
.

__GFP_ZERO

, ,

2.2

__GFP_DMA

ZONE_DMA

__GFP_HIGHMEM

ZONE_HIGHMEM

ZONE_NORMAL
2.3
35

GFP_ATOMIC

GFP_NOIO

,
/

GFP_NOFS


/,
,

GFP_KERNEL

.
,
GFP_USER

.

GFP_HIGHUSER ZONE_HIGHMEM,

GFP_DMA
ZONE_DMA
2.4

GFP_ATOMIC

__GFP_HIGH

GFP_NOIO

__GFP_WAIT

GFP_NOFS

__GFP_WAIT | __GFP_IO

GFP_KERNEL

__GFP_WAIT | __GFP_IO | __GFP_FS

GFP_USER

__GFP_WAIT

__GFP_IO

__GFP_FS

__GFP_IO

__GFP_FS

__GFP_HARDWALL
GFP_HIGHUSER __GFP_WAIT

__GFP_HARDWALL | __GFP_HIGHMEM
GFP_DMA

__GFP_DMA

36


GFP_KERNEL. .
GFP_KERNEL swap.
GFP_NOIO
/. GFP_NOFS /,
.
/.
GFP_DMA ,
ZONE_DMA. . [10]
2.2.3.
1
upper(),
, ,
.

: ,
, ,
, .
asmlinkage long sys_upper(char *src, char *dst, int len)
{
int i;
char *buff;
buff = (char *)kmalloc(len, GFP_KERNEL);
memset(buff, 0, len);
copy_from_user(buff, src, len);
for (i = 0; i < len; i++)
37

if((buff[i] >= 0x61) && (buff[i] <= 0x7A)) buff[i] -= 0x20;


copy_to_user(dst, buff, len);
kfree(buff);
return len;
}

kmalloc().
GFP_KERNEL. memset() len
0, , buff.
copy_from_user()
.

( ).
, 97
122 (0x61 0x7A ):
.
( )
copy_to_user().
(
), ( )
.
copy_from_user copy_to_user()
include/asm-i386/uacces.h.
( "asm").
.
#include <asm/uacces.h>

kfree().

38

arch/i386/kernel/new_calls.c.
2.1 " ".
2
,

upper() .

C:
#include <sys/syscall.h>
#include <stdio.h>
#define __NR_upper 319
int main(int argc, char *argv[])
{
char *s1, *s2;
int len, ret;
if (argc > 1)
s1 = argv[1];
else
s1 = "This Is (1234) Default TEST String";
len = strlen(s1);
s2 = (char *)malloc(len);
memset(s2, 0, len);
printf("Input string: %s\n", s1);
ret = syscall(__NR_upper, s1, s2, len);
printf("Output string: %s\n", s2);
return 0;
39

}
s1.
( argc 1),
s1 ,
, , ("This
Is (1234) Default TEST String").
s1 s2,
upper().
# gcc upper.c -o upper; ./upper
Input string: This Is (1234) Default TEST String
Output string: THIS IS (1234) DEFAULT TEST STRING
# ./upper HeLlo
Input string: HeLlo
Output string: HELLO
upper.c .
new_calls.c .

3 " ".
upper()
. .

2.3.
2.3.1. Linux
Linux :
.
.
(task). (kernel thread)

40

, .
. ,
, ,
.

:
. ,
,
. ,
. Linux
,
.
.
Linux ( Unix )
fork() ( ),
.
, fork(), (,
parent), (, child).
fork() ,
.
- .
exec*()
.
exit(),
. ,
,
.

, (task list).
41

task_struct,

include/linux/sched.h,

. 1,7
32- , .
pid,
.
Linux Unix 32768 (
/proc/sys/kernel/pid_max).
Linux .
init (pid = 1).

(sibling).

task_struct

( struct task_struct *parent)


children ( struct list_head children).
current.
getpid() pid :
asmlinkage long sys_getpid(void)
{
return current->tgid;
}
tgid ( )?
tgid pid.
Linux ,
.
tgid .

.

(executable) .
,
42

, . ,

. current .

.
state task_struct .
:

TASK_RUNNING (runnable).
,
.

TASK_INTERRUPTIBLE

, sleeping).
. ,
TASK_RUNNING.
.

TASK_UNINTERRUPTIBLE

TASK_INTERRUPTIBLE,

.
,
.
, TASK_INTERRUPTIBLE.

TASK_ZOMBIE ,
,

, wait4().

TASK_STOPPED .
, . ,
SIGSTOP, SIGTSTP, SIGTTOU,
, .

43

.
__set_task_state(). i386
include/linux/sched.h:
#define __set_task_state(tsk, state_value)

do { (tsk)->state = (state_value); } while (0)


/* tsk state_value*/


(spawn). ,
,
. Unix ( Linux) :
fork() exec().
fork()
.
. Linux fork()
(copy-on-write) .

. ,
, ,
. read-only.
fork() i386
arch/i386/kernel/process.c. Linux do_fork()
( do_fork() kernel/fork.c).
asmlinkage int sys_fork(struct pt_regs regs)
{
return do_fork(SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
}

44

do_fork() Linux Minix,


do_fork(). do_fork()
copy_process() ( kernel/fork.c)
. copy_process() :

dup_task_struct().

.


.
tgid.

,
, .

.
do_fork(). copy_process()
, .
, do_fork,
.
2.5.
2.5 do_fork()

CLONE_FILES


CLONE_FS


CLONE_IDLETASK

PID (
(idle) )

CLONE_NEWNS

(. 2.4.1)
45

CLONE_PARENT


CLONE_PTRACE


( )

CLONE_SIGHAND

CLONE_THREAD

CLONE_UNTRACED

CLONE_PTRACE

CLONE_STOP

TASK_STOPPED
CLONE_VM


,
, kernel_thread() (
arch/i386/process.c):
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
fn, arg.
do_fork() flags:
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0,
NULL, NULL);
:
, ,
.

46


.
, exit() ( C
main()).
: ,
, . ,
do_exit() (
kernel/exit.c).
do_exit() .
. release_task()
. ,
, ""
( ) init.
init
. [10]
2.3.2.
,
.
.

.
"Segmentation Fault" ( Windows
"Access violation at adress[0000:0000]").
: [10, 16]

. , ,
(text section).

47

.
, ,
(data section).

).
, ,
BSS (bss section).

(heap). , ,
malloc() .
, .

. 1.1.

.


, .

mm_struct,
include/linux/sched.h, .
mm_struct
mmlist. init_mm init.
mmlist_nr.
mm
task_struct.
copy_mm().
CLONE_VM (
), .

:
48

oldmm = current->mm; /* */
if (clone_flags & CLONE_VM) { /* CLONE_VM*/
atomic_inc(&oldmm->mm_users); /* 1*/
mm = oldmm; /* */
goto good_mm;
}
good_mm:
tsk->mm = mm; /* */
, mmput(),
mm_users .
mm_users , mmdrop(),
mm_count. mm_count
, free_mm(),
.


( mm NULL),
.
, ,
.
, ,
NULL,
.
,
, . ,

.

49

:
; () .
,
.
Linux
( ,
):
1. (page
global directory, PGD). pgd_t
( unsigned long). PGD
, PMD.
2. () (page middle direcory)
pmd_t. PMD
PTE.
3.
(page table entry) pte_t.
.
(
). pgd
.

( ).
,
.

50

(translation

lookaside

buffer,

TLB),

.
TLB.
,
. [10]

mm_struct
( pgd)

pgt_t

pmd_t

pte_t

pgt_t

pmd_t

pte_t

pgt_t

pmd_t

pte_t

pgt_t

pmd_t

pte_t

pgt_t

pmd_t

pte_t

pgt_t

pmd_t

pte_t

pgt_t

pmd_t

pte_t

pgt_t

pmd_t

pte_t

pgt_t

pmd_t

pte_t

pgt_t

pmd_t

pte_t

page

. 2.2. .
2.3.3.

,
: PID, UID, .
.
PID
, .
, PID
( init, Linux ).

mm_struct
active_mm .
51

mmap mm_struct. mmap struct vm_area_struct.

task_struct

mm_struct

include/linux/sched.h. vm_area_struct
include/linux/mm.h:
#include <linux/sched.h>
#include <linux/mm.h>
init (
Linux ).
, pid_t. pid_t
include/linux/types.h.
#include <linux/types.h>
static int nr = 1;
int. ,
. ,
: byte, short, ushort, int, uint, long, ulong, charp (),
bool, invbool.
module_param(nr,

int,

0000)

(,

MODULE_PARM_DESC(nr, "Process ID") (, ).


include/linux/moduleparam.h.
module_param(nr, int, 0000);
MODULE_PARM_DESC(nr, "Process ID");
( , ,
), .
init.
task_struct,
, . find_task_by_pid()
52

pid.
pid_t.
struct task_struct *task;
task = find_task_by_pid((pid_t)nr);

task. , PID ,
pid state :
printk(KERN_INFO "taskinfo: Process %d information:\n", task->pid);
printk(KERN_INFO "taskinfo: STATE %u\n", (u32)task->state);

active_mm unsigned long.
start_code end_code , start_data end_data
, start_brk brk "".
(_ _). mm_struct
active_mm.
struct mm_struct *a_mm;
a_mm = task->active_mm;

a_mm. , ,
:
printk(KERN_INFO "taskinfo: START CODE SEGMENT ADDRESS
0x%08X\n", (u32)a_mm->start_code);
printk(KERN_INFO "taskinfo:

END CODE SEGMENT ADDRESS

0x%08X\n", (u32)a_mm->end_code);
printk(KERN_INFO "taskinfo: CODE SEGMENT LENGTH 0x%08X\n",
(u32)(a_mm->end_code a_mm->start_code));
53

mmap
active_mm unsigned long. vm_start vm_end.
struct vm_area_struct
. mmap (task>active_mm->mmap).
struct vm_area_struct *vma;
vma = task->active_mm->mmap;
vm_start vm_end
vma.
printk(KERN_INFO "taskinfo: START MEMORY AREA ADDRESS
0x%08X\n", (u32)vma->vm_start);
printk(KERN_INFO "taskinfo:

END MEMORY AREA ADDRESS

0x%08X\n", (u32)vma->vm_end);
, , ,
(vm_end vm_start):
printk(KERN_INFO "taskinfo: MEMORY AREA LENGTH 0x%08X\n",
(u32)(vma->vm_end vma->vm_start));
,
nr.
nr, .
insmod taskinfo.ko nr=<pid>
/var/log/messages.
, ,
:
cat /var/log/messages | grep taskinfo: | tail -n 21

54

21 ,
"taskinfo:". taskinfo.c .

,
init ( ).
. ,
, Linux,
.

2.4. (VFS)
2.4.1. VFS

(Virtual File System),
(Virtual File Switch)
, .
VFS,
.
VFS , open(), read()
write(),
. ,
,
: VFS ,

. Unix.

, .

55

,
" ", " " .
. ,
.
, write(f, &buf,
len) len buf , f.
sys_write() (
fs/read_write.c),
, , f.
sys_write() VFS vfs_write()
( fs/read_write.c),
, (file->f_op->write()).
2.3.
write()

sys_write()

vfs_write()

f_op->write()

VFS

2.3. write().
VFS
VFS
. ,
:
, .
VFS:

(superblock),
.

(inode), .

(dentry),
.
56

. dentry ,
. dentry ,
dentry.

(file), ,
.

VFS

, :

super_operations ( ).
include/linux/fs.h. ,
.

inode_operations ( ).
include/linux/fs.h. ,
.

dentry_operations ( ).
include/linux/dcache.h. ,
.

file_operations ( ).
include/linux/fs.h. ,
.

,
,

VFS.

, ,

.
superblock

57

" " (,
procfs) .
super_block,
include/linux/fs.h.
alloc_super() .
s_op ,
super_operations. s_op
, . , ,
,
.
sb->s_op->write_super(sb);
sb . write_super()
, ,
. .
C++ :
sb.write_super();
Linux C,

.
inode
inode ,
( Unix ).
Unix inode VFS
. (FAT, HPFS),
.
inode inode,
include/linux/fs.h. ,
,
58

.
,
(NULL). i_op .
dentry
Unix. , ls
: /bin/ls. bin, ls , bin
, .
. VFS
, : ,
, .
VFS
(directory entry dentry). dentry . /,
bin, ls .
VFS dentry " ".
dentry dentry,
include/linux/dcache.h. dentry
d_op. dentry
.
,
dentry . dentry
dcache (Dentry Cache) :

dentry,
( i_dentry inode).

dentry.
:
. ,
( ).

59

- ( dentry_hashtable) - ( d_hash
dentry_operations),
dentry.

(used). d_inode inode,


VFS ( d_count
0). .

(unused). d_inode inode,


VFS ( d_count
0). , "
".

(negative). d_inode inode (


, ).
, .

file
,
. open()
close().
file,
.
file, include/linux/fs.h. file
.
dentry,
inode, .
file f_op.

60

VFS

file_system_type, include/linux/fs.h.
.
vfsmount.
,
, include/linux/mount.h.
, ,
.
,
, : fs_struct, files_struct
namespace.

fs_struct

include/linux/fs_struct.h.

.
files_struct include/linux/file.h.
.
fd fdtable (
include/linux/file.h).
namespace ,
(
). include/linux/namespace.h.
,
, list.
, CLONE_FILES

CLONE_FS

(, ), files_struct
fs_struct.
. CLONE_NEWNS,

61

.
. [10]
2.4.2.

, .
, .
/linfs/.

, ,

VFS .

LinFS. :
1.
inode.
2.
, .
3.
.
4. .
5. .
inode
inode
. linfs_make_inode().
static struct inode *linfs_make_inode(struct super_block *sb, int mode)

62


inode inode.
inode new_inode().
struct inode *ret = new_inode(sb);
(if (ret))
inode:
ret->i_mode = mode;
ret->i_uid = ret->i_gid = 0;
ret->i_blksize = PAGE_CACHE_SIZE;
ret->i_blocks = 0;
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
i_mode inode.
. i_uid i_gid User ID
Group ID inode .
. i_blksize ()
.

PAGE_CACHE_SIZE,

include/linux/pagemap.h PAGE_SIZE,
include/asm/page.h 4096 (). i_blocks
. ,
. i_atime, i_mtime, i_ctime
,
.
, .

63


.
register_filesystem().
file_system_type.
static struct file_system_type linfs_type = {
.owner

= THIS_MODULE,

.name

= "linfs",

.get_sb

= linfs_get_super,

.kill_sb

= kill_litter_super,

};

ISO

C99.

. :
static struct super_operations linfs_sops = {
owner:

THIS_MODULE,

name:

"linfs",

get_sb:

linfs_get_super,

kill_sb:

kill_litter_super,

};
ISO C99.
name : ext2, vfat, ntfs ,
name . get_sb ,

linfs_get_super() get_sb_single().
static struct super_block *linfs_get_super

64

(struct file_system_type *fst, int flags, char *devname, void *data, struct
vfsmount *mnt)
{
return get_sb_single(fst, flags, data, linfs_fill_super, mnt);
}
get_sb_single() fs/super.c.
int get_sb_single(struct file_system_type *fs_type, int flags, void *data,
int (*fill_super)(struct super_block *, void *, int), struct vfsmount *mnt)

fs_type. ,
fill_super().
linfs_fill_super().
static int linfs_fill_super(struct super_block *sb, void *data, int silent)
.
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = LFS_MAGIC;
sb->s_op = &linfs_sops;
s_blocksize s_blocksize_bits ()
. s_op
( ). s_magic " "
. 0x19980122.
#define LFS_MAGIC 0x19980122
.
struct inode *root;
65

struct dentry *root_dentry;


root = linfs_make_inode (sb, S_IFDIR | 0755);
root->i_op = &simple_dir_inode_operations;
root->i_fop = &simple_dir_operations;

inode linfs_make_inode(). i_op i_fop
inode
. simple_dir_inode_operations simple_dir_operations
fs/libfs.c.
dentry " ", ""
.
root_dentry = d_alloc_root(root);
sb->s_root = root_dentry;
linfs_create_files(sb, root_dentry);
s_root dentry,
.

linfs_create_files().


dentry.

linfs_create_files() counter.
atomic_set(&counter, 0);
linfs_create_file(sb, root, "counter", &counter);

atomic_set()

counter

66

atomic_t

()

0.

linfs_create_file() ,
dentry (), ,
dentry .
static struct dentry *linfs_create_file
(struct super_block *sb, struct dentry *dir, const char *name, atomic_t
*counter)
linfs_create_file() dentry.
struct qstr qname;
qname.name = name;
qname.len = strlen(name);
qname.hash = full_name_hash(name, qname.len);
qstr dentry,
include/linux/fs.h.
: len ( ) -.
full_name_hash() include/linux/dcache.h.
inode dentry .
dentry = d_alloc(dir, &qname);
inode = linfs_make_inode(sb, S_IFREG | 0644);
inode->i_fop = &linfs_fops;
inode->u.generic_ip = counter;
d_add(dentry, inode);
d_alloc() dentry.
d_alloc() fs/dcache.c.
dentry.
inode. u.generic_ip
67

. .
d_add() .
dentry inode. dentry
-, inode "" (attach)
dentry. include/linux/dentry.h.
counter linfs_create_files()
subdir subcounter.
atomic_set(&subcounter, 0);
subdir = linfs_create_dir(sb, root, "subdir");
linfs_create_dir() .
,
dentry, .
linfs_create_file(), Unix
.
inode.
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
i_op i_fop simple_dir_inode_operations
simple_dir_operations. (if (subdir)),
subcounter.
linfs_create_file(sb, subdir, "subcounter", &subcounter);
.
.

68



super_operations "" .
static struct super_operations linfs_sops = {
.statfs

= simple_statfs,

.drop_inode

= generic_delete_inode,

};
statfs , VFS

simple_statfs(),

fs/libfs.c. drop_inode ,
VFS,
inode. generic_delete_inode(),
fs/inode.c.


file_operations. file_operations (
open), ( read) ( write).
static struct file_operations linfs_fops = {
.open= linfs_open,
.read = linfs_read_file,
.write = linfs_write_file,
};

. linfs_open() .
static int linfs_open(struct inode *inode, struct file *filp)
69

{
filp->private_data = inode->u.generic_ip;
return 0;
}
inode,
file filp. private_data file
.
u.generic_ip,
linfs_create_file().
, .
linfs_read_file() .
static ssize_t linfs_read_file
(struct file *filp, char *buf, size_t count, loff_t *offset)
file,
, buf,
count ( )
offset.
counter
v atomic_read().
Int v;
v = atomic_read(counter);
, (
offset ). counter
atomic_inc(). v
.
if (*offset == 0)
70

atomic_inc(counter);
else
v -= 1;
tmp TMPSIZE
. len.
#define TMPSIZE 20
char tmp[TMPSIZE];
int len;
int len = snprintf(tmp, TMPSIZE, "%d\n", v);

0.
if (*offset > len)
return 0;
, (count >
len *offset), count ,
(len *offset). (*offset > len).
if (count > len *offset)
count = len *offset;

tmp, .
,
.
copy_to_user(buf, tmp + *offset, count)
, count.
*offset += count;
71

linfs_write_file() .
static ssize_t linfs_write_file
(struct file *filp, const char *buf, size_t count, loff_t *offset)
filp file,
buf, count offset.

. (),
.
if (*offset != 0)
return -EINVAL;

TMPSIZE, . ,
memset().
if (count >= TMPSIZE)
return -EINVAL;
memset(tmp, 0, TMPSIZE);
.
.
if (copy_from_user(tmp, buf, count))
return -EFAULT;
,
counter.
atomic_set(counter, simple_strtol(tmp, NULL, 10));
simple_stroll() lib/sprintf.c.
tmp unsigned long long
72

10.
NULL.

unregister_filesystem().
unregister_filesystem(&linfs_type);
linfs.c .

.
? -
, mount
none.
# mount -t linfs none /linfs/


.
.

2.5. procfs
2.5.1. /proc/
procfs Unix-
,
. procfs
/proc/. - /proc/,
.
.
73

/proc/,

.
procfs
. /proc/
.
( 0).
, procfs
( ). , ,
, pid .
/proc/self/ . [4, 14]
/proc/sys/
/proc/sys/ 1.3.57
, .
:

debug/. C .

dev/. C , (
dev/cdrom/info). .

fs/. .

kernel/. . ,
, , , .

net/.
.

sunrpc/. Sun
(NFS). .

vm/. ,
.
74

/proc/
man proc. [5]
2.5.2. procfs

, /proc/
mykernel_test/ :

jiffies
.

jiffies2 jiffies.

seconds ,
.

foo .

success "Congratulations! Your Linux experiment


successed".



procfs. include/linux/proc_fs.h.
procfs
fs/proc/.
, procfs, :
static struct proc_dir_entry
*example_dir,

*jiffies_file,

*symlink,

*success_file;

75

*seconds_file,

*foo_file,

proc_mkdir().

, /proc/mykernel_test:
#define MYKERNEL_ENTRY "mykernel_test"
example_dir = proc_mkdir(MYKERNEL_ENTRY, NULL);
, ,
create_proc_read_entry(). , jiffies
/proc/mykernel_test/ 0444:
jiffies_file =
create_proc_read_entry("jiffies",

0444,

example_dir,

proc_read_jiffies, NULL);
proc_read_jiffies():
static int proc_read_jiffies
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len;
len = sprintf(page, "Your processor timer ticked %lu times\n", jiffies);
return len;
}
,
page.
( jiffies).
proc_read_seconds() ,
jiffies/HZ. HZ
. jiffies / HZ ,
.
76

proc_symlink().
,

/proc/mykernel_test/jiffies2 /proc/test/jiffies:
symlink = proc_symlink("jiffies2", example_dir, "jiffies");
,
, .
, ,
create_proc_entry(). , /proc/mykernel_test/foo
0644:
foo_file = create_proc_entry("foo", 0644, example_dir);
,
.
,
foo.
#define FOO_LEN 16
struct fb_data_t {
char value[FOO_LEN + 1];
};
strcpy(foo_data.value, "foo\n");
foo_file->data = &foo_data;
proc_read_foo(),
proc_write_foo():
foo_file->read_proc = proc_read_foo;
foo_file->write_proc = proc_write_foo;

77

proc_read_foo() proc_read_jiffies(),
, char *page, value
foo_data_t.
static int proc_read_foo
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len;
struct fb_data_t *fb_data = (struct fb_data_t *)data;
len = sprintf(page, "Last message: %s", fb_data->value);
return len;
}
proc_write_foo()
copy_from_user().
static int proc_write_foo
(struct file *file, const char *buffer, unsigned long count, void *data)
{
int len;
struct fb_data_t *fb_data = (struct fb_data_t *)data;
if(count > FOO_LEN)
len = FOO_LEN;
else
len = count;
if(copy_from_user(fb_data->value, buffer, len))
return -EFAULT;
78

fb_data->value[len] = '\0';
return len;
}
owner:
example_dir->owner = THIS_MODULE;
jiffies_file->owner = THIS_MODULE;
symlink->owner = THIS_MODULE;
foo_file->owner = THIS_MODULE;
/proc/test/jiffies
/proc/mykernel_test/jiffies2
:
# cat /proc/mykernel_test/jiffies
Your processor timer ticked 35938 times
/proc/test/foo
"foo", :
# cat /proc/mykernel_test/foo
Last message: foo
# echo "hello" > /proc/mykernel_test/foo
# cat /proc/mykernel_test/foo
Last message: hello

remove_proc_entry().
remove_proc_entry("success", example_dir);
remove_proc_entry("foo", example_dir);
79

remove_proc_entry("seconds", example_dir);
remove_proc_entry("jiffies2", example_dir);
remove_proc_entry("jiffies", example_dir);
remove_proc_entry(MYKERNEL_ENTRY, NULL);
procfiles.c .

2.6.
2 Linux.
2.1 Linux,

API. ,
,

.
2.2

.
,
.
2.3 Linux
,
. ,
: ,
.
Linux 50 . 2.4
,

80

. VFS
.
, ,
.
2.5 /proc/
procfs.
/proc/sys/.
, procfs.

81


,
, , ,

Linux

,
.
:

. ,
Linux
.

.
.

taskinfo
Linux.

:

/.

(SMP).

. .

. kobject
sysfs.

Linux API.

.
82


, .
: " ,
.
".

83


1. Corbet, J. Creating Linux virtual filesystems [ ] / J.
Corbet. Linux Weekly News. http://lwn.net/Articles/13325/ (22 . 2002).
2. Salzman, P. J. The Linux Kernel Module Programming Guide [
] / P. J. Salzman, Burian M., Pomerantz O. The Linux Documentation
Project. http://tldp.org/LDP/lkmpg/2.6/html/index.html. (31 . 2005).
3. , . [ ] /
. . CITKIT. http://citkit.ru/articles/18/. (17 . 2005).
4. , . [] / . // . 2005
. 9. . 104-106.
5. , . Linux [] / . // . 2005 .
10. . 102-104.
6. , . Linux [ ] / .
. . http://linuxcenter.ru/lib/books/zlp/ (4 . 2006).
7. , . [] / . //
. 2003 . 10. . 30-37.
8. , . . Linux [
]

http://www.linuxcenter.ru/lib/history/lh-00.phtml. ( 2005).
9. , . . Linux [ ] / .
. . .
http://www.intuit.ru/department/os/baseLinuxwork/.
10., . Linux [] / . . .: ".. ",
2006. 448 .
11., . LPI 201: Linux [ ] / . .
IBM

developerWorks.

http://www.ibm.com/developerworks/ru/edu/l-

lpic2201/ (20 . 2005).

84

12., . Linux [] / . //
. 2004 . 6. . 42-51.
13.,

Linux

http://www.linuxcenter.ru/lib/articles/programming/new_scall.phtml (31
2005).
14., . Linux.
[] / . , . , . . .:
"", 2004. 288 .
15., . Linux.
[ ] / . . .
http://linuxcenter.ru/lib/books/linuxdev/_index (6 . 2006).
16., . Linux. [] / . .
.: -, 2005. 656 .
17., . . [] /
. , . . .: , 2006. 576 .
18., . Linux? ? [] / . // Chip Linux. 2005 .
1. . 56-60.

85