2015-06-08

Linux Kernel Notion





리눅스 배포판 확인

  • 리눅스 배포판 확인
<centos 6.4>
# cat /etc/issue
CentOS release 6.4 (Final)
Kernel \r on an \m


  • 리눅스 커널 버전 확인
<centos 6.4>
# uname -r
2.6.32-358.el6.x86_64


  • 리눅스 커널 소스 다운로드
https://www.kernel.org/

  • 리눅스 커널 소스 구조
├── arch
│   ├── x86
│   └── ..........
├── block
├── crypto
│   └── async_tx
├── Documentation
│   ├── x86
│   └── ...........
├── drivers
│   ├── char
│   └── ...........
├── firmware
│   ├── 3com
│   └── ...........
├── fs
│   ├── ext3
│   └── ...........
├── include
│   ├── pcmcia
│   └── ...........
├── init
├── ipc

├── kernel
│   ├── irq
│   └── .........
├── lib
│   ├── zlib_deflate
│   └── ..............
├── mm
├── net
│   ├── selinux
│   └── ..............
├── security
│   ├── selinux
│   ├── ............
├── sound
│   ├── synth
│   └── ..........
├── tools
│   └── perf
├── usr
└── virt
   └── kvm



시스템 콜 ( System Call )

OS에서 제공하는 기능을 , 사용자 레벨 에서 호출 하게 해주는 API로, 대표적으로 파일 읽기, 쓰기, 인터럽트 호출 등이 해당된다.

# man open
OPEN(2)                    Linux Programmer’s Manual                   OPEN(2)
NAME
      open, creat - open and possibly create a file or device
…...
*OPEN(2)  에서 ‘2’가  시스템 콜을 의미한다.


시스템 콜의  수행

사용자 어플리케이션에서 OS의 시스템 콜을 호출하면, 해당 프로그램은 사용자 모드에서 커널 모드로 이동한다, 그 후 커널 모드에서의 실행이 완료되면 다시 사용자 모드로 제어권이 넘어온다. 그 과정은 다음과 같다.
대다수의 OS가 멀티 프로세싱을 지원하므로 사용자가 실행 시킨 어플리케이션 이외에도 다른 어플리케이션이 사용자 모드와 커널모드를 나누어 사용한다.
위 그림과 같이 사용자 어플리케이션에서 시스템 콜을 호출 하면 트랩에 의해 커널 모드로 집입을 하게 되며 커널모드안에서 커널 함수를 호출하여 요구사항을 처리 하게 된다.

트랩?
트랩이란 실행중인 프로그램에서 특정한 조건에 의해서 , 그에 해당하는 루틴을 실행하도록 하는 일종의 조건 전달점을 가르킨다.
리눅스 커널에서는 시스템콜 호출시 0x80 이라는 소프트웨어 인터럽트를 호출하고 이를 감지한 트랩에 의해서 커널 모드로 들어가게 된다.

시스템 콜 번호
커널 소스  include 디렉토리안의 unistd.h 를 열어 확인 할수 있다.


모듈 프로그래밍

모듈은 시스템이 동작중일때 시스템 콜을 붙였다 땠다 할수 있도록  한그룹으로 묶은 시스템 콜의 집합이다. 즉 커널 코드의 일부를 커널이 동작중일때  추가, 삭제 , 변경 하는것이 가능하도록 하기 위해 사용되는 개념이다.







인터럽트   (Interrrupt, IRQ)

 시스템 콜(system call) 이 OS와 응용 프로그램간의 통신 방법이라고 한다면, 인터럽트는 하드웨어와 운영체제 간의 통신 방법이라고 할수 있다.
하드웨어는 OS 와 통신을 하고 싶을때 인터럽트를 발생시키고 이름 받은 OS는 인터럽트 서비스 루틴 (ISR)을 통해 해당 HW요청을 처리한다.
따라서 인터럽트는 기존의 OS가 하던 작업을 중지 시키기 때문에 비동기  신호 체계 이다.




예외


예외는 인터럽트의 한 부분으로 소프트웨어(SW) 인터럽트를 말한다. SW인터럽트는 HW와 같은 개념으로 HW가 아니라 동작 중인 프로세스가 OS에세 신호를 주기 위해 발생 시키는 인터럽트로 대표적으로 “devide by zero” 등이 있다. SW 인터럽트는 이와 같은 성격상 예외 라도로 불리운다. 시스템콜을 처리하는 트랩(trap)도 SW인터럽트에 속한다.


인터럽트의 수행과정


인터럽트의 수행과정은 시스템 콜의 수행과정을 포함한다.

  1. 커널모드 전환
  2. 인터럽트(IRQ) 번호및 레지스터값 저장
  3. IRQ 번호에 해당하는 인터럽트 핸들러 수행
  4. 사용자 모드로 전환후 프로세스 계속 실행.


발생된 인터럽트는 해당 핸들러가 수행 완료되기 전까지는 다른 모든 작업을 중지한다.
따라서 즉시 처리와 지연처리 인터럽트를 구분 해줘야 한다.

지연처리 로직
  • softirq : 상세조사요
  • tasklet : 상세조사요
  • workqueue : 상세조사요


IDT? (Interrupt Decriptor Table)?
인터럽트 핸들러로 등록된 커널 함수가 시작하는 시작점 주소를 가진다.
리눅스에서는 /kernel/trap.c 에 정의 되어 있다.

시그널(Signal)

시스템에 발생한 이벤트를 커널이 아니라 프로세스에게 알려주기 위해 사용한다. 시그널은 IPC( Inter Process communication)의 한 방법으로 내부 프로세스간의 통신 방법을 의미 한다.
시그널의 발생과 처리 과정은 인터럽트의 그것과 유사하다.
프로세스는 발생하는 시그널에 대해 다음과 같은 4가지 동작을 한다.
  • 무시
    • 가장 기본 동작으로서 시그널을 수신하지만 명시적으로 무시한다.
  • 차단
    • 시그널을 mask 해 차단하고 , 해제하면 signal이 배달 된다.
  • 대기
    • 발생했지만 아직 배달되지 않은 시그널을 의미한다.
  • 예외
    • KILL이나 STOP과 같은 특정 신그널에 대해 무시 차단 할 수 없으며 항상 기본 동작한다.

시그널에 대한 처리 정보는 /linux/sched.h에 다음과 같이 정의되어 있다.
int signpending
해당 프로세스에  대기중인 시그널의 정보를 가진다.
struct signal_struct *sig
해당 프로세스의 시그널 핸들러의 정보를 가진다.
sigset_t blocked
차단된 시그널의 정보를 가진다.
struct sigpending pending
대기중인 시그널의 목록 정보를 가진다.


시그널의 전달과정

1. 시그널의 생성( 해당 프로세스의 PCB의 시그널 자료구조에 기록).
2. 시그널의 처리( 커널이 프로세스를 깨워 시그널 핸들러를 호출한다)
프로세스에서 프로세스로 시그널을 보낼경우 /kernel/kill.c 명령을 사용하고 커널에서 프로세스로 시그널을 보낼 경우에는 /kernel/signal.c을 사용한다.

시그널 핸들러
  • teminate : 프로세스 종료
  • dump : 프로세스 종료, core dump 발생
  • ignore : 무시
  • stop : 프로세스를 멈춘다
  • continue 프로세스가 멈춰있는 경우 깨운다.

커널 동기화

사용자 모드와 커널 모드 사이를 전화하는 조건에 의해서 발생하는  인터럽트의 중복 실행에 의해 발생한다. 커널 모드에서의 중첩된 두 처리가 공유된 변수를 참조할경우 문제발생의 여지가 있으므로  동기화가 필요하며 Atomic operation, locking, Interrupt disabling 등과 같은 메카니즘이 필요하다.



프로세스

프로세스 동작방식

  1. Nonprocess kernel
오래된 os에서 사용하는 방법으로, 응용 프로그램과 커널은 자기만의 이미지를 가지고 완전히 다른 영역에서 동작한다. 즉 커널이 커널모드에서 프로세스는 유저모드에서 완전히 분리되어 실행된다.


  1. Execution within user process
응용 프로그램과 커널이 같은 이미지 안에서 동작한다.
리눅스에서 사용하는 방식으로 응용 프로그램이 커널함수를 수행하는 동안만 커널모드에서 수행된다.


  1. processed-based operating system
커널과 응용 프로그램이 별도의 이미지로 동작한다.
즉 커널 모드에서 죽~ 실행되는 커널 프로세스 들이 존재한다.
멀티 프로세스 환경에서 유리하다.



컴퓨터의 cpu는 줄줄이 들어오는 한가지 명령씩만을 처리한다. 그래서 운영체계가 프로그램을 잘게 잘라 cpu에게 처리하도록 하여 마치 동시에 여러 프로그램이 실행되는 것처럼 보이게 해주는 것이다.


리눅스 프로세스 이미지

리눅스의 프로세스는 다음그림과 같은 이미지를 가지고 동작한다. 보면 하나의 이미지 안에 user 프로그램 이미지와 커널의 이미지가 함께 있는 것을 확인 할수 있다. 따라서 리눅스에서는 ‘듀얼모드(커널, 사용자모드)’를 설정 하여 사용자 모드에서 커널 모드를 함부로 사용할수 없게끔 안전장치를 두었다.

프로세스 생성 fork.

어떤 프로그램을 사용자나 커널이 실행하면 커널은 우선 프로세스의 가상 이미지를 생성하고 , 이미지 안에 프로세스의 동작과 데이터를 넣는다.  하지만 항상 새롭게 프로세스 이미지를 생성하는 것은 아니고, 프로세스를 생성하는 브모 프로세스의 이미지를 그대로 복사한후 필요한 내용만을 다시 이미지 안에 복사하여 , 새로운 프로세스로 동작하게 한다.

현대의 운영체제로 오면서 멀티 프로세싱이 기본이 되어가고, 하드웨어 성능의 향상에 따라  CPU가 복수의 프로세스를 시분할로 처리하여, 사용자로 하여금 동시에 여러 작업이 가능한것처럼 동작하게 되었다.

이에따라 어떤 프로세스에 어느정도의 cpu를 할당 한것인가, 즉 스케줄링의 문제가 대두 되었다.

tast_struct  구조체

/indlude/linux/sched.h 안에 정의 되어 있으며 리눅스에서 프로세스를 실행하기 위한 모든 정보를 저장한다. 많은 정보를 가지지만 그중 , state 는 프로세스의 상태를 , flag는 시스템의 상태를 나타낸다.

state
TASK_RUNNING            
0
프로세스 실행중, cpu 할당대기
TASK_INTERRUPTIBLE      
1
HW,나 시스템 자원을 사용할수 있을떄까지 기다림, 인터럽트 발생으로 TASK_RUNNING 으로 변경 가능
TASK_UNINTERRUPTIBLE    
2
HW 인터럽트에만 의한 TASK_INTERRUPTIBLE
__TASK_STOPPED          
4

__TASK_TRACED           
8

EXIT_ZOMBIE             
16
프로세스 수행종료상태, PCB가 남아 있는 상태임.
EXIT_DEAD               
32

TASK_DEAD               
64

TASK_WAKEKILL           
128

TASK_WAKING             
256

TASK_KILLABLE           
(TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)                                                                

TASK_STOPPED            
(TASK_WAKEKILL | __TASK_STOPPED)                                                                      
프로세스 수행중단 상태, 프로세스가 시그널을 받거나 디버깅을 수행할때
TASK_TRACED             
(TASK_WAKEKILL | __TASK_TRACED)                                                                       

TASK_NORMAL             
(TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)                                                           

TASK_ALL                
(TASK_NORMAL |
__TASK_STOPPED | __TASK_TRACED)                                                        

TASK_REPORT             
(TASK_RUNNING | TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE | __TASK_STOPPED | __TASK_TRACED)           



flags
PF_KSOFTIRQD
0x00000001
I am ksoftirqd      
PF_STARTING
0x00000002
being created       
PF_EXITING
0x00000004
getting shut down      
PF_EXITPIDONE
0x00000008
pi exit done on shut down   
PF_VCPU
0x00000010
I'm a virtual CPU     
PF_FORKNOEXEC
0x00000040
forked but didn't exec     
PF_MCE_PROCESS
0x00000080
process policy on mce errors    
PF_SUPERPRIV
0x00000100
used super-user privileges      
PF_DUMPCORE
0x00000200
dumped core       
PF_SIGNALED
0x00000400
killed by a signal     
PF_MEMALLOC
0x00000800
Allocating memory       
PF_FLUSHER
0x00001000
responsible for disk writeback     
PF_USED_MATH
0x00002000
if unset the fpu must be initialized before use
PF_FREEZING
0x00004000
freeze in progress. do not account to load
PF_NOFREEZE
0x00008000
this thread should not be frozen   
PF_FROZEN
0x00010000
frozen for system suspend     
PF_FSTRANS
0x00020000
inside a filesystem transaction     
PF_KSWAPD
0x00040000
I am kswapd      
PF_OOM_ORIGIN
0x00080000
Allocating much memory to others    
PF_LESS_THROTTLE
0x00100000
Throttle me less: I clean memory   
PF_KTHREAD
0x00200000
I am a kernel thread    
PF_RANDOMIZE
0x00400000
randomize virtual address space     
PF_SWAPWRITE
0x00800000
Allowed to write to swap    
PF_SPREAD_PAGE
0x01000000
Spread page cache over cpuset    
PF_SPREAD_SLAB
0x02000000
Spread some slab caches over cpuset   
PF_THREAD_BOUND
0x04000000
Thread bound to specific cpu    
PF_MCE_EARLY
0x08000000
Early kill for mce process policy   
PF_MEMPOLICY
0x10000000
Non-default NUMA mempolicy      
PF_MUTEX_TESTER
0x20000000
Thread belongs to the rt mutex tester  
PF_FREEZER_SKIP
0x40000000
Freezer should not count it as freezeable  
PF_FREEZER_NOSIG
0x80000000
Freezer won't send signals to it   


TIP
intel x86 아키텍처에서는 다음 그린과 같이 4단계의 Current previlige level (CPL)을 설정 할 수 있지만 , 리눅스에서는 0번과 3번 레벨만을 사용한다.






스케줄링 (Scheduling)


스케줄링이란?

어떤 프로세스를 언제 어떻게 얼마나 실행할지를 결정하는 방법을 의미한다.
리눅스 스케줄링은 시분할 처리를 기반으로 한다. 하나의 처리가 완료되면 대기중인 프로세스중 우선순위에 따라 다음 처리 프로세스를 결정한다.

프로세스는 위 그림과 같은 사이클을 가지는데 생성되면 Running이 라는  실행 가능 상태를 가진다. Running 상태를 가지는 프로세스중 우선순위에 따라 실행되는 프로세스는 동작을 수행하는 동안 Current상태를 가지게 된다. 실행중 커널 모드에서 하드웨어의 수행이 필요한 작업을 수행하면 Blocked 상태로 이동하며, 해당 하드웨어로부터 응답 인터럽트를 수신하면 Running 상태로 이동한다.

우선 순위를 결정할때 현재 실행중인 프로세스보다 높은 우선순위의 프로세스가 있으면  실행중인 프로세스를 Running 상태로 이동시키고 수행한다. 이를 선점(preempt)라고 한다.

리눅스에서는 커널 버전에따라 선점을 허가 하는 선점허가커널(preemptive kernel)과 비선점커널(non-preemptive kernel)로 나눌수 있는다.(2.4:비선점커널, 2.6:선점커널)

비선점 커널은 선점 커널에 비하여 구조간 간단하여 커널 자료구조 동기화 문제등을 쉽게 피할수 있지만, 스케줄러가 각 프로세스가의 수행에 대한 예측이 어렵고 엄격한 데드라인이 요구되는 실시간 프로세스의 수행을 지원할 수 없다.

리눅스 스케줄링 방법


  • SCHED_FIFO : 고정된 우선순위를 가지고, SCHED_OTHER 에 의해 선점 당하지 않는다. 사용 시간의 제약(time quantum)이 없어, 보다 높은 우선순위를 가진 프로세스에게 선점 당하거나, 프로세스사 스스로 blocked상태로 가지 않는한 계속 실행된다.
  • SCHED_RR : 고정된 우선순위를 가지고, 사용가능 시간(time quantum)에의해 스케줄링된다.
  • SCHED_OTHER :  나머지 프로세스를 의미.


TIP
소프트 리얼타임 : 리눅스가 이에 해당 , 스케줄링을 통해 프로세스들의 우선순위를 조정함으로서 가능한 실시간 처리를 지원한다 ( SCHED_FIFO, SCHED_RR 이 실시간 프로세스를 지원하기 위한 정책이다.)
하드 리얼타임 : 처리해야할 작업에 대해, 특정 시간안에 처리 되어야할 데드라인이 존재함.

TIP
에포트(epoch)  리눅스가 프로세스 스케줄링에 사용하는 상대적시간을 가지는 논리 시간 단위.
모든 프로세스의 ‘사용가능 시간’(time quantum) 이 계산 되는 시간을 시작 기준으로 하여 프로세스가  ‘사용가능 시간’을 다 사용하면 새롭게 epoch를 시작한다.

프로세스의 분류

  1. 인터렉티브 프로세스 ( interactive process )
CPU를 적게 사용하늩 특성이 있다( 대체로 I/O 작업을 분리할수 있기 때문에 cpu는 쉴수 있다.)
  1. 배치 프로세스 ( batch process )
cpu를 많이 사용하느 프로세스를 의미한다.반면 특별히 높은 우선순위를 가지지는 않는다.
  1. 실시간 프로세스 ( real time process )
반응 시간을 중요하게 평가하는 특성이 있다.

프로세스의 ‘사용가능 시간’(time quantum)

‘사용가능 시간’(time quantum)이 너무 길면 시스템의 반응성이 떨어지게 된다. 우선순위가 높은 프로세스에 의해 선점 될경우 ‘사용가능 시간’을 다 채울수 없을수 도 있지만, 기본적으로 프로세스는 time quantum 만큰 수행 하기 때문이다.
time quantum 수치는 ../indlude/linux/sched.h 에 정의되어 있다.

#define DEF_COUNTER (10*HZ/100)             /* 100ms time slice */
HZ(헤르츠는 CPU의 클럭이 1초에 tick하는 횟수)로 x86에서 100으로 정의되어 있다.
위 공식에 따라 Time Quantum 은 100ms가 된다. 반면 epoch후에 새로이 할당받는  Time Quantum 은 60ms이다.


파일 시스템 (File System)


파일 시스템을 이해하기 위해선 디스크의 구조에 대한 이해가 필요 하다. 디스크에는 0과 1로 이루어진 데이터가 저장되는데, 한 bit 씩처리 할경우 디스크 io에 대한 오버 헤드가 발생 하므로 일정한 크기의 논리 블럭단위로 디스트에 io한다. 블럭단위는 최근에는 4096kb 이상이 보편적이다.
보통 프로그램 혹은 데이터는 하나의 블럭으로만 이루어지지 않기 때문에 이 블럭 들을 관리하기 위한 추상적 객체가 파일이 된다. 따라서 사용자는 추상적 객체인 파일 단위의 처리를 수행할 수 있다.
이 블럭이 실제 물리 디스크에는 연속공간에만 저장되는 것이 아니기 때문에
블럭 체인, 인덱스 블럭, FAT, INODE 기법등을 사용하여 관리한다.

  • 블럭체인
    • 같은 체인에 속한 블럭들을 링크드 리스트로 연결 관리
    • 파일의 긑블럭을 읽고자 할경우 링크드 리스크의 첫 블럭부터 순차적으로 접근해야 한다.
  • 인덱스 블럭
    • 블럭 체인의 경우처럼 순차적 접근이 아닌 임의접근이 가능하도록 블럭을 인덱스화 하고 이를 관리하는 블럭을 별도 관리한다.
  • FAT
    • 동일 파일에 있는  블럭들을 FAT 자료구조에 저장한다.
    • INODE와 유사한 방식이다.
  • INODE
    • 파일이 생성될때마다 INODE라는 자료구조를 생성한다.
    • INODE에는 파일에 대한 헤드 정보와 파일의 블럭들에 대한 인덱스구조 정보를 가진다.

INODE의 구조



사용자가 파일을 저장할 경우 , 파일의 사이즈가 적으면 i_block의 15개 인덱스중 12개를 사용하여 파일을 저장하며, 파일의 사이즈가 커질경우는 i_block의 끝의 indirect 데이터 블럭을 사용해서 파일을 저장하게 된다.
INode의 구조상으로 파일의 한계는 4T이지만 리눅스 머신의 지원과 표준 호환성으로 인해 4T보다 작다.

가상 파일 시스템의 논리 구성도

  • Buffer Cache
    • 디스크에서 빠르게 데이터를 읽기위해 사용
    • 파일 시스템과 상호 독립적으로 운영
    • 리눅스 커널이 데이터 버퍼를 io하는 메커니즘의 일부
  • INODE Cache
    • 실 파일 시스템과 연결된 가상 파일 시스템상에서 커널내의 파일 처리에 관한 성능을 향상
    • 프로세스가 파일을 액세스 하면 수많은 VFS INODE의 탐색이 이루어진다. 이 부하를 줄이기 위해 Inode cache를 사용한다.
  • Directory Cache
    • Inode 자체를 저장하지 않고 단지 디렉토리의 이름과 iNode번호를 매핑하는 역활을 한다.


가상 파일 시스템 구조

가상 파일 시스템에서는 “일반적인” 파일 시스템이 가져야한 주요 명령들(open,write,read,closd등) 및 관련 동작들을 일반화 시키고, 적합하게 구현하여야한다.

가상 파일시스템의  주요 구조체
  • 파일 시스템을 나타내는super block 구조체
  • 파일을 나타내는 inode구조체
  • 각 디렉토리를 나타내는 dentry 구조체
  • 프로세스에서 사용하기 위해 필요한 파일 구조체

EXT2 파일 시스템
블럭 기반으로 데이터 관리.
파티션을 블럭 그룹으로 관리하며, 각 블럭그룹은  슈퍼블럭등의 중요정보를 중복해서 갖고 있다.



파일 시스템의 캐시 구조


  • 버퍼 캐시( Buffer Cache )
메모리와 디바이스 사이의 속도차를 해결하기 위한 완충 역할을 수행한다.
기능적으로 크게 해시구조, LRU 구조, 블럭 버퍼관리 구조로 나누어 진다.


  1. 해시구조
    버퍼에  해당 데이터가 존재하는 지 여부를 빠르게 확인할수 있도록 하는 구조.
  1. LRU 구조
캐시저장 공간이 부족할 경우 가장 요청할 가능성이 적은 데이터를 버리기 위한 정책이다.
LRU는 버퍼의 데이터의 상태에 따라  clean, locked, dirty의 리스트를 가진다.
  1. 블럭 버퍼 관리 구조
블럭 버퍼들의 리스트를 관리한다.
free_list 에 의하여 버퍼의 크기별로 구분되어 링크드리스트 형태로 관리한다.



  • Inode 캐시
inode 데이터 정보는 파일시스템 사용시 가장 많이 사용하는 데이터 이며, inode 캐시는 해시 테이블로 구현되어 있다.
해시값은 파일 시스템을 가지는 장치 식별자와 inode번호로 만들어진다.
캐시 검색시 해시값으로 검색하여 inode 정보가 캐시네에 존재하면 , 캐시의 카운트 값이 1증가한다. 이는 해당 inode를 사용하는 사용자가 있다는 의미이며, 해당 inode의 사용빈도를 알려준다.
만약, 해당 inode정보를 캐시네에서 찾을수 없다면 메모리로부터 비어 있는 가상 파일 시스템을 할당 받거나 , inode캐시 카운트를 확인하여 사용빈도가 적은 것을 버린다( 시스템에서 허용된 캐시 공간이 이미 차 있는 경우) .
빈 가상 파일 시스템에 inode 가 만들어지면, 가상 파일 시스템은 실제 파일 시스템에서 읽어온 정보를 inode 에 채우는 루틴을 호출한다. 이때  inode의 카운트는 1이 되고 락이 걸리므로 해당 inode가 완전한 정보를 갖게 될때 까지는 아무도 접근 할수 없다.

  • 디렉토리 캐시
실제 파일 시스템 내부의 객체에 접근할 때, 그 객체의 디렉토리 엔트리를 통하여 inode정보를 얻어야만 한다. 따라서 디렉토리 접근속도는 inode 접근속도 못지 않게 중요하다.
디렉토리도 해시 테이블로 구현되며, 1단계, 2단계 의 2가지 큐를 사용한LRU 방식을 사용해서 관리한다.

파일 시스템의 수행 흐름.

  • 파일 시스템의 등록 및 해제
파일 시스템 등록 작업은  해당 파일 시스템에 대한 개략적인 정보와 , 수퍼블럭을 메모리로 로드하기 위한 메소드를 구조체 file_system_type 에 정의하는 작업이다.
등록된 file_system_type의 구조체 정보들은  포인터변수 file_systems가 head를 가르키느 선형 리스트 형태로 관리된다.

file_system_type의 정보.
1. 수퍼블럭 읽기 루틴 - 파일 시스템이 마운트 될때 가상 파일 시스템에 의해 호출된다.
2. 파일 시스템 이름 - 파일 시스템 이름을 나타낸다.
3. 필요한 장치 - 파일 시스템을 실제로 지원하는 장치가 필요한가를 나타낸다.
( ex. proc 파일 시스템은 블록 장치를 필요로 하지 않는다)

등록방법
1. 커널 부팅시 파일 시스템을 등록하는 방법
2. insmod에 의해서 등록하는 방법.

두가지 방법 모드 함수 init_ext2_fs()를 호출한다, 함수내에서는 가상 파일 시스템에 정의된 함수 register_filesystem() 을 호출 하여 등록 작업을 수행한다.

마운트된 파일 시스템들은 구조체 변수 vfsmount에 의해서 포괄적인 정보들이 표현된다.
이 vfsmount 선형 리스트를 통해 , 리눅스는 마운트 되어진 superblock과 device에 대한 정보를 얻을수 있다.

  • bdflush , update 커널 대몬
bdflush daemon 은 ps 명령시 kflushd라는 이름으로 찾을수 있으며 시스템이 시작할때부터 커널 스레드로 시작된다.
bdflushd 는 버퍼가 할당되거나 버려질때 시스템의 더티 버퍼수를 검사해서 일정 비율이상(기본60%) 이면 더티 버퍼의 내용을 디스크에 쓴다.
데이터를 버퍼에 쓰면 버퍼가 더티하게되고 BUF_DIRTY LRU 리스트에 연결된다.
update명령은 주기적으로 오래된 더티 버퍼들을 디스크에 기록한다.

파일 시스템

ext3 파일 시스템

ext3는 ext2파일 시스템에 저널링 기능을 추가하여,  예외적인 상황에서의 복원기능을 향상시킨 버전이다.
ext3는 ext2보다 저널링 기능에 대한 중복 기록으로 오버헤드가 증가 했지만,  하드 디스크의 헤드모션을 최적화하는 저널링 기능을 사용 ext2보다 성능이 향상되었다.


* 저널링: 데이터베이스 시스템에서의 트랜잭션 단위의 로그 관리 기능과 비슷한 역활을 수행.

proc 파일 시스템

가상 파일 시스템으로서 블럭 디바이스(block device)가 아닌 메모리에 위치한며, 프로세스가 현재 커널의 정보를 확인할수 있도록 하는 기능을 제공한다.
ca등의 파일관련 명령으로 확인 가능한데 파일 사이즈는 0으로 이는 메모리에 데이터가 실제 올라와있기 때문이다.

procfs는 에 대해서는 “include/linux/proc_fs.h”에 정의되어 있다.

i-node 자료구조
struct inode
{ char i_flag;
char i_count; /* reference count */
int i_dev; /* device where inode resides */
int i_number; /* i number, 1-to-1 with device address */
int i_mode;
char i_nlink; /* directory entries */
char i_uid; /* owner */
char i_gid; /* group of owner */
char i_size0; /* most significant of size */
char *i_size1; /* least sig */
int i_addr[8]; /* sector addresses constituting file */
int i_lastr; /* last logical block read (for read-ahead) */
} inode[NINODE];



파일 자료 구조
struct file
{ char f_flag;
char f_count; /* reference count */
int f_inode; /* pointer to inode structure */
char *f_offset[2]; /* read/write character pointer */
} file[NFILE];


디바이스 스위치 테이블  자료구조
struct cdevsw
{ int (*d_open)();
int (*d_close)();
int (*d_read)();
int (*d_write)();
int (*d_sgtty)();
} cdevsw[];




메모리 ( MEMORY )

메모리공간의이해


운영체제가 대부분 그렇듯, 멀티 프로세스 서버에서 한정량의 물리적 메모리 만으로는 프로세스를 유연하게 사용할수 없다 따라서 , 가상화 메모리 기법, 메모리 영역 보호 기법,  메모리 동적 할당 기법등을 사용해서 메모리 를 유연하게 사용하도록 되었다.

물리주소(Physical address) : 물리주소는 0부터 시작하여 장착된 메모리 크기에 해당되는 주소를 가진다.
가상주소(Virtual address): 가상 주소는 프로세스 마다 할당되며  0부터 시작하여 각 운영체제가 프로세스에게 제공하는  영역 까지를 가진다.

페이징 기법 : 프로세스의 메로리를 실제적으로 물리적메모리에 조각내어 저장하고 , 프로세스가 볼떄만 연속적으로 이어진것처럼 메모리를 사용하는 방법.
1. 물리 메모리를 일정크기의 프레임으로 나눈다.
2. 프로세스가 사용하는 가상 메모리를 프레임 크기로 나눈다.
3. 시스템은 사용하지 않는 프레임을 저장해 두었다가, 새로운 프로세스에게 할당한다.

페이징 기법을 활용한 가상 , 물리 메모리 맵핑법.

세그먼테이션 기법 : 프로세스가 사용하는 데이터 영역이  코드, 데이터, 스택, 힙 으로 구분된다는 사실에 기반하는 하는 방법이다.

세그먼테이션 과  페이징 기법은 가상주소와 물리조주소 사이의 변환가정이 복잡하여 , 이로 인한 성능저하를 막기 위하여 하드웨어에서 많은 기능을 지원하도록 되어있다.

인텔i386 계열에서는 세트먼테이션과 페이징기법을 다음과 같이 표현한다.
프로세스의 가상 주로가 세그먼 테이션을 거치면 선형주소가 되고 페이징 처리를 거치는 물리주소를 반환하게 된다.

논리주소
세스먼트 아이디는 세그먼트 정보를 읽는데 사용되는데, 빠른 수행을 위해 별도의 레지스터를 제공한다.
  • CS : code segment register
  • DS : data segment register
  • SS : stack segment register

선형주소
선형주소는 페이징 유니트를 통해 물리주소로 변환데는데 , 이때 해당 페이지에 대한 점근 권한 검사가 발생한다.
권한이 없거나 , 페이지가 지정하는 메모리 프레임이 존재하지 않을경우 page fault exception을 발생시킨다. 이와 같은 검사를 통해 프로세스간 메모리 나 커널 영역으로의 침범을 제어한다.


i386 의 페이징 처리 과정
위에와 같이 i386 에서는 32비트 메모리 공간을 선형주소에 할당하여 페이징단 10비트씩 2단계 페이징 기법을 사용한다.


64bit 선형주소의 경우에는 Page Directory를 Page Global Directory, Page Midle Directory 로 3단계 페이징 레벨의 페이징 기법을 제공한다.

가상 메모리 관리 데이터 구조



요구페이징 (demang paging)

프로세스의 가상 메모리 공간에 있는 페이지들중 현재 수행에 필요한 페이지들만 물리 메모리로 로드함으로서 부족한 물리 메모리를 보다 효율적으로 사용하고자 하는 기법.

커널은 현재 수행에 필요하지  않다고 판단되는 페이지를 물리 메모리 상에서 제거 하는데 이떄 제거된 페이지의 영역이 저장되는 영역이 스왑(SWAP)파티션이다.

스와핑

커널이 프로그램의 수행이 필요하다고 생각되는 페이지가 스왑영역에 저장(swap-out)되어 있는 경우 , 하드웨어의 스왑영역에서 페이지를 읽어 물리 메모리에 저장한다. 이떄 물리 메모리에 페이지가 비어 있지 않으면 , 다른 물리 페이지를 제거 해야 한다.
이때 물리 페이지가 변경이 되어 있다면 저장을 해줘야 한다. 이때 저장되는 영역이 스왑이다.
따라서 물리 페이지를 제거하는 방법이 중요해지는데 리눅스는 Least Recently Used 방식을 사용한다.



struct vm_area_struct{
unsigned long vm_start;
unsigned long vm_end;
struct vm_operations_struct *vm_ops;
struct mm_struct *vm_mm;
struct vm_area_struct *vm_next;
struct file * vm_file;

• vm_start: the initial address in the interval
• vm_end: the final address in the interval
• vm_ops: operations associated with a given VMA
• vm_mm: points back to this VMA‟s associated mm_struct
• vm_next: list of VMA‟s
• vm_file: file we map to

}








네트워크 프로그래밍



  • TCP/IP stack


Tcp/ip 의 계층구조를 표준 osi7계층과 구분해 보면 다음과 같다.


- TCP/IP 4계층은 인터넷 모델이라고도 한다.
레벨
계층
기능
4계층
Application
응용 계층
프로토콜 : HTTP, FTP, Telnet, DNS, SMTP
OSI 7계층의 5, 6, 7계층에 해당한다.
TCP/IP 기반의 응용프로그램을 구분할 때 사용한다.
3계층
Transport
전송 계층
프로토콜 : TCP, UDP
OSI 7계층의 4계층에 해당한다.
통신 노드 간의 연결을 제어하고, 자료의 송수신을 담당한다.
2계층
Internet
인터넷 계층
프로토콜 : IP, ARP, RARP, ICMP, OSPF
OSI 7계층의 3계층에 해당한다.
통신 노드 간의 IP 패킷을 전송하는 기능 및 라우팅 기능을 담당한다.
1계층
Network Interface
네트워크 인터페이스 계층
프로토콜 : Ehternet, Token Ring, PPP
OSI 7계층의 1, 2 계층에 해당한다.
CSMA/CD, MAC, LAN, X.25, 패킷망, 위성 통신, 다이얼 업 모뎀 등 전송에 사용된다.

  • 리눅스의 네트워크 구현 방식
리눅스 운영체제의 네트워크 모델은 tcp/ip와 유사하지만 몇가지 다른점이 있다.
  1. 네트워크 기능이 운영체제 내부에 있기 때문에 응용 프로그램과 네트워크 기능간 BSD 소켓 레이어를 두어 네트워크 기능을 손쉽게 사용하도록 돕는다.
  2. 응용 프로그램은 네크워트 기능을 사용하기 위해 소켓 인터페이스를 사용하는데 , 리눅스에서는 이를 하나의 특별한 파일로서 관리한다.
  3. 디바이스 레이어를 두어 다양한 네트워크 디바이스를 관리한다.
리눅스 에서 네트워크간 데이토 이동을 다루는 구조체는 socket과 sk_buff이다.
응용 프로그램이 네트워크 기능을 사용하기 위해서는 socket을 사용하여 리눅스에 네트워크 기능을 사용할 것을 요청하고, socket 자료구조를 사용하여 응용프로그램과 네트워크 기능간의 인터페이스를 관리한다.그리고 네트워크 기능 내부에서의 실제 송, 수신 데이터는 sk_buff상에서 하나의 데이터(패킷)이 저장되는 형태로 보여준다.
네트워크 계층구조
TCP/IP 스택이 4계층으로 이루어져 있지만, 실제 리눅스의 커널은 어떤 위 “ 네트워크 계층구조” 에서 보듯이 어떤 프로토콜 패미리를 선택하느냐에 따라. 최종 네트워크 디바이스 드라이버까지의 독립적인 계층이 존재한다.

1. BSD 소켓 레이어는 socket(), bind(), connect(), accept(), listen() , send(), recv() 과 같은 시스템 콜을 제공한다.
2. INET 레이어에서는  stream, datagram, raw( 가공되지 않음을 의미) 소켓의 타입을 지원한다.
3. Transport레이어는 전송계층의 역활을 담당한다.
4. IP레이어서는 ip주소를 사용하여 통신을 하게 된다.
5. 네트워크 어드레스 레이어 에서는 실제 물리적 전송을 담당한다.


아래 그림의 k_buff는 다른 자료구조와는 달리 , 실제 저장되는 데이터의 영역을 줄이거나 늘릴 수 있다. 응용 프로그램에서 네트워크 기능을 사용하기 위하여 각 레이어를 거치면서, 데이터의 앞이나 뒤에 메타 정보를 붙이고 sk_buff 의 정보를 수정함으로서, 각 레이어의 구조체를 구현할 필요가 없어졌다.
통신의 각 레이어를 별도의 구조체를 정의 하는 쓰레드로 구현하는 것도 가능하지만 , 리눅스 운영체제는 데이터 전송 효율성을 극대화 시키기 위하여 하나의 일괄된 프로그램 형태와 st_buff와 같이 공유 가능한 데이터를 이용하여 레이어 구조를 구현하였다.

* 레이어와  모듈화
복잡한고 다양한 의존 관계를 가지는 모듈화는 , 복잡한 모듈관리와 사이드 이펙트와 그 검증이 어렵다. 반면 레이어 구조는 단순하고 직접적인 읜존 관계를 가지지만 데이터의 전송을 바로 하지 못하고 레이어 구조를 통과하게 되므로 복잡한 레이어 구조에서는 오버헤드가 발생한다.



  • 리눅스의 네트워크 관련 주요 자료 구조.

VFS Layer
struct file_operations
BSD Socket Layer
struct net_proto_family
struct socket
INET Layer
struck sock
struct ptoto_ops
Transport Layer
struct tcp_opt
struct proto
IP Layer
struct tcp_func
struct packet_type
Device Layer
struct device

자료구조와 네트워크 커널 흐름

  • 데이터 송수신


구분
1) 클라이언트와 서버
2) 연결지향형 소켓 프로그래밍
3) 무연결지향형 소켓 프로그래밍




No comments:

Post a Comment