리눅스에서 프로세스 시작과 관련된 함수 

: system(), fork()


종료와 관련된 함수

: wait(), waitpid(), exit()





##### system()


#include <dtdlib.h>

int system(const char    *string);

프로그램 수행도중 새로운 명령이나 프로그램 수행 가능

string : 명령 (sleep 3, ls ...)



##### fork()


#include<unistd.h>

pid_t fork(void);


프로세스 생성

부모프로세스로부터 만들어지며, 부모 프로세스와 같은 공간의 코드를 수행하지만 자기자신만의 데이터 공간 및 FDT등의 실행 환경을 구성

고유한 PID를 갖고, 부모프로세스의 PID를  자신의 PPID에 저장

부모 프로세스로부터 시그널 등도 상속받음

부모프로세스의 함수와 자식 프로세스의 함수에서는 서로 다른 값을 반환하여, 각 프로세스에서 수행할 일을 구분하게 됨

(부모 return : 정상 시 자식프로세스 PID, 자식 return : 정상 시 0)


fork() 실패 시 -1 rerutn.

- 메모리 부족 : errno 변수에 ENOMEM 설정

- 자식 프로세스 개수의 제한 : errno변수에 EAGAIN 설정



##### wait() 

: 자식프로세스의 종료까지 책임이 부여되는 함수


#include <sys/types.h>

#include <sys/wait.h>

pid_t wait(int *stat_loc);


case 1. 자식프로세스가 존재하는 경우

wait() 호출 -> 자식프로세스가 시그널을 보낼 때 까지 부모프로세스의 수행 중지 -> 자식프로세스의 PID반환

case 2. 자식프로세스가 존재하지 않는 경우

wait() 호출 -> -1 반환 -> errno 변수에 ECHILD 설정

case 3. 부모 프로세스에서 자식 프로세스의 종료 원인을 자세히 알고싶은 경우

인수로 상태정보를 읽어 올 수 있는 변수를 넘겨줌 -> 종료 상태 확인(sys/wait.h의 매크로 사용)


<관련 매크로>

'System > Linux Kernel' 카테고리의 다른 글

CFS 구현의 핵심  (0) 2016.01.22
커널에서 원하는 값을 가지고오기 위해 clz를 하는 이유  (0) 2016.01.16
[Unix V6] 시스템 부팅  (0) 2015.12.19
Device Tree, 리눅스 커널 4.0  (0) 2015.08.29
메모리관리  (0) 2015.08.18


UNIX v6로 배우는 커널의 원리와 구조 (한빛미디어)

http://v6.cuzuco.com/v6.pdf






##### 14. 시스템 부팅




<개요>


- 커널 프로그램을 메모리로 읽어야 함(약 40KByte)

- 당시에는 메모리 용량이 작아서 ROM에 저장해 놓을 수 없었음

=> 단계를 나누어 작은 크기부터 읽은 후 큰 크기의 프로그램을 읽는 점진적 형태로 부팅을 수행

1. 부트로더를 읽는 프로그램을 먼저 메모리로 올리고,

2. 부트로더를 읽고,

3. 실제 커널 프로그램을 읽음




<Unix V6의 부팅과정>


1. ROM에 저장되어있는 Boot Strap Loader Program에서, Root Disk의 블록번호 0에 저장된 Boot Strap Program을 읽어서 메모리의 0x0으로 읽어옴

* Boot Strap Program은 시스템 관리자가 /etc/mkfs을 실행하여 파일 시스템을 구축할 때 블록 디바이스의 0번째 블록에 위치하도록 설정


2. Boot Strap Program은 Root Disk의 fs에서 /Unix나 /rkunix에 있는 Kernel Program의 본체를 메모리의 0x0으로 계속하여 읽어서 실행


3. kernel은 시스템을 초기화 함



<부팅, low.s>

--------------------------------------------------------------------------

/*

 *    커널 본체(?)의 하위 어드레스 부분

*/


1.    . = 0^.                            // 프로그램이 메모리로 로드될 때 주소가 0x0 임

2.        br    1f                       // 최초 실행 명령어, label 1로 brach

3.        4                               

4.        

5.        /* 중간 생략 */

6.

7.    . = 40^.

8.    .global    start,    dump   

9.    1:    jmp    start               // start로 jump

10.         jmp    dump

--------------------------------------------------------------------------





### 14.1.1 start


<start, m40.s> 

--------------------------------------------------------------------------

/*

 *    <처리내용>

 *

 *    1. 커널 APR 초기화

 *        - 최초의 커널공간을 설정

 *        - 커널 APR(Active Page Register, PAR과 PDR) 설정 (참고. p460, 표 14.1 커널 APR 초기 설정)

 *            a. APR0~5 : 물리메모리의 0~0137777를 할당. 물리어드레스 = 가상어드레스영역. 앞부분에 커널프로그램의 본체가 로드 됨

 *            b. APR6 : 커널 프로그램 뒤의 1KByte 영역 할당. proc[0]의 PRDA(user 구조체와 커널스택)이 할당

 *                            현재 실행 중인 프로세스의 PRDA이며, 프로세스 전환히 함께 전환 됨

 *            c. APR7 : 물리메모리의 최상위 영역 할당(0760000~07777777)

 *                            PDP-11/40이나 주변 디바이스 레지스터를 할당하여 PDP-11/40과 주변장치를 제어

 *            d. SP는 APR6 영역의 맨 끝을 가리키도록 함

  *        - 커널 APR은 PAR6을 제외하고 시스템 동작 중에는 값이 바뀌지 않음

 *            => 실행 프로세스의 PAR6은, user 구조체로 접근할 수 있는 전역변수 u(0140000)를 사용하여         

 *                해당 data segment의 physical memory address로 설정 (참조. p65, 그림 2.13 물리 어드레스 계산)

 *            (PAR, Page Address Register, 11~0 bit, physical memory block address의 base address register, 64bit 단위)

 * 

 *    2. MMU 초기화

 *        - SR0을 설정하여 MMU를 활성화 하면 "physical address <-> logical address"가 시작 됨 (가상메모리 사용을 시작 함)

 *            MMU는 SR0과 SR2라는 Status Register를 가짐 (참고. p41)

 *            SR0 : 메모리 관리 유효화 플래그와 에러 정보에 사용

 *            SR2 : 실행할 명령어의 16bit logical address

 *        - 커널 프로그램의 bss와 proc[0]의 PPDA를 0으로 초기화 (참고. p59)

 *                PPDA : 프로세스의 메모리 영역 중 Data Segment의 "user구조체 + 커널 스택 영역" 

 *                bss : 프로세스의 메모리 영역 중 Data Segment의 Data 영역에 있는 정적 변수가 위치하는 영역

 *        - 이전 모드를 user mode로 설정한 후 main() 실행 

 * 

 *    3. miain() 수행

 * 

*/


0610 /* ------------------------- */ 


0611 .globl start, _end, _edata, _main 

0612 start: 


/* MMU가 이미 활성화 되어있으면 비활성화가 될 때까지 진행하지 않음 */

0613 bit $1,SSR0 / SSR0 : SR0의 어드레스, SR0[0] bit가 서 있으면, MMU에서 메모리 관리 활성화 (SSRO = 177572)

0614 bne start / loop if restart 

0615 reset 

0616 


0617 / initialize systems segments, 커널 APR0-5의 초기화

0618 

0619 mov $KISA0,r0 / KISA0 = 172340, 커널 APR의 PAR

0620 mov $KISD0,r1 / KISD0 = 172300, 커널 APR의 PDR

0621 mov $200,r4 

0622 clr r2 / r2 클리어 

0623 mov $6,r3 


0624 1: 

0625 mov r2,(r0)+ 

0626 mov $77406,(r1)+ / 4k rw

0627 add r4,r2 

0628 sob r3,1b 

0629 

/*

* APR은 0~7까지 8쌍이 존재하며, 한 쌍의 APR은 한 페이지에 대응

* _edata : 데이터영역, _etext : 텍스트영역, _end : bss영역의 하한 어드레스를 가리킴 

* => 프로그램 컴파일 시 링커에 의해서 심볼 테이블로 저장

*/

0630 / initialize user segment, 커널 APR6 초기화

0631 

0632 mov $_end+63.,r2 

0633 ash $-6,r2 

0634 bic $!1777,r2 / PAR6 설정값 계산

0635 mov r2,(r0)+ / ksr = sysu / APR이 64byte 단위로 물리 어드레스를 관리하므로 반올림 할 때

0636 mov $USIZE-1\<8|6,(r1)+ / 6비트 오른쪽으로 시프트하여 하위 10bit를 남기고 0으로 초기호 

0637 

0638 / initialize io segment, 커널 APR7 초기화

0639 / set up counts on supervisor segments 

0640 

0641 mov $IO,(r0)+ 

0642 mov $77406,(r1)+ / rw 4k 

0643 

0644 / get a sp and start segmentation 

0645 / SP 초기화 및 MMU 활성

0646 mov $_u+[USIZE*64.],sp 

0647 inc SSR0 

0648 

0649 / clear bss

0650 / bss 활성화

0651 mov $_edata,r0  

0652 1:

0653 clr (r0)+

0654 cmp r0,$_end

0655 blo 1b

0656

0657 / clear user block

0658 / proc[0] user 커널 스택 영역을 0으로 초기화 

0659 mov $_u,r0

0660 1:

0661 clr (r0)+

0662 cmp r0,$_u+[USIZE*64.]

0663 blo 1b

0664

0665 / set up previous mode and call main

0666 / on return, enter user mode at 0R

0667 / main() 호출

0668 mov $30000,PS

0669 jsr pc,_main

0670 mov $170000,-(sp)

0671 clr -(sp)

0672 rtt


--------------------------------------------------------------------------



### 14.1.2 main() 



<처리내용>


1. 메모리 초기화


- proc[0]의 PPDA이하를 0으로 초기화 한 후 빈 영역의 관리를 위해서 coremap[]에 추가.

map 구조체 : 물리 메모리와 스와프 영역의 빈 영역을 관리 (빈 영역의 어드레스 크기를 나타냄) (참고. p134)

(coremap[] : 물리 메모리 관리영역(APR의 최소단위인 64bytes 단위) , swapmap[] : swap 메모리 관리영역(512bytes, 블록단위)


- MAXMEM 설정

: 실제 빈 영역의 크기를 나타내는 maxmem에는 실제 빈 영역의 크기와 MAXMEM 중 더 작은 값을 설정


int maxmem;    (system.h, maxmem)

#define MAXMEM    (64*32)    (param.h, MAXMEM)


2. swap 영역 초기화


- swapmap[]

- mfree() 확보

- swplo 블록에서 mswap 블록까지의 영역을 swapswap에 swap 영역으로 등록


(conf.c)

int swplo    4000;

int nswap    872;


3. clock 장치 초기화


4. proc[0] 생성

- proc[0] : 시스템 프로세스 스케줄러


5. I/O자원 초기화


6. proc[1] 생성 

- proc[1] : /etc/init을 실행하는 사용자 프로세스로 inode[]에 넣어둔 명령어들을 실행


* inode : 파일크기, 접근권한, 데이터가 저장된 블록 디바이스의 블록 번호정보 등을 포함하는 파일의 속성 데이터

블록 디바이스에 저장되어 있으며, 커널은 파일을 사용하기 위해 해당 파일의 inode를 읽음




<inode[], ken/main.c>


1511 /* 1561 UISD->r[0] = 077406; 

1512 * Icode is the octal bootstrap 

1513 * program executed in user mode

1514 * to bring up the system. 

1515 */ 

1516 int icode[] 

1517 {

1518     0104413, /* sys exec; init; initp */ 

1519     0000014, 

1520     0000010, 

1521     0000777, 

1522     0000014, /* initp: init; 0 */ 

1523     0000000, 

1524     0062457, /* init: */ 

1525     0061564, 

1526     0064457, 

1527     0064556, 

1528     0000164, 

1529 };



=> C언어 판

1    char *init = "/etc/init";

2    execl(init, init, 0);

3    while(1);



< main(), ken/main.c >


1550 main() 

1551 { 

1552     extern schar; 

1553     register i, *p; 

1554 

1555     /* 

1556     *     zero and free all of core  메모리와 스택영역 초기화

1557     */ 

1558 

1559     updlock = 0; 

1560     i = *ka6 + USIZE;                 // i에 proc[0]의 PRDA 영역의 뒤에 어드레스를 설정

ka6은 커널의 APR6의 어드레스(KISA6)이 설정되어 있으므로 "*ka6"으로 커널 APR6 값 가져오기

1561     UISD->r[0] = 077406;         // UISD, UISA : 사용자 APR0의 PAR, PDR의 어드레스 (seg.h에 define되어있음)

1562     for(;;) {     

1563         UISA->r[0] = i; 

1564         if(fuibyte(0) < 0)             // fuibyte() : 이전 모드의 가상 어드레스 공간의 데이터를 한 바이트만큼 복사하는 함수

 전 모드가 user mode이므로 fuibyte(0)은 사용자 APR0에 할당된 페이지의 처음부터 데이터를 복사하기 시작

1565             break; 

1566         clearseg(i);                       // 성공 시 수행루틴

1567         maxmem++;                     // coremap을 증가시키기 

1568         mfree(coremap, 1, i);        //  coremap 초기화

1569         i++; 

1570     } 

1571     if(cputype == 70) 

1572    for(i=0; i<62; i=+2) { 

1573         UBMAP->r[i] = i<<12; 

1574         UBMAP->r[i+1] = 0; 

1575     } 

1576     printf("mem = %l\n", maxmem*5/16); 

1577     printf("RESTRICTED RIGHTS\n\n"); 

1578     printf("Use, duplication or disclosure is subject to\n"); 

1579     printf("restrictions stated in Contract with Western\n"); 

1580     printf("Electric Company, Inc.\n"); 

1581 

1582     maxmem = min(maxmem, MAXMEM);

1583     mfree(swapmap, nswap, swplo); 

1584 

1585     /* 

1586     * set up system process, 프로세스 0 생성

1587     */ 

1588 

1589     proc[0].p_addr = *ka6;     

1590     proc[0].p_size = USIZE; 

1591      proc[0].p_stat = SRUN;

1592     proc[0].p_flag =| SLOAD|SSYS;     // SSYS : 시스템 프로세스, 스와프아웃의 대상이 되지 않음

1593     u.u_procp = &proc[0]; 

1594 

1595     /*

1596     * determine clock, 클록장치 초기화

1597     */ 

1598 

1599     UISA->r[7] = ka6[1]; /* io segment */        // 사용자 APR7에 커널 APR7 값을 설정 => fuiword()가 I/O 영역에 접근할 수 있도록 설정

1600    UISD->r[7] = 077406; 


// CLOCK1 : 전원주파수 클록 레지스터의 어드레스

// CLOCK2 :  프로그래머블 클록 자아치의 레지스터의 어드레스


< CLOCK, ken/main.c >

#define CLOCK1    0177546

#define CLOCK2    0172540


1601     lks = CLOCK1;                         

1602     if(fuiword(lks) == -1) {     // CLOCK1에 대해 fuiworkd()를 수행

1603         lks = CLOCK2;             // 실패하면 CLOCK2에 재수행

1604         if(fuiword(lks) == -1) 

1605             panic("no clock");     // CLOCK1, CLOCK2 둘 다 실패하면 pannic()으로 실행 중지

1606     } 

1607     *lks = 0115;     // 초기값이 왜 뒤에있을까.. 미리 설정되어있어야 하는게 아닐까? 전역변수 같은데 딴데서 먼저 했나보네~~

1608 

1609    /* 

1610     * set up ’known’ i-nodes, 자원 초기화

1611     */ 

1612 

1613     cinit(); 

1614     binit(); 

1615     iinit(); 

1616     rootdir = iget(rootdev, ROOTINO); 

1617     rootdir->i_flag =& ~ILOCK; 

1667     while(nt >= 128) { 

1618         u.u_cdir = iget(rootdev, ROOTINO); 

1619         u.u_cdir->i_flag =& ~ILOCK; 

1621         /* 

1622         * make init process             , 프로세스 1 생성

1623         * enter scheduling loop 

1624         * with system process 

1625         */ 

1626 

1627         if(newproc()) {         // proc[1]을 생성


//  proc[1]의 데이터영역의 어드레스 0에 inode[]를 복사하고 리턴

//

1628             expand(USIZE+1);             

1629             estabur(0, 1, 0, 0); 

1630             copyout(icode, 0, sizeof icode);   

1632             * Return goes to loc. 0 of user init 

1633             * code just copied out. 

1634             */ 

1635             return;     // return 되면 main()을 실행했던 위치로 돌아가서 값을 스택에 쌓고, rtt 명령을 실행

// rtt명령 : 스택의 처음부터 pc에 0, PSW에 0170000을 읽음

// 현모드, 이전모드가 사용자 모드 상태이며, 사용자 공간의 어드레스 0부터 명령이 실행

// 어드레스 0에 icode[]가 복사되어 있기 때문에 /etc/init을 실행하여 처리

1636         } 

1637         sched();         // proc[0]이 실행하여, 스와핑 대상이 없으므로 proc[0]은 sleep하고 제어권은 proc[1]로 이동

1638     } 

1639 /* ------------------------- */





### 14.1.3 /etc/init


* 사용자 프로그램, 자세한 내용은 UPM(8) 참조


1. 등록된 터미널에 대한 프로세스를 생성

2. 각 프로세스는 터미널의 다이얼 업 접속, 사용자의 로그인을 기다림. 

사용자가 로그인하면 쉘 프로그램을 실행

3. /etc/init는 이후 무한 루프로 들어가서 프로세스 처리를 계속


> 스케줄러는 sched(), switch() 실행을 계속 수행

> /etc/init : 등록된 터미널에 대응하는 프로세스를 생성하고 고아 프로세스의 처리 루프를 계속 수행

> 각 터미널에 대응하는 프로세스 터미널의 다이얼 업 접속과 사용자의 로그인을 기다림







'System > Linux Kernel' 카테고리의 다른 글

커널에서 원하는 값을 가지고오기 위해 clz를 하는 이유  (0) 2016.01.16
system(), fork()  (0) 2015.12.24
Device Tree, 리눅스 커널 4.0  (0) 2015.08.29
메모리관리  (0) 2015.08.18
인터럽트 / 트랩  (0) 2015.08.16

KLDP 등 여러 리눅스 커뮤니티에 공지를통해서

커널연구회라는 곳에서 세미나를 주최하여 진행하였음.



일시 : 2015.08.29(토) 14:00 ~ 17:00

내용 : Device Tree,  커널 4.0 포팅


1. 소개

- 강사소개 및 출판서적

커널연구회, 정재준대표님


Dedvice Tree 상세분석 in Linux Kernel 4.0


- 3.2커널이후부터는 디바이스 트리가 규약화 됨

- 디바이스 트리란? 디바이스 트리의 스크립트 부분만 수정하여(전체 커널소스는 수정하지 않아도됨) 다시 컴팡리하면 많은 하드웨어 디바이스를 지원이 가능하게하는 일종의 규약으로 탄생


- 임베디드 작품들 구경 및 설명



2. 컴퓨터 아키텍쳐


# 8bit microprocessor (AVR ATmega)

- Block Diagram of the AVR MCU Architecture


- 8bit 레지스터 * 32개

- 8bit : op + op1 + op2

   ex. + 001   01      01


- program memory map, data memory map, 

- the pararrel instruction fetches and instruction executions

- single cycle ALU Operation

- on-chip data sram access cycles

- Clock Distribution






# ARM cortex 제품 라인업

- cortex-A : s/w 위주 위주로 개발할 때 

- cortex-R & M  : h/w  위주로 개발할 때


# 32bit Architecture 

: 2^32 = 4 GB



32bit Architecture Memory Map


# 2^64 = 1024 * 1024 * ...... * 2^4 = ??GB


# ARM Cortex-M (32bit)


참고하기. http://lifeseed.tistory.com/m/post/60



3. 리눅스 커널 소스

- 2.6..21~ : task_struct 구조체, Linked-list(pointer), 라운드로빈, RTS 알고리즘

-  2.6.35~ : CFS 자료구조, 레드블랙트리 알고리즘


# 소스 다이어그램

- linux kernel map : http://www.makelinux.net/kernel_map/

- kernel diagram : http://www.makelinux.net/kernel/diagram





- system

- networking

- storages, file system

- memory

- processing

- human interface



# 커널 자료구조

- Device Tree : /proc/device-tree

/arch/...

/devices/...

/net/...

/mm/...

/devices/...

/fs/...


http://ssup2.iptime.org/wiki/Device_Tree


# 커널 4.0 포팅하는 방법


- GIC : 분산처리해주는...

- DMC 


http://forum.falinux.com/zbxe/index.php?document_srl=613440&mid=lecture_tip

<디바이스 트리>

- 타겟보드로 컴파일을 진행할땐 uboot로 진입해야함

- fastboot로 실행을 시킴

- 각 파티션으로 나누어져 있고 해당부분에 올려서 크로스컴파일로 진행

- root권한으로 진행

- DTB, DTC, DTS,
http://forum.falinux.com/zbxe/?document_srl=589850&mid=lecture_tip&page=3

http://forum.falinux.com/zbxe/?mid=lecture_tip&l=ru&document_srl=589850



<커널>

- ubuntu 버전에서

kernel.org에서 리눅스 소스를 받으면 됨 
    https://www.kernel.org/pub/linux/kernel/v4.x/

- "make" 컴파일




"make build"  

https://kldp.org/node/133775

http://mintnlatte.tistory.com/429

https://www.gnu.org/software/make/


Ramdisk

buildroot : http://buildroot.org/


* logic analizer

https://www.saleae.com/downloads



'System > Linux Kernel' 카테고리의 다른 글

system(), fork()  (0) 2015.12.24
[Unix V6] 시스템 부팅  (0) 2015.12.19
메모리관리  (0) 2015.08.18
인터럽트 / 트랩  (0) 2015.08.16
VFS, Virtual File System  (0) 2015.08.16


# 가상메모리



# SMP (Symmetric Multiprocessing)

: 모든 CPU가 메모리와 입출력 버스 등을 공유하는 구조

=> 병목현상 발생


# NUMA (Non-Uniform Memory Access)

: SMP 구조에서 병목현상이 발생하여 CPU들을 몇개의 그룹으로 나누고 각 그룹에게 별도의 지역 메모리를 할당

<-> UMA (Uniform Memory Access)



# Node 

: 리눅스에서 뱅크를 표현하는 구조

- bank : 리눅스에서 접근 속도가 같은 메모리의 집합을 부르는 말

- ~/include/linux/mmzone.h


- UMA구조에서는 뱅크가 한개, NUMA 구조에서는 뱅크가 여러개

- 리눅스의 전역변수인 contig_page_data변수로 뱅크에 접근 가능

- NUMA처럼 뱅크가 복수개인 경우, pgdat_list라는 배열을 통해 뱅크에 접근이 가능


=> 리눅스에서는 하드웨어 시스템에 관계없이 노드라는 일관되 자료구조를 통하여 전체 물리메모리에 접근이 가능



# pg_data_t 자료구조

: UMA구조에서 단일노드를 contig_page_data변수로, NUMA구조에서 복수노드를 pgdat_list 배열로 가리켜도

 두 변수는 pg_data_t 구조체를 통해 표현


------------------------------------------------------------------------------------------------------------------------------------------------------------

typedef struct pglist_data {

struct zone node_zones[MAX_NR_ZONES];        // zone 구조체를 담기위한 배열

struct zonelist node_zonelists[GFP_ZONETYPES];    

int nr_zones;        // zone의 개수를 저장

...

unsigned log node_start_pfn;        // 해당 물리메모리가 메모리 맵의 번지수를 저장하는 변수

unsigned long node_present_pages;    // 해당 노드에 속해있는 물리메모리의 실제 양을 저장하는 변수

unsigned log 

...

} pg_data_t;

------------------------------------------------------------------------------------------------------------------------------------------------------------


* 물리메모리 할당 요청시 태스크가 수행되고있는 CPU와 가까운 노드에서 메모리 할당을 시도



# zone

: 일부 ISA 버스 기반의 디바이스를 지원하기위해, node의 일부분(16MB이하 부분)을 따로 관리할 수 있도록 자료구조를 만듬

(물리메모리 중 반드시 16MB 이하 부분을 할당해 주어야 했음)

- ~/include/linux/mmzone.h

- 동일한 속성을 가짐

- 다른 zone의 메모리와는 별도로 관리되는 메모리 집합

- ZONE_DMA, ZONE_DMA31 : 특별히 관리되는 16MB 이하의 메모리

(16MB 이상의 메모리는 ZONE_NORMAL이라고 함)

- ZONE_HIGHMEN : 1GB이상의 메모리를 필요로하는 경우 바로 커널의 가상주소공간과 1:1로 연결해주는 것은 비효율 적이라고 판단하여 

896MB의 물리메모리만 커널의 가상주소공간과 1:1로 연결하고, 나머지 부분은 필요할 때 동적으로 할당하는데,

이때 896MB 이상의 메모리 영역을 일컫는 용어


- 모든 시스템에서 언제나 DMA. NORMAL, HIGHMEN이라는 세개의 zone이 존재하는 것은 아님


- 각각의 zone은 자신에게 할당된 물리메모리의 관리를 위해 zone 구조체를 사용

해당 zone에 속해있는 물리 메모리의 시작주소, 크기

버디할당자가 사용할 free_area 구조체를 담는 변수 등등

- watermark와 vm_stat를 통해 남아있는 빈 공간이 부족한 경우 적절한 메모리 정책을 결정

- page가 부족하여 메모리 할당 요청에 대하여 실패한 경우 프로세스들을 wait_queue에 넣고 hashing을 수행하여 wait_table변수가 가리키게 함

- cat /proc/zoneinfo 명령어를 통해 확인



# Page Frame

: 물리메모리의 최소 단위

- zone은 자신에게 속한 물리메모리를 관리

- 각각의 페이지 프레임은 page 구조체로 관리 (~/include/linux/mm_types.h)

- 페이지 프레임 당 하나의 page 구조체가 존재. (모든 물리메모리에 접근이 가능해야하므로)


- page frame : 하나의 페이지로 관리

- zone : 복수개의 페이지 프레임으로 구성

- node : 하나 또는 복수개의 node로 구성

- 리눅스의 전체 물리 메모리 : 하나 또는 복수개의 node 


# Buddy와 Slab

- 내부 단편화문제를 해결하기 위해 슬랩할당자 사용

- 메모리관리의 부하와 외부 단편화의 해결을 위해 버디할당자 사용


* 물리메모리는 설정한 페이지프레임의 최소단위로 할당

(기본 4KB, 8KB와 2MB 등으로도 설정이 가능)



# Buddy Allocator

- 페이지프레임이 4KB의 경우 10KB를 할당하려할 때 3개의 페이지프레임으로 할당하지 않고 16KB를 할당        

=> 메모리관리의 부하를 줄이고 외부 단편화를 방지


* 커널 2.6.19버전 이전에서 사용되던 버디 


- zone 구조체에 존재하는 free_area[]배열을 통해 구축

- zone 당 하나의 버디가 존재

- free_area[] 배열의 각 엔트리는 free_area 구조체

- free_area 구조체는 free_list와 map이라는 필드를 가짐


------------------------------------------------------------------------------------------------------------------------------------------------------------  

/* ~/include/linux/mmzone.h  */

#define    MAX_ORDER    10        // 10개의 엔트리를 가짐. 0~9의 각 숫자는 해당 엔트리의 free_area가 관리하는 할당의 크기를 나타냄

// 0인경우 2^0으로 1개의 페이지프레임 할당, 1인경우 2^1이므로 2개의 페이지프레임 할당 

// 4KB, 8KB, 16KB... 4MB(2^10 * 4KB) ---> 이 단위들로 메모리 할당이 가능

struct zone {

...

struct free_area    free_area[MAX_ORDER];    // 

...

};

struct free_area {                

struct list_head    free_list;      // 자신에게 할당된 free 페이지 프레임을 list로 관리

// ex. free_list[1]에 free상태의 연속된 2개의 페이지 프레임들이 free_list로 연결

unsinged long     *map;         // 자신이 관리하는 수준에서 페이지의 상태를 bitmap으로 관리

// ex. 전체 물리메모리를 2개의 페이지 프레임 단위로 봤을 때의 상태를 map이라는 bitmap에 저장

};

------------------------------------------------------------------------------------------------------------------------------------------------------------  



그림 출처. https://lwn.net/Articles/121618/




* order(0) -> free_area[0]

  order(1) -> free_area[1]

  ...


* 버디할당자 동작방식

Linux kernel physical memory allocator (Buddy) - Part 2-1

http://woodz.tistory.com/57


http://woodz.tistory.com/58

http://woodz.tistory.com/59

http://woodz.tistory.com/60




# Lazy Buddy

- 커널 2.6.19부터는 free_area 구조와 버디 할당자의 구현이 조금 바뀐

- 프레임에 할당하거나 해제하는 작업에서 페이지를 쪼개거나 합치는데 이럴 때 비트맵 수정도 필요함

- 반복 과정에서 오버헤드가 발생

- 페이지프레임에 대한 작업을 조금 미루자!


 *변경된 free_area 구조체

------------------------------------------------------------------------------------------------------------------------------------------------------------

/* ~/include/linux/mmzone.h  */

#define    MAX_ORDER    11


struct zone {

...

struct free_area    free_area[MAX_ORDER];    // 

...

};


struct free_area {                

struct list_head    free_list;      

unsinged long    nr_free;    // 기존의 비트맵 포인터에서 자신이 관리하는 zone내에서 비사용중인 페이지 프레임의 갯수를 저장하는 변수로 바뀜

};

------------------------------------------------------------------------------------------------------------------------------------------------------------

- zone 마다 유지되고 있는 watermark(high, low, min)값과 현재 사용가능한 페이지 수를 비교

- zone에 가용 메모리가 충분한 경우 해제된 페이지의 병합 작업을 최대한 뒤로 미룸

- 가용 메모리가 부족해지는 경우 병합작업을 수행


* 병합작업

- __free_pages(), 버디에 메모리를 반납하는 함수

- __free_pages()함수는 내부적으로 __free_one_page()라는 함수를 호출

- __free_one_page(), MAX_ORDER만큼 루프를 돌면서 현재 해제하는 페이지가 버디와 합쳐져서 상위 order에서 관리될 수 있는지 확인

- 가능하면 현재 order의 nr_free를 감소시킴

, 상위로 페이지를 이동 후 상위 order의 nr_free를 증가  

=> 해당 작업을 반복하여 전체 order의 버디를 동작


- __alloc_pages() : 버디 할당자로부터 페이지를 할당받는 커널 내부 함수 중 가장 저수준의 함수

- __free_page() : 페이지를 해제하는 함수


- 2의 승수의 크기 단위로 관리하므로 함수 호출시에도 메모리의 크기를 2의 승수로 지정

- 복수개의 zone에 각각의 버디 할당자가 동작할 수 있는 상황에서는 어느 zone에서 메모리를 할당 받았는지 같은 몇몇 속성을 지정해 주어야 함

- 현재 시스템의 버디 할당자 관련 정보 조회 : "$ cat /proc/buddyinfo"



# Slab Allocator

일종의 캐시의 집합을 통하여 메모리를 관리하는 정책


- 페이지 프레임의 크기가 요청되는 메모리의 크기와의 차이가 상대적으로 많이 날 수록 내부 단편화로 낭비되는 공간이 증가

- 미리 페이지 프레임을 할당 받은 후 일정한 크기로 분할 해 둔 뒤 사용자가 메모리를 요청하면 버디할당자가 아닌 미리 할당받아 분할한 이 공간(일종의 캐시)에서 공간을 받아옴

- 해제 역시 중간의 이 공간에 이루어짐


- 현재 시스템의 slab 할당자와 관련된 정보조회 : "$ cat /proc/slabinfo"


출처. http://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/9_VirtualMemory.html



- 캐시의 크기? 




 


'System > Linux Kernel' 카테고리의 다른 글

[Unix V6] 시스템 부팅  (0) 2015.12.19
Device Tree, 리눅스 커널 4.0  (0) 2015.08.29
인터럽트 / 트랩  (0) 2015.08.16
VFS, Virtual File System  (0) 2015.08.16
리눅스 부팅과정과 런레벨  (0) 2015.08.13



# 인터럽트 

: 주변장치나 CPU가 자신에게 발생한 사건을 리눅스 커널에 알리는 매커니즘


- 외부 인터럽트. 하드웨어적 인터럽트 (인터럽트)

- 소프트웨어적 인터럽트 (트랩, 예외처리라고도 함)


# 인터럽트 핸들러의 수행

- 인터럽트 발생

- PC(or instruction pointer) 레지스터값을 미리 정해진 특정 번지로 설정

ex. ARM 

0x00000000 + offset로 점프

- reset interrupt : offset은 0

- undefined instruction : offset은 4

- software interrupt : offset은 8


# 인터럽트 백터 테이블

: 인터럽트는 간결히 작성해도 4Byte를 넘기때문에 다른위치에 인터럽트 핸들러를 작성하고 0x00000000에는 인터럽트 핸들러로 점프하는 명령어만 기록

     

ex. ARM CPU의 인터럽트 백터 테이블

--------------------------------------------------------------

0x00000000    _start :        b        reset

b        undefined_instruction

b        software_interrupt

b        prefetch_abort

b        data_abort

b        not_used

b        IRQ

b        FRQ        

--------------------------------------------------------------

- 보통 IDT(Interrupt Descriptor Table) 또는 IVT(Interrupt Vector Table)이라고 부름


# 인터럽트/트랩의 처리

: 문맥저장->인터럽트처리->문맥복원


- 리눅스에서는 인터럽트와 트랩을 동일한 방법으로 처리

- 외부인터럽트/트랩을 처리하기 위한 루틴을 함수로 구현

- 각 함수의 시작주소를 리눅스의 IDT인 idt_table이라는 이름의 배열에 기록

- 다양한 CPU를 지원하기위해 idt_table의 0~31까지 32개를 트랩핸들러를 위해 할당, 그 외의 엔트리는 전부 외부 인터럽트 핸들러를 위해 사용

- 외부 인터럽트를 발생할 수 있는 주변장치는 하드웨어적으로 PIC(Program-mable Interrupt Controller)라는 칩의 각 핀에 연결

- PIC는 CPU의 한 핀에 연결

- x86 CPU의 경우, idt_table의 32번 부터  PIC로 사용이 가능(31까지는 트랩이 사용하므로)

- 리눅스 커널 부팅중에 설정


ex. idt_table의 32번 엔트리에 timer 인터럽트 발생 (가정)

- timer는 PIC와 연결된 선에 펄스를 보냄

- PIC는 수신한 펄스를 적절한 번호로 변환

- I/O 포트에 저장하여 CPU가 버스를 통해 읽을 수 있도록 함

- CPU와 연결된 라인에 펄스를 보내 외부인터럽트 발생을 알림

- CPU가 인터럽트 발생을 알게되어 PIC의 I/O 포트를 읽어 발생한 외부인터럽트의 벡터번호를 확인

- 인터럽트 선을 원래대로 복원시켜 PIC가 다른 인터럽트를 받을 수 있게 함

- 리눅스 커널은 발생한 인터럽트의 번호를 확인

- 이 번호로 idt_table에 인덱싱을 하여 엔트리에 있는 핸들러를 실행


- x86 CPU에서의 idt_table


그림 출처. http://duksoo.tistory.com/entry/System-call-%EB%93%B1%EB%A1%9D-%EC%88%9C%EC%84%9C



# irq_desc table

: 외부 인터럽트가 발생되어 들어오는 라인은 한정되어 있으며, 디바이스 드라이버들은 동적으로 인터럽를 동적으로 할당받거나 해제할 수 있음.

따라서 별도의 관리 매커니즘이 필요. 


- idt_table의 32~255까지(128번 제외, 시스템 호출이 사용)를 같은 인터럽트 핸들러 함수가 등록

- 해당 함수들은 do_IRQ()를 호출

- do_IRQ() : 외부 인터럽트 번호로 irq_des 테이블을 인덱싱하여, 해당 인터럽트 번호와 관련한 irq_desc_t자료구조를 탐색

- irq_desc_t : 하나의 인터럽트를 공유할 수 있도록 action이라는 자료구조의ㅏ 리스트를 유지

- action : 이 리스트를 통해 단일 인터럽트 라인의 공유가 가능


# 문맥저장


- idt_table에 등록되어있는 common_interrupt (외부 이너럽트를 위한 공통 핸들러)

-----------------------------------------------------------------------------------------------------------------------------------

# define  SAVE_ALL     \

cld;    \

pushl    %es;    \

pushl    %ds;    \

pushl    %eax;    \

pushl    %ebp;    \

pushl    %edi;    \

pushl    %esi;    \

pushl    %edx;    \

pushl    %ecx;    \

pushl    %ebx;    \

novl    $(___USER_DS),    %edx;    \

novl    %edx,    %ds;    \

novl    %edx,    %es;


common_interrupt:

SAVE_ALL                    // 인터럽트가 발생한 시점에 수행중이던 태스크의 문맥 저장

call    do_IRQ                // do_IRQ() 함수를 호출하여 실제 인터럽트 서비스가 수행

jmp ret_from_intr         // 인터럽트 처리가  종료되면 SAVE_ALL 매크로로 저장했던 문맥을 RESTORE_ALL 매크로를 통해 복원

-----------------------------------------------------------------------------------------------------------------------------------



# 리눅스에서 트랩의 처리

- 트랩은 구분이 필요함

1. fault : fault를 일으킨 명령어 주소를 eip에 저장 후 해당 핸들러 종료 후 eip에 저장되어있는 주소부터 다시 수행

2. trap : trap을 일으킨 명령어의 다음 주소를 eip에 저장 후 해당 핸들러 종료후 다시 수행

3. abort : 심각한 에러. eip에 값을 저장할 필요가 없고 현재 태스크를 강제 종료


-  ret_from_exception()

: 시스템 콜을 제외한 트랩의 경우 ret_from_exception()을 호출하여 이전 문맥으로 돌아감

- ret_from_intr()

: 일반적인 외부 인터럽트의 경우 해당함수를 호출하여 이전 문맥으로 돌아감

- ret_from_sys_call()

: 0x80 인터럽트, 즉 시스템 콜의 경우

- ret_from_fork() 

: 시스템콜 중 fork(), vfork(), clone()의 경우



# 시스템 호출 처리과정 (intel CPU의 경우로 가정)

그림 출처. http://duksoo.tistory.com/entry/System-call-%EB%93%B1%EB%A1%9D-%EC%88%9C%EC%84%9C


- fork() 시스템 콜 호출

- /usr/lib/libc.a 표준 C 라이브러리에 구현되어있는 fork() 라이브러리 함수 호출

- CPU내의 범용 레지스터 중 eax 레지스터(ARM CPU의 경우 r7 레지스터)에 fork() 함수에 할당되어 있는 고유한 번호인 2를 저장

- 0x80인자(시스템콜)로 int명령으로 트랩을 발생시킴. (ARM CPU의 경우 swi 명령어)

- 트랩 발생 후 커널로 제어 이동

- 문맥저장 후 트랩의 번호(0x80으로 가정)에 대응되는 엔트리에 등록되어있는 함수(0x80이므로 sys_call())를 호출

- sys_call()에서 eax의 값을 인덱스(여기에서는 2)로 sys_call_table을 탐색하여 sys_fork()함수의 포인터를 얻어옴

sys_call() : arch/x86/kernel/의 entry_32.S 또는 entry_64.S에 구현

sys_call_table : arch/x86/kernel/의 syscall_32.c 또는 sysscall_64.c에 구현


=> 사용자 응용단에서 fork() 시스템 콜 호출 후 IDT 테이블과 sys_call_table을 이용해 커널에서 구현된 sys_fork()함수 호출



# 시스템 콜에 할당되어있는 고유번호 찾기(Intel CPU 기준)

- 리눅스 커널에서 제공하는 모든 시스템콜은 고유한 번호를 가짐

- ~/arch/x86/syscalls/syscall_64.tbl 또는 syscall_32.tbl에 정의

- 총 317개

- read()는 0, write()는 1, open()는 2



# 시스템 호출 함수 구현


1. 사전 등록처리, 시스템 호출 번호 할당

- ~/arch/x86/kernel/syscalls/syscall_64_tbl 파일에 새로운 번호를 할당

- 시스템 호출 테이블에 새로운 시스템 호출 처리 함수를 등록

- 할당한 번호를 인자로 sys_call_table이 접근될 때 호출할 함수를 등록

- ~/include/linux/syscalls.h파일에 sys_newsyscall 함수 원형을 등록


2. 시스템 호출 함수 구현

- 태스크관리관련 : kernel/ 디렉터리, 파일시스템 관련 : fs/ 디렉터리

- sys_ 접두어 사용

- asmlinkage : C로 구현된 함수가 어셈블리 언어로 구현된 함수에서 호출 할 수 있도록 해주는 키워드 

  -> 인텔 CPU에서는 특별한 기능은 없으며 알파 CPU의 경우 어셈블리 언어에서 C로 구현된 함수를 호출할 때 몇가지 전처리 작업을 수행함

- 커널에서 수행되는 함수이므로 표준 C라이브리를 사용할 수 없음


3. 커널컴파일 수행

4. 재부팅


* 시스템 호출 함수를 kernel/newfile.c 이라는 새로운 파일에 구현하였으면, 

make 명령이 컴파일 할 때 이 파일도 함께 컴파일할 수 있도록 해야함.

-> kernel/Makefile 아래에 해당 내용을 추가


* syscall() : 인자로 시스템콜의 번호를 받아 해당 시스템콜을 호출해주는 매크로



* 라이브러리를 이용한 시스템 호출 함수 구현 : ar 명령어를 사용하여 라이브러리 만들 수 있음.


* Glibc 라이브러리 ?

- 리눅스 배포판이 설치될 때 기본적으로 설치되는 라이브러리 중 하나

- fork(), open() 등의 함수를 호출하게 해주는 라이브러리

- 위에서 말한 syscall()도 해당 라이브러리에 구현되어 있음


# 인자를 전달하는 시스템 호출

--------------------------------------------------------------------------------------------------------------------------------------

// system call 번호를 318로 등록


#include<linux/unistd.h>

#include<linux/kernel.h>

#include<asm/uaccess.h>

asmlinkage int sys_show_mult(int x, int y, int* res)     // 앞의 2개의 인자를 곱하여 결과를 3번째 인자로 넘김

{

int error, comute;

int i;

error = access_ok(VERIFY_WRITE,res,sizeof(*res));    // access_ok() : res라는 사용자 공간에 쓰기가 가능한지 체크

if(error < 0)

{

printk("error in cdang \n");

printk("error is %d \n", error);

return error;

}

compute = x*y;        // current 포인터 변수 : 현재 실행중인 task_struct

printk("compute is %d \n", compute);

i = copy_to_user(res,&compute,sizoeof(int));    // copy_to_user() 매크로 : 

return 0;                                                    //     include/asm/uaccess.h에 정의. 값을 사용자 수준 공간에 전달하기위해 복사

}



// 호출

int main(void) 

{

...

i=syscall(318,x,y,&mult_ret);

...

}

--------------------------------------------------------------------------------------------------------------------------------------



- 시스템 콜의 매개변수는 레지스터의 크기인 32 혹은 64 bit을 넘을 수 없음

- 레지스터의 개수가 제한적임(인텔 CPU의 경우 6개를 넘을 수 없음)

=> 구조체 사용


- kmalloc() : C 라이브러리 함수인 malloc()과 유사하며 커널 내부함수로써 할당 받는 공간은 물리적으로 연속된 공간을 보장




참고

리눅스 커널 내부구조(책)



'System > Linux Kernel' 카테고리의 다른 글

Device Tree, 리눅스 커널 4.0  (0) 2015.08.29
메모리관리  (0) 2015.08.18
VFS, Virtual File System  (0) 2015.08.16
리눅스 부팅과정과 런레벨  (0) 2015.08.13
Linux File System  (0) 2015.08.13


# 사용자의 task에서 file system으로의 접근
: open(), read(), write(), close(), ... 호출

# POSIX 표준 시스템
: Portable Operating System Interface. 서로 다른 UNIX OS의 공통 API를 정리하여 이식성이 높은 유닉스 응용 프로그램을 개발하기 위한 목적으로 IEEE가 책정한 애플리케이션 인턴페이스 규격.  
-> https://ko.wikipedia.org/wiki/POSIX

- 운영체제와 관련하여 IEEE에서 만들 규약
- UNIX를 고려하여 만들어졌기 때문에 X를 붙임임
- OS들의 호환성을 고려함.
- 시스템콜, 프로세스 환경, 파일/디렉터리, 시스템 데이터베이스, tar압출 포맷 등을 다룸

# VFS
Virtual File System
- POSIX 표준 시스템 호출을 이용
- 파일시스템과 사용자 태스크 사에에 가상층을 도입.
- 인자에 담겨있는 파일의 이름을 보고 파일을 관리하고있는 파일시스템이 무엇인지 판단.
- 해당 파일시스템의 함수를보고 해당하는 함수를 호출.
- 함수로부터 결과를 리턴받아 사용자 태스크에게 전달.

-> VFS를 통해 리눅스에서 다양한 파일시스템을 지원
- UFS, 유닉스 파일시스템
- ext2(3), 리눅스 기본 파일시스템
- NFS(Network File System), SUN에서 개발한 네트워크 파일시스템
- LFS(Log Structured File System), small write에 좋은 성능을 제공하는 파일 시스템
- CODA, CMU대학에서 개발하였으며 disconnected 연산 기능을 제공하는 파일시스템
- iso9660, CD를 위한 파일 시스템
- msdos, VFAT, MS의 DOS 파일 시스템
- 윈도우 NT 파일 시스템
- proc, 커널의 내부 상태를 볼 수 있는 파일 시스템
- sysfs, 장치를 통합 관리하는 파일 시스템

그림 출처. http://e2fsprogs.sourceforge.net/ext2intro.html


# VFS 동작 원리
: 예시. ext2 file system, /dev/hda2, b.txt

- 사용자 태스크가 b.txt라는 인자로 open()시스템 콜을 호출
- VFS가 b.txt의 정보를 저장하기위해 구조체를 만듬
- 생성한 구조체를 인자로 ext2 파일시스템 내부의 open()함수를 호출
- ext2는 자신의 inode table에서 b.txt의 inode를 찾아 해당 정보를 인자로 받은 구조체에 저장하여 리턴
- VFS는 리턴받은 구조체의 내용을 바탕으로 사용자 태스크에게 필요한 정보를 전달

# VFS의 4가지 객체
: VFS에서 다양한 파일시스템과의 호환을 위해 사용하며 사용자 태스크에게 제공할 일관된 인터페이스를 정의

1. 수퍼블럭 객체
: 파일시스템 자신이 관리하는 파티션에 파일시스템 마다 고유한 정보를 수퍼블록에 저장. 이를 관리하기위해  VFS에서 수퍼블럭 객체라는 범용적인 구조체를 정의
- 현재 마운트 되어 사용 중인 파일시스템당 하나씩 주어짐

2. 아이노드 객체
: 특정한 파일과 관련한 정보를 저자하기위해 정의된 구조체
- 파일에 대한 메타데이터 정보를 저장하기 위해 아이노드객체를 생성하고 파일시스템에 특정파일에 대한 정보를 요청하면
  파일 시스템은 자신의 관리영역에서 해당 정보를 아이노드 객체에 저장
- ext2의 경우 해당 파일의 디렉터리 엔트리와 inode를 찾아서 아이노드 객체에 저장
- msdos의 경우 해당 파일의 디렉터리 엔트리를 읽어서 아이노드 객체에 저장

3. 파일 객체
: 태스크가 open한 파일과 연관되어 있는 정보를 관리하기 위해 사용하는 구조체
- 2개 이상의 태스크가 하나의 파일에 접근할 때, 각각의 offset등과 같은 정보를 관리해야함
- 태스크 관련 정보를 유지하는 용도로 파일 객체를 사용
- 각 태스크가 아이노드 객체에 접근하는 동안만 메모리상에 유지

4. 디엔트리 객체
: 사용자 태스크가 파일에 접근하게 하기위해 아이노드 객체와 파일객체의 연결이 필요, 이때 빠른 연결을 위해 캐시역할을 수행하는 객체
   

# task_struct

: 프로세스는 자신이 사용하는 자원, 자원에서 수행되는 수행흐름으로 구성(resource + flow of control). 이를 관리하기 위해 각 프로세스마다 생성하는 자료구조.

- 프로세스, 스레드 마다 생성, 수행 이미지 공유여부 및 스레드 그룹정보를 통해 구분

- 리눅스에서는 프로세스와 쓰레드 모두 커널내부에서 태스크로 관리


fork(), clone(), pthread_create()     -->     sys_clone()     -->    do_fork()    ,task_struct

vfork()                                            -->     sys_vfork()     -->    do_fork()    ,task_struct


cf. task_struct 구조체 내부 필드 중

- pid : 태스크 별로 유일한 값

- tgid : 한 프로세스내의 쓰레드는 동일한 PID를 공유해야한다는 POSIX 표준에 따라 리눅스에서는 Thread Group ID라는 개념을 도입


- files : file_struct라는 자료구조를 가리킴(file_struct의 max_fds : 한 태스크가 오픈할 수 있는 파일의 최대 갯수를 나타내는 변수)

- fd_array : file_struct구조체의 file이라는 자료구조에 대한 포인터를 갖는 배열

유닉스 계열의 운영체제에서 일반적으로 fd, file descriptor라고 부름

fd는 함수의 리턴값을 받는 변수로, fd_array에서 해당되는 인덱스로 사용됨

일반적으로 fd_array[0]은 표준입력(stdin), fd_array[1]은 표준 출력(stdout), fd_array[2]는 표준 에러출력(stderr)으로 설정


# fd_array 

: task_struct의 files변수가 가리키는 file_struct구조체내의 값으로 fd_array의 각 값들은 파일 객체를 가리킴

- 유닉스 운영체제에서는 파일 테이블이라고 부름

- 사용자 태스크에게 fd라는 정수로 파일에 접근할 수 있도록 하는 추상화 계층을 제공하는 변수


- f_dentry : 디엔트리 객체를 가리킴(해당 디엔트리 객체는 다시 연결되어있는 아이노드 객체를 가리킴)

- f_pos : 현재 피일에서 읽거나 쓸 위치를 저장(처음 파일을 오픈하였을 때는 값이 0), lseek호출을 통해 f_pos값을 바꿀 수 있음

- f_op : file_operations라는 자료구조를 가리키는 포인터(8장) 

 

# file_operations와 inode_operations

- file_operations 구조체 : 가상적인 파일연산이 요청되면 커널에서는 요청된 파일의 유형정보 및 파일의 고유 함수를 사용하여 서비스를 제공해야하는데 이때 사용하는 구조

                                     각 파일 유형에 적합한 파일 연산들이 저장되는 변수


inode_operations 구조체 : 아이노드 객체에 있는 i_op 포인터 변수가 inode_operations를 가리킴
사용자가 create(), mkdir() 등 파일시스템의 메타데이터 관련된 연산을 요청하면,
커널은 요청한 연산이 어떤 파일시스템에서 발생하였는지 파악하고,
적절한 파일시스템의 고유한 함수를 사용하여 서비스를 제공하는데 이때 사용하는 구조체

각 파일시스템 유형에 적합한 파일시스템 연산들이 저장되는 변수


=> 리눅스가 다양한 파일과 파일시스템을 지원할 수 있는 비밀병기 



# task_struct와 VFS



그림 출처. http://www.redirfs.org/docs/thesis/


- 파일의 이름을 인자로 시스템콜을 호출

- VFS가 아이노드 객체를 인자로 파일시스템 내부의 해당 함수를 호출

- 필요한 정보를 아이노드 객체에 채운 후 리턴

- VFS는 해당 아이노드 객체를 디엔트리 객체에 연결시킨 후 사용자 태스크 구조와 연결



# f_op

: 파일시스템마다 구현된 함수들이 다른데, 해당되는 파일 유형에 맞는 연산이 등록되는 변수


예.  file -> f_op -> open()

- ext2 : ext2의 open(), linux/fs/ext2/file.c에 구현

- NFS : nfs_file_open()

- 파이프 : fifo_open()

- 장치파일 : chrdev_open() / blkdev_open(), linux/fs/device.c에 구현


# sys_open() 

- 특정파일 각각의 open()함수들의 호출 후 filp_open()함수 리턴

: 태스크에서 현재 사용하지 않는 fd_array의 한 항을 할당

- 해당 항이 생성된 파일 객체를 가리키도록 설정

- 태스크 구조와 VFS이 연결됨


# sys_read()함수 

: 인자로 전달된 fd를 이용해 파일 객체를 찾고 해당 f_op에 등록된 read함수를 호출, linux/fs/reead_write.c에 구현

- 우선 요청 데이터가 캐시에 있는지 찾음

- 캐시에 있으면 디스크에 안가고 바로 데이터를 사용자에게 전달, 없다면 디스크로 접근

- 이때 각 파일시스템은 서로 다른 방식으로 디스크를 관리하므로 각 파일시스템은 서로다른 디스크 연산함수를 사용하며 해당 처리가 필요함

-> 특정 파일시스템에 맞는 디스크 연산 함수를 호출할 수 있도록 inode_operations구조체를 사용

-> include/linux/fs.h에 정의

-> inode와 관련한 연산을 나타내는 변수로 구성(create, lookup, link, mkdir, mknod, readpage...)

-> 즉, 각 파일세스템에 고유한 연산들이 저장



# 파일의 사용과 파일시스템의 사용

- f_op와 i_op : 각 파일과 파일시스템에 고유한 연산을 제어를 전달하는 진입점 역할을 수행하는 변수

- 파일에 접근(새로운 장치를 위한 장치파일 연결)을 위해 디바이스 드라이버를 사용하여 새로운 file_operations 구조를 작성해 커널에 등록

- 파일시스템의 경우 file_operations구조 및 register_filesystem()이라는 커널내부함수를 사용하여 inode_operations구조도 작성하여 커널에 등록


# register_filesystem()

- linux/fs/filesystems.c에 구현

- struct_file_system_type 자료구조를 인자로 받음, include/linux/fs.h에 정의


<항목>

- name : 파일시스템을 나타내는 변수. ext2, ext3 ...

- fs_flags : 속성정보 저장 변수. 물리장치필요여부, 읽기전용여부...

- mount : 수퍼블록을 읽어 파티션을 마운트 하는 함수의 포인터 저장 변수

- 복수개의 file_system_type구조들의 연결을 위한 리스트와 모듈 정보 등

- ...


-  register_filesystem()으로 커널에 등록된 파일시스템은 하나의 file_system_type 자료구조를 가짐

- 커널의 존재하는 모든 file_system_type은 리스트로 연결

- file_systems라는 커널 내의 전역변수가 file_system_type리스트의 시작을 가리킴



# File System의 마운트 요청,

- file_systems에서 검색하여 요청된 file_system_type 자료구조 찾기

- get_sb에 기록된 함수를 호출하여 파일시스템의 수퍼블럭정보를 얻어옴

- 얻어온 수퍼블럭정보를 VFS의 수퍼블럭 객체에 저장

- 수퍼블럭을 읽어 해당 파일시스템의 자세한 정보를 얻어옴

- 이 자세한 정보로 inode_operations, file_operations에 접근이 가능



# VFS의 내부구조

그림 출처. http://www.read.cs.ucla.edu/111/2006fall/notes/lec14



그림 출처. https://www.usenix.org/legacy/event/usenix01/full_papers/kroeger/kroeger_html/node8.html



- 태스크는 시스템 콜 인터페이스로 VFS와 통신

- 태스크가 원하는 내용은 커널내부의 페이지캐시(캐시역할)을 통할수도 있음

- 캐시에 없다면 실제 디스크와 I/O 수행

- 이때 디엔트리 객체와 아이노드 객체를 위한 캐시를 일반데이터블럭을 위한 캐시공간과 분리하여 성능향상을 도모

- VFS내에 존재하는 객체의 연결관계를 이용해 inode_operations, file_operations 구조체의 함수를 호출

- 가상계층과 물리는 실제 디스크와 I/O하는 부분에서는

   커널내의 일반 블록 게층(Generic Block Layter)의 gendisk를 관리하는 블록 디바이스 드라이버에게 I/O 요청을 해야함

- 성능향상을 위해 리눅스는 자체적인 디스크 I/O 스케줄링 알고리즘(3가지 Elevator알고리즘)을 통해 요청을 보냄




참고. 

리눅스 커널 내부구조(책)





'System > Linux Kernel' 카테고리의 다른 글

Device Tree, 리눅스 커널 4.0  (0) 2015.08.29
메모리관리  (0) 2015.08.18
인터럽트 / 트랩  (0) 2015.08.16
리눅스 부팅과정과 런레벨  (0) 2015.08.13
Linux File System  (0) 2015.08.13

v6 책,



http://cafe.naver.com/linuxcare/3403


http://ttend.tistory.com/61


https://www.linux.co.kr/linux/tip/boot_sequence/


http://rootblog.tistory.com/1

'System > Linux Kernel' 카테고리의 다른 글

Device Tree, 리눅스 커널 4.0  (0) 2015.08.29
메모리관리  (0) 2015.08.18
인터럽트 / 트랩  (0) 2015.08.16
VFS, Virtual File System  (0) 2015.08.16
Linux File System  (0) 2015.08.13

Linux File Syetem에 대한 새로운 포스팅

http://jiming.tistory.com/359




# File Systme

: 보조기억장치를 관리하는 소프트웨어


---------------------------------------------------------------------------------------------

cf. 

# Memory Management System 

: 주기억장치 관리 소프트웨어


# File System 및 Memory Management System의 역할

: 자원을 최대한 아껴서 사용하기 위해 각각의 policy가지고 내/외부 단편화를 관리


# File System과 Memory Management System

: 둘다 기억장치를 관리하는 소프트웨어임

: 차이점? File System은 "Naming"이라는 특성을 사용하여 관리를 수행 

---------------------------------------------------------------------------------------------


# 디스크의 구조




# File System이 저장하는 정보

- meta data : 파일의 속성정보, 데이터블록의 인덱스 정보 등

- user data : 사용자가 실제 저장하려는 데이터


# 디스크의 전체 용량

; 헤드의 갯수, 트랙/실린더의 갯수, 각 트랙마다 존재하는 섹터의 갯수 등에 따라 용량등의 디스크의 물리적 특성이 결정


# 디스크 접근 시간

- seek time : 헤드를 요청한 데이터가 존재하는 트랙 위치까지 이동하는 데 걸리는 시간

- rotation latency : 요청한 섹터가 헤드 알래로 위치될 때까지 걸리는 시간

- transmission time : 헤드가 섹터의 내용을 일거나 쓰는 시간


# 디스크의 논리구조와 디스크 I/O

- 파일 시스템에서 디스크는 논리적 구조를 가짐

- 논리적 구조는 disk block의 집합으로 표현됨(각 블록은 논리적인 번호를 가짐)

- 일반적으로 디스크 블록의 크기는 페이지 프레임의 크기와 같음(보통 4KB)

- 또 디스크 I/O의 병목현상으로 최근에는 디스크 블록의 크기를 더 크게 함.

- 디스크블록의 크기가 4KB, 섹터의 크기가 512byte 일때. 하나의 디스크 블록에 8개의 섹터가 대응되므로 한번에 8개의 섹터가 읽혀짐

    (블록 디바이스 드라이버의 read_ahead 변수과 관련이 있음)

  => 블록의 번호와 해당되는 섹터들의 매핑의 관리는 디스크 디바이스 드라이버 or 디스크 컨트롤러가 담당함


# 디스크블록 할당방법

- used / free 

- 연속 할당(sequential allocation)

  : 연속할당기법을 사용하여 파일에게 디스크를 할당해 주었다면 파일의 크기가 커져 디스크의 용량이 모자를때 데이터 전체가 다른 연속된 공간으로

이동해야함.

- 불연속 할당(non-sequential allocation)

  : 각각의 파일에 대한 디스크 블록들의 위치정보를 저장해야함. -> 블록체인기법, 인덱스블록기법, FAT 등등


- 블록체인기법 : 각 블록에 포인터를 두어 다음 블록의 위치를 기록. 

파일의 끝을 읽으려는 경우 처음부터 찾아가야한다는 단점이 있음 

중간의 블록이 유실된 경우 나머지 데이터까지 모두 영향을 받음

-  인덱스 블록 기법 : 블록들에 대한 위치정보를 저장하기 위해 인덱스 블록을 따로 두는 방법

인덱스 블록이 유실되면 나머지 전체 데이터가 영향을 받음

또 인덱스 블록을 위한 별도의 공간과 인덱스 블록의 용량의 한계에대한 방법이 필요

파일마다 하나의 인덱스 블록이 존재

- FAT(File Allocation Table) : 같은 파일에 존재하는 블록들의 위치를 FAT이라는 자료구조에 저장

파일 시스템이 관리하는 공간 내에 전역적으로 존재하는 FAT 구조를 사용하여 데이터에 접근

파일 시스템 전체적으로 하나의 FAT이 존재

FF : 파일의 끝 / 0 : free 상태

FAT 구조의 유실은 파일시스템 내의 모든 파일에 영향을 미치므로 대부분의 FAT구조 파일시스템은 중복으로 FAT구조를 관리


# FAT File System


그림출처. http://www.recovermyfiles.com/fat-recovery.php



# FAT File System의 metadata


그림 출처. http://www.differencebetween.info/difference-between-fat32-and-ntfs



- FAT table

- directory entry

- super block



# msdos file system의 Directory Entry

: msdos의 file system은 대표적인 FAT방식의 file system임


- 각 파일마다 디렉터리 엔트리를 가짐

- 디렉터리 엔트리가 모여 디렉토리를 구성

- 리눅스에서 디렉터리는 하나의 파일로 취급(자신이 포함하는 파일들의 이름을 데이터로 가지는 특수한 파일)


struct msdos_dir_entry {


_u8    name[MSDOS_NAME];       /* name and extension 11 */

_u8    attr;                               /* attribute bits */

_u8    lcase;                             /* Case for base and extension */

_u8    ctime_cs;                        /* Creation time, centiseconds(0~199) */

_le16  ctime;                            /* Creation time */

_le16  cdate;                            /* Creation date */

_le16  adate;                            /* Last access date */

_le16  starthi;                           /* High 16 bits of cluster in FAT32 */

_le16  time,date,start;                 /* time, date and first cluster */ 

_le32  size;                              /* file size (in bytes) */

};



# CWD와 디렉터리 계층 구조

- CWD : Current Working Directory

- 리눅스는 사용자 태스크의 CWD를 항상 task_struct 구조체에 유지, 상대경로 -> 절대경로

- '/(root)' 디렉터리 엔트리를 먼저 읽어 해당 데이터 블록을 찾아, 디렉터리 엔트리를 읽어가며 접근을 원하는 파일의 경로로 찾아감

- '/(root)'의 디렉터리 엔트리의 번호는 관리하는 공간의 맨 앞부분에 위치한 'super block'이라는 곳에 저장


# msdos file system의 super block

- sector의 크기

- cluster(sector가 여러개 모여 구성)의 크기

- FAT 테이블의 위치 및 크기

- 파일시스템의 전역 정보

- '/'의 위치 (root_cluster변수)

=> 파일의 전체적인 정보와 '/'의 위치를 저장


struct msdos_sb_info {


unsigned short sec_per_clus;    /*  sectors/cluster   */

unsigned short cluster_bits;    /*  log2(cluster_size)  */

unsigned int cluster_size;    /*  cluster size  */

unsigned char fats, fat_bits;    /*  number of FATs, FAT bits (12 or 16)  */

unsigned short fat_start;    

unsigned long fat_length;    /*  FAT start & length (sec.)  */

unsigned long dir_start;    

unsigned short dir_entries;    /*  root dir start & entries  */

unsigned long data_start;    /*  first data sector  */

unsigned long max_cluster;    /*  maximum cluster number  */

unsigned long root_cluster;    /*  first cluster of the root directory  */

unsigned long fsinfo_sector;    /*  sector number of FAT32 fsinfo  */

struct mutex fat_lock;    

struct mutex nfs_build_inode_lock; 

struct mutex s_lock;    

unsigned int prev_free;    /*  previously allocated cluster number  */

unsigned int free_clusters;    /*  -1 if undefined  */

unsigned int free_clus_valid;    /*  is free)clusters valid?  */

...

}


# inode 구조

: 파일이나 디렉토리의 모든 정보를 가지고 있는 자료구조


- 리눅스의 디폴트 파일시스템인 ext4 등, ext 계열의 파일시스템에서 사용

- 128 byte

- 하나의 파일에 하나의 inode 할당

- 파일의 이름을 제외한 모든 정보를 저장

- inode number를 가지고 처리

- inode table에서 해당 파일이나 디렉터리의 정보를 찾을 수 있음

- file name은 inode numver와 함께 디렉터리 안에 저장

- file system을 생성 할 때만 inode 갯수를 지정할 수 있으며, 이 갯수는 즉 최대 file의 갯수와 같음



- i_blocks : 해당 파일이 가지고있는 데이터 블록의 갯수 저장

- i_mode : 해당 inode가 관리하는 파일의 속성 및 접근제어 정보 저장

- i_links_count : 해당 inode가 가리키는 파일 수(또는 링크 수)

- i_uid, i_gid : 파일을생성한 소유자의 id 및 group id

- i_atike, i_ctime, i_mtime : 파일의 접근시간, 생성시간, 수정시간


# i_mode 변수

: 해당 inode가 관리하는 파일의 속성 및 접근제어 정보를 저장하는 변수


- 16bit로 구성


- 상위 4bit : 파일의 유형

S_IFREG 정규파일

S_IFDIR 디렉터리

S_IFCHR 문자 장치 파일

S_IFBLK 블록 장치 파일

S_IFLNK 링크 파일

S_IFFIFO 파이프 

S_IFSOCK 소켓

...


- 다음 3bit 

u bit : setuid(set user id), 파일이 수행될 때 수행시킨 태스크의 소유자 권한이 아닌, 파일을 생성한 사용자의 권한으로 동작할 수 있게함

g bit : setgid(set group id)

s bit : sticky bit, 태스크가 메모리에서 쫒겨날 때, swap 공간에 유지되도록 할 때, 디렉터리에 대한 접근 제어에 사용


- 다음 9bit : 파일 접근 제어. 사용자 / 그룹 / 기타 사용자


# i_block[15]

: inode 하단부에 존재하며, 파일에 속한 디스크 블록들의 위치를 관리


- 총 15개의 엔트리로 구성

- 12개의 direct block : 실제 파일의 내용을 담고있는 디스크의 데이터 블록을 가리키는 포인터

- 3개의 indirect block 

single indirect block :  단일 간접블럭, 하나의 인덱스 블럭을 가짐

double indirect block : 이중 간접블럭, 2단계의 인덱스 블럭을 가짐

triple indirect block :  삼중 간접블럭, 3단계의 인덱스 블럭을 가짐


* 하나의 인덱스 블럭은 4KB. 1024개의 포인터(4byte*1024=4096)를 가짐

즉 데이터블럭의 크기가 4KB라고 가정하였을 때, single indirect block으로 지원가능한 파일의 크기는 1024개 * 4KB = 4MB임.

double indirect block : 1024 * 1024 * 4KB = 4GB

triple indirect block : 1024 * 1024 * 1024 * 4KB = 4TB


=> inode가 지원할 수 있는 최대 파일사이즈는 48KB + 4MB + 4GB + 4TB

but, 리눅스가 지원하는 실제 파일사이즈는  4GB(or 2GB)

: inode가 4TB정도의 파일을 지원할 수 있다고 하더라도, 

  리눅스 커널 내부의 파일 관련 함수들이 사용하는 변수나 인자들이 아직 32bit로 구현되어 있기때문


# Ext2 file system의 디렉터리 엔트리

: 파일의 속성정보와 inode의 연결정보를 저장


#define EXT2_NAME_LEN 255


struct ext2_dir_entry {


_le32    inode;         /*  inode number  */

_le16    rec_len;       /*  directory entry length  */

_le16    name_len;    /*  name length  */

char     name[];        /*  file name  */

}


=> EXT2 파일시스템의 디렉터리 엔트리는 FAT 방식과는 다르게 간단한 정보만 유지하고 실제 데이터 블록 인덱싱등의 세부적인 정보는

    inode 번호를 가지고 찾을 수 있는 inode 자료구조에 저장




# Ext2 File System, more 


* Ext3, 4 : Ext2를 기반으로 저널링 기능을 추가하여 신뢰도 및 속도를 향상 (Ext 2와 호환됨)

* IDE방식의 디스크 : hd(hda, hdb, hdc...), SCSI방식의 디스크 : sd

* 파티션 : 시스템에 장착한 디스크를 논리적인 영역으로 분할한 개념. 리눅스에서는 각 디스크마다 최대 64개의 파티션을 제공할 수 있음

              (hda1, hda2, hda3, hdb1, hdb2, hdc1, hdc2, hdc3 ...)

- 파티션에 파일시스템 만들기 : mke2fs, mkfs.XXX ...

- 파티션 당 파일시스템이 만들어짐


# Ext2 File System Layout





- 파티션에 Ext2 파일시스템을 만들면 여러개의 block group으로 구성

- block group : 접근성을 위함. 

  관련 inode와 disk block들을 인접한 실린더에 유지하여 seek time을 줄이기위해 인접한 실린더를 block group으로 지정


- '/'는 inode번호 '2'를 가짐

- 최초에 실행되는 inode 번호는 '11'


# Block Group X

 Super Block

 - 파일 시스템의 전체적인 정보를 저장

 - 파일 시스템의 크기, 마운트 정보, 데이터 블럭의 갯수, inode 갯수, 블럭그룹 번호, 블록의 크기, 그룹당 블룩 수, 슈퍼블록의 수정여부 정보

 Group Descriptor

 - 해당 파일 시스템 내의 모든 Block Group들의 정보를 저장

 - Block Bitmap의 블럭 번호, Inode Bitmap의 블럭 번호, 첫번째 Inode Table Block의 블럭 번호, 그룹안에 있는 빈 블럭 갯수, 그룹안에 있는 inode의 갯수, 그룹안에있는 빈 디렉토리 갯수 

* 크기가 일정하지 않아 Block Bitmap의 위치에 영향을 미치므로 그 위치 정보도 저장

 Block Bitmap

 - 데이터 블록 내에서 빈 공간을 관리하기 위해 사용

 - Block 사용 현황을 bit로 표현 (Super Block, Group Descriptor Block, inode table block 등등)

 - 한 블럭그룹 내의 각각의 블럭은 Block Bitmap의 각각의 bit에 대응

 - 사용중인 block은 Block Bitmap의 해당되는 인덱스의 값이 1로, 사용중이지 않으면 0으로 표현

 Inode Bitmap

 - inode table 내에서 빈 공간을 관리하기 위해 사용

 - Inode 사용 현황을 bit로 표현

- 한 블럭그룹내의 각각의 inode는 Inode Bitmap의 각각의 bit에 대응

- 사용중인 inode는 Inode Bitmap의 해당되는 인덱스의 값이 1로, 사용중이지 않으면 0으로 표현

 Inode Table

 - 파일/디렉터리 관리를 위한 inode들이 저장

 - 파일 시스템 구축 시 계산된 값으로 결정. 고정된 값을 가짐

 - 인접하는 연속된 블럭으로 구성. 각 블럭은 미리 정의된 inode 갯수를 포함

 - Inode Table의 첫 번째 블럭번호를 Group Descriptor에 저장

 - 모든 inode의 크기는 128byte

 - 1024byte의 inode table block은 8개의 inode를 가질 수 있음

 - 4096byte의 inode table block은 32개의 inode를 가질 수 있음 

 Data Blocks

 - 파일에서 데이터를 저장하는 블럭

 - inode에 포함되어 있으며, inode는 몇개의 데이터 블럭을 포함




# Ext 3, 4 File System

: 신뢰성 및 성능향상을 위해 Ext2에 여러 기술을 접목시켜 업그레이드 한 파일시스템


- 목적 : 특정 파일로 인해 발생한 문제가 파일시스템 전체에 영향을 주는 것을 막고, 성능 향상을 도모하자

- Ext2를 기반으로 하여 Ext2 file system과 호환이 가능



# Ext3의 특징

1. Hash 기반의 HTree 도입 

: 빠른 디렉터리 탐색을 도모

  ext2는 단순 linked list로 구현, 한 디렉터리에 파일이 많이 존재할수록 검색 시간이 효율적이지 못하였던 것을 개선


2. fault tolerant를 위해 강력한 저널링(journaling)기능 지원

: 디스크에서 별도의 공간을 차지함


* 저널링 모드

- Journal : 파일시스템에 데이터를 쓰기 전, 모든 데이터를 저널에 기록하고, 추후에 실제 파일시스템에 데이터를 복사

느린 속도, 안전성이 높음

- Ordered : meta data에 한하여 Jounal을 사용. user data는 실제 파일시스템에 저장. Journal에 쓰여진 meta data는 쓰기 순서를 보장

일반적으로 사용됨

- Writeback : Ordered와 비슷하지만 쓰기 순서를 보장하지는 않음.

속도면에서의 향상, 안정성이 떨어짐


* 저널링기능 사용

: 파일시스템을 마운트 할 때 -J 옵션을 이용. 커널내의 JBD(Journaling Block Device)와 유기적으로 동작


3. online-resizing

: LVM(logical volume manager)를 지원하여 파일시스템이 관리하고있는 용량을 동적으로 늘릴 수 있는 기법을 도입

 시스템의 가용시간을 향상



# Ext4의 특징

1. 선할당(preallocation)기법, 지연할당(Delayed allocation)기법의 도입

- 선할당 기법 : 파일시스템의 일관성과 속도를 향상

파일 생성 시 미리 일정 개수의 블록을 할당해주어 물리적으로 연속된 블록을 할당하여 성능을 향상

- 지연할당 기법 : 단편화 방지

우선 자유 블록 카운트만 먼저 갱신하고, 실제 할당은 뒤로 미루는 방식


2. extent기반 데이터 블럭 유지

: 대용량 파일의 메타데이터를 줄일 수 있음. 

디스크상에 연속적인 블럭을 할당하였다고 하더라도 각 데이터 블럭을 가리키기 위해 해당 파일의 inode에 존재하는 총 15개의 직접/간접 블록들을 이용하여 블록마다 하나씩 지정해야함. 

  ex. 500번부터 50개의 block을 사용할 때, 기존에는 500,501,502,503,504...의 데이터를 모두 저장

이때 extent기반의 데이터 블록 유지방법은 "(500,50)"이라는 정보만을 저장함으로써 metadata의 크기를 절약 할 수 있음

또한 데이터 블록을 인덱싱하는데 걸리는 시간도 절약


3. Journaling checksum

: ext3의 Journaling 기능의 성능을 향상


4. 대용량 파일 시스템과 큰 크기의 파일 지원


5. 온라인 단편화 제거 지원


......





참고.

- 리눅스 커널 내부 구조(책)

- http://cafe.naver.com/securitycommunity/127




--------------------------------------------------------------------------------------------------------------------------------------------------------------------

[펌] 

리눅스 파일 시스템

 http://egloos.zum.com/nix102guri/v/392605


1.2 파일 시스템의 종류

리눅스는 다양한 파일 시스템을 지원한다. ext2, ext3, minix, xiats, umsdos, hpfs OS/2, isofs, CD-ROM, msdos, nfs, sysv 등이 있다. 이 파일 시스템들은 각각 다음과 같은 특징을 가지고 있다.

◎ minix
과거 미닉스에서 사용되어졌던 파일 시스템으로 리눅스 파일 시스템 대부분의 기능을 제공하는 파일 시스템이다.

◎ xiafs
미닉스의 제한이 이었던 파일 이름과 파일 시스템에 대한 제한을 보안한 미닉스 파일 시스템의 수정 버전이다. 이 파일 시스템에는 추가된 새로운 기능은 없다. 한때 ext2와 함께 사용되었던 파일 시스템이었으나 현재는 많이 사용되지 않는다.

◎ msdos
도스의 FAT파일 시스템과 호환을 지원하는 파일 시스템이다. 또한 msdos와 OS/2와 윈도NT FAT파일 시스템과도 호환된다

◎ hpfs OS/2
OS/2의 파일 시스템이다. 하지만 현재는 읽기 전용인 파일 시스템으로 파일 시스템에 대한 읽기만이 가능하다.

◎ isofs CD-ROM
ISO기준을 따르는 표준 CD-ROM의 파일 시스템이다. isofs CD-ROM은 CD-ROM에 좀더 긴 파일명을 사용할 수 있도록 확장된 록 브릿지가 기본으로 지원된다.

◎ umsdos
MS-DOS 파일 시스템을 리눅스 상에서도 긴 파일명과 소유자, 접근 허가, 링크와 장치 파일 등을 사용할 수 있도록 확장한 파일 시스템이다. umsdos는 일반적으로 DOS 파일 시스쳄이 마치 리눅스 파일 시스템인 것처럼 보이도록 하는 기능을 제공하므로 따로 리눅스를 위한 파티션은 필요하지 않는다.

◎ nfs
네트워크 파일 시스템이다. 네트워크 상의 많은 컴퓨터들이 각각의 시스템에 가진 파일들을 서로 쉽게 공유하기 위해 제공되는 상호간의 파일 시스템 공유 파일시스템이다.

◎ sysv
System V/386, Xenix 그리고 Coherent 파일 시스템이다.

◎ ext
리눅스 초기에 사용되던 파일 시스템으로 호환성이 없던 ext2의 구 버전이다. 지금은 대부분 하지 않는다.

◎ ext2
리눅스는 미닉스 파일시스템을 처음으로 사용했다. 그러나 여러가지 제약 조건과 성능이 뛰어나지 못하였다. 이를 보안 하기 위해 EXT(Extened File System)이 제시 되었다. 이 파일 시스템은 리눅스 전용으로 설계되어 1992년 4월에 소개 되었다. 또한 1993년에는 2차 확장 파일 시스템인 EXT2가 ext의 여러가지 문제점을 보안하여 나왔다.


2. 디렉토리 구조

리눅스의 기본 디렉토리 구조는 트리 구조를 하고 있다. 그리고 디렉토리 구조는 기본구조를 제외하고 사용자의 설정에 따라 달라질 수 있다. 리눅스의 디렉토리 구조는 파일 시스템 표준안 (FSSTND, Linux File System Standard)을 기반으로 하는 것이 바람직하다. 파일 시스템 표준안은 리눅스상에서 어떻게 파일 시스템을 구성할 것인지에 대한 표준안을 제정하기 위해서 만들어진 문서이다. 표준안을 무조건 따르라는 강제력은 없지만 파일의 위치가 일관된게 유지되어 프로그램 작성, 포딩은 물론 시스템 관리도 쉬워지는 이점이 있기에 배포판들은 이 표준안을 지키고 있다.

2.1 디렉토리 기능 및 내용

대부분의 리눅스는 FHS(Filesystem Hierarchy Standard) 표준 파일 시스템 계층을 사용하고 같은 목적의 파일들은 같은 장소에 일관되게 모아 관리하므로 시스템에 자원이나 프로그램들을 쉽게 찾을 수 있다.

◎ /
루트 디렉토리라고 부르는 리눅스 시스템에서 가장 최상위 디렉토리며 디렉토리 구조의 시작이다. 시스템관리자의 홈인 /root와는 다르다. / 디렉토리 아래에 /bin, /etc, /boot, /mnt, /usr, /lib, /home, /dev, /proc, /var, /sbin, /tmp, /root, /lost+found 등의 디렉토리가 존재한다.

◎ /bin
binaries의 약어로 이진 파일들이며 리눅스에서 가장 기본이 되는 명령어들이 모여 있는 디렉토리이다. 디렉토리의 파일들을 보면 대부분이 실행 파일임을 알 수 있다. 또한 이곳에는 부팅에 필요한 명령어들이 위치하여 부팅후에 시스템의 계정 사용자들이 사용할 수 있는 일반적인 명령어들도 위치 하고 있다.

◎ /etc
이 디렉토리는 리눅스 시스템에 관한 각종 환경 설정에 연관된 파일들과 디렉토리들을 가진 디렉토리이다. 대부분의 이 디렉토리의 파일들은 시스템 관리자에 의해 관리되는 파일들이다. 웹 서버 환경 설정, 시스템 계정 사용자 정보, 패스 워드 관리, 시스템의 파일 시스템 관리 파일, 여러가지 시스템 보안에 관련된 파일들, 시스템 초기화 설정 파일, TCP/IP 설정 파일 등 시스쳄 전반에 걸친 거의 모든 환경 설정 파일들이 모두 이 디렉토리에 있다.

◎ /etc/rc.d
시스템의 부팅과 시스템 실행 레벨 변경시에 실행되는 스크립트들이 저장되어 있는 디렉토리이다. 리눅스의 6가지 실행 레벨로 각각의 해당 디렉토리가 있다.

◎ /etc/shadow
파일에서 패스워드 부분만을 따로 저장하는 파일이다. 이 파일에 패스워드는 암호화 되어 셰도우 패스워드 형태로 저장되어 있으며 시스템 관리자만이 접근할 수 있기 때문에 크래킹 등에 대한 우려가 상대적으로 적다.

◎ /etc/group
시스템의 그룹에 대한 정보를 저장하고 있는 파일이다.

◎ /etc/inittab
init를 설정하는 파일이다.

◎ /etc/issue, /etc/issue.net
getty에 의해서 로그인을 위한 프롬프트가 뜨기 전에 출력되는 메시지를 설정하는 파일이다. 리눅스 시스템으로 접속할 경우 가장 처음으로 볼 수 있는 메시지이다. 보통 시스템에 대한 설명과 각종 환영 메시지를 전달하기 위해서 사용된다. issue 파일의 내용은 보통 시스템의 터미널에서 볼 수 있다. 그리고 /etc/issue.net 파일의 내용은 리모트상에서 시스템으로 접속할 경우 볼 수 있다.

◎ /etc/motd
'Message of the day'의 약자로 시스템으로의 접속에 성공할 경우 쉘이 뜨기 전에 출력되는 메세지를 설정하는 파일이다.

◎ /etc/profile, /etc/csh.login, /etc/csh.cshrc
시스템이 시작될 때 사용자가 로그인을 할 때 본쉘이나 C쉘에 의해서 실행되는 스크립트 파일이다. 일반적으로 사용자들에 대한 기본 환경 설정에 사용된다.

◎ /etc/securetty
시스템 관리자가 시스템에 로그인할 수 있는 안전한 터미널에 대한 정보가 저장되어 있다. 일반적으로 가상콘솔이 설정되어 있다. 이것은 네트워크를 통해 시스템으로 침입해 시스템 관리자의 권한을 획득하는 크랙킹을 막기 위해서이다.

◎ /ete/shell
시스템에서 안정적으로 사용할 수 있는 쉘에 대한 정보를 저장하고 있는 파일이다. 만약 chsh명령을 사용해 사용중인 쉘을 바꾸려면 이 파일에 저장되어 있는 쉘중에 선택해야한다. 또한 ftp데몬의 경우 사용자의 쉘을 검사하여 /etc/shell에 저장되어 있지 않은 쉘을 사용한다면 로그인을 허용하지 않는다.

◎ /boot
리눅스 커널이 저장되어 있는 디렉토리로서 각종 리눅스 boot에 필요한 booting지원 파일들이 저장되어 있는 디렉토리이다.

◎ /mnt
외부 장치인 플로피 디스크, 시디롬, 삼바등을 마운트하기 위해서 제공되는 디렉토리이다. 임시로 사용되는 디렉토리이므로 프로그램들은 /mnt에 어떤 파일 시스템이 마운트 되었는지 자동으로 인식하지 않는다. 또한 /mnt는 보통 여러 개의 하위 디렉토리로 나누어 사용되고, 평소에는 각 디렉토리들은 비어 있다.

◎ /usr
시스템에 사용되는 각종 프로그램들이 설치되는 디렉토리이다. 프로그램과 관련된 명령어 미치 라이브러리들이 이 디렉토리에 위치 하게 된다. 또한 X 시스템관련 파일들과 리눅스 커널 소스, 각종 C언어 과련 해더 파일 등도 이 디렉토리 안에 저장되어 있다.

◎ /usr/bin
리눅스 시스템에서 사용되는 각종 프로그램들이 저장되어 있으며 /bin 디텍토리에 없는 다양한 실행 파일들이 저장되어 있는 디렉토리이다.

◎ /usr/X11R6
X 윈도우 시스템에 사용되는 모든 파일들이 이 디렉토리 안에 저장된다. 이 디렉토리는 X 윈도우 시스템의 개발과 설치를 좀더 쉽게 하기 위해서 전체 시스템 디렉토리 구조에 통합되지 않고 독자적인 구조를 가진다.

◎ /usr/etc
/etc 디렉토리에는 각종 환경 설정 파일들이 있듯이 이곳에도 여러 가지 시스템 환경 설정 파일들이 저장되어 있다./usr/etc의 파일들은 /etc디렉토리 안의 파일들과 달리 꼭 팔요한 파일들은 아니다.

◎ /usr/sbin
시스템 관리자를 위한 명령어들이 저장되는 디렉토리이다. 보통 이 디렉토리의 명령어들은 루트 파일 시스템에는 필요가 없는 서버 프로그램들이 저장된다.

◎ /usr/include
C언어 관련 해더 파일드이 저장되어 있는 디렉토리이다.

◎ /usr/lib
각종 라이브러리들이 저장되어 있는 디렉토리이다. 만약 사용자가 직접 작성한 프로그램을 컴파일한다면 해당 프로그램은 /usr/lib 디렉토리의 파일에 link된다. 또한 이 라이브러리 안에 실행 코드가 필요하다면 /lib 디렉토리를 참조한다.

◎ /usr/local
시스템의 특정적인 프로그램들이 저장되는 디렉토리이다.특정적인이란 시스템 관리자에 의해서 따로 설치되는 프로그램들을 말한다.

◎ /usr/man
man페이지의 실제 내용들이 저장되어 있는 디렉토리이다. 디렉토리를 살펴보면 man1, man2, man3, 등과 같이 여러개의 디렉토리들로 나누어져 있는 모습을 볼수 있다.man1 디렉토리는 섹션 1의 man 페이지 소스를 위한 디렉토리를 말한다.

◎ /usr/src
시스템에서 사용하는 각종 프로그램들의 컴파일되지 않은 소스 파일들이 저장되어 있다./usr/src/linux 디렉토리가 바로 리눅스의 커널소스를 저장하고 있는 디렉토리이기 때문이다.

◎ /usr/X386
/usr/X11R6 디렉토리와 유사한 티렉토리로 X11 Release 5를 위한 디렉토리이다.

◎ /usr/info 
GNU info문서들을 저장하고 있는 디렉토리이다.

◎ /usr/doc
각종 문서들이 저장되어 있는 디렉토리이다

◎ /lib
프로그램들의 각종 라이브러리들이 존재한다. 대부분 공유 라이브러리로 더 편하게 사용할 수 있으며,파일의 크기를 줄여서 실행할 때 불러 사용하게 된다. /lib/modules 디렉토리에는 커널로 로딩 사능한 커널 모듈들이 저장되어 있다.

◎ /home
시스템 계정 사용자들의 홈 디렉토리와 ftp,www,등과 같은 서비스 디렉토리들이 저장된다. 이곳의 디렉토리와 파일들은 시스템에서 상용되지 않는다. 단지 리모트상에서 시스템으로 접속하는 사용자들을 위한 공간이다.

◎ /dev
디렉토리에는 시스템의 각종 디바이스들에 접근하기 위한 디바이스 드라이버들이 자장되어 있는 디렉토리이다. 이 디렉토리는 물리적인 용량은 갖지 않는 가상 디렉토리이다. 대표적으로는 하드 드라이브,플로피, 씨디롬 그리고 루프팩장치 등이 존재한다. 리눅스 시스템은 윈도우와 달리 각종 디바이스 장치들을 하나의 파일로 취급한다. 따라서 시스템은 각각의 장치들로부터의 정보를 /dev 디렉토리에 존해하는 해당 장치 파일로 부터 가지고 온다.

◎ /dev/console
시스템의 콘솔이다.

◎ /dev/hda
시스템의 하드 디스크이다. 여기서 /dev/hda는 첫 번째 하드 디스크를 의미하는 것이다./dev/hda1은 첫번째 하드 디스크의 첫번째파티션,/dev/hda2 두 번째 파티션등을 의미한다.만약 시스템에 여러 개의 하드 디스크가 부착되어 있다면 /dev/hdb,/dev/hdc 등의 파일도 /dev/hdb1,/dev/hdb2등과 같은형식으로 저장되어 있다.

◎ /dev/lp
시스템의 병렬 포트 장치들이다.

◎ /dev/null
이 디렉토리는 블랙홀이라고도 부르는 특별한 장치이다. 이 장치로 데이터 등을 보내면 모두 폐기되므로 주의해야 할 것이다.

◎ /dev/pty
시스템으로의 원격 접속을 위한 'pesudo-terminal'들이다. 만약 시스템 계정 사용자드이 원격지에서 시스템으로 텔넷등을 이용하여 시스쳄에 접속을 시도한다면 이들은 /dev/pty 디바이스들을 사용하게 되는 것이다.

◎ /dev/sda
SCSI 장치들이다. 만약 시스템에 스카시 하드 디스크를 장착했다면 시스템은 /dev/sda파일에서 정보를 얻어 장치에 접근할 것이다.

◎ /dev/ttyS,/dev/cuaS
/dev/ttyS은 직렬포트 장치들이고, /dev/cauS는 Callout. 장치이다.

◎ /dev/tty
시스템의 가상콘솔들이다. 이 가상 콘솔의 기능은 하나의 화면에 여러 개의 콘솔들을 만든다. 만약 사용자가 시스템 앞에 앉을 수 있다면,Alt + F1, Alt + F2등을 이용하여 리눅스에 제공한 여러개의 가상 콘솔을 직접 볼수 있을 것이다.

◎/proc
시스템의 각종 프로세서, 프로그램 정보 그리고 하드웨어적인 정보들이 저장된다. 이 티렉토리는 가상 파일 시스템으로 가상 파일 /dev와 마찬가지로 하드 디스크상에 물리적인 용량을 갖지 않는다. 즉 디렉토리에 존재하는 파일들은 실제 하드 디스크에 저장되지 않고 커널에 의해 메모리에 적재 된다. 디렉토리 안의 파일들은 현재의 시스템 설정을 보여 주는 것이다.

◎ /proc/1
프로세스 번호가 1인 프로세스에 대한 정보를 저장하는 디렉토리이다. 다른 프로세스들도 자신의 고유한 프로세스 번호의 디렉토리를 가진다는 것을 의미한다.

◎ /proc/cpuinfo
프로세서의정보를 저장하고 있는 파일이다. cpu의 타입, 모델, 제조회사, 각종 성능 등의 정보를 제공하여 준다.

◎ /proc/devices
현재 시스템 커널에 설정되어 있는 장치들에 대한 정보를 저장하고 있다.파일등의 정보로 모든 시스템의 장치 목록에 대한 정보를 얻을 수 있다.

◎ /proc/dma
현재 시스템에서 사용하고 있는 DMA 채널에 대한 정보를 저장하고 있다.

◎ /proc/filesystem
시스템에 설정되어 있는 파일 시스템에 대한 정보를 저장하고 잇는 파일이다.

◎ /proc/interrupts
현재 사용중인 인터럽트와 인터럽트의 사용량에 대한 정보를 저장하고 있는 파일이다.

◎ /proc/ioports
현재 사용중인 I/O 포트에 대한 정보를 저장하고 있는 파일이다.

◎ /proc/kcore
현재 시스템에서 사용중인 메로리의 실제 이미지이다. 이 파일은 실제 메모리의 내용을 모두 가진 것처럼 보이지만 프로그램이 필요로 하는 부분의 이미지만을 필요할 때 만들어 제공한다.

◎ /proc/kmsg
커널에 의해서 출력되는 메시지들을 저장하고 있는 파일이다.이것은 또한 syslog파일에도 저장된다.

◎ /proc/loadavg
현재 시스템의 평균 부하량(Load Average)에 대한 정보를 저장하고 있는 파일이다.이 파일을 통해서 시스템이 현재 수행해야 하는 일이 얼마나 많은지를 알려주는 3가지 지표에 대한 정보를 얻을 수 있다.

◎ /proc/ksyms
시스템 커널이 사용하고 있는 심볼들에 대한 정보를 저장하고 있는 파일이다.

◎ /proc/meminfo
현재 시스템이 사용중인 메모리의 사용량을 저장하고 있는 파일이다./proc/meminfo에서 실제 메모리는 물론 가상 메모리에 대한 정보도 얻으 수 있다.

◎ /proc/self
이 디렉토리를 보고 있는 프로그램 자시의 프로세스 디렉토리로 링크도어 있다. 만약 서로 다른 2개의 프로세스가 /proc 디렉토리를 보고 있다면 두 프로세스는 서로 다른 링크를 보게 된다. 이를 통해서 프로그램들이 자신의 프로세스 디렉토리를 쉽게 찾을 수 있다.

◎ /proc/stat
시스템의 현재 상태에 대한 다양한 정보를 저장하고 있는 파일이다.

◎ /proc/uptime
시스템이 얼마나 오래 동작했는지에 대한 정보를 저장하고 있는 파일이다.

◎ /proc/version
시스템이 현재 사용중인 커널 버전에 대한 정보를 저장하고 있는 파일이다.

◎ var
시스템에서 사용되는 동적인 파일들이 저장된다. 각종 시스템 로그 파일, 사용자 로그인에 대한 보안기록,메일서버를 운영한다면 사용자들에게 전송된 메일들을 임시로 저장한다.

◎ /var/cache
포멧된 메뉴얼 페이지들이 잠시 대기(Cache)하기 위한 디렉토리이다.

◎ /var/lib
시스테이 동작하면서 계속 수정되고 변경되는 파일들을 위한 디렉토리이다.

◎ /var/local
/usr/local 디렉토리에 설치된 프로그램들의 각종 데이터들이 저장되는 디렉토리이다.

◎ /var/lock
잠금 파일들이 저장되는 디렉토리이다.프로그램들이 특정한 장치나 파일들을 프로그램 자신이 독점적으로 사용하려 할 때 /var/lock 디렉토리에 잠금 파일을 만들어 사용하게 된다. 그렇기 때문에 다른 프로그램들은 장치나 파일을 사용하기 전에 우선 이 디렉토리의 내용을 조사하여 해당 장치나 파일들이 사용중인지 확인하게 된다.

◎ /var/log
프로그램들의 로그 파일들이 저장되는 디렉토리이다. 이 디렉토리에 wtmp파일은 login 파일과 messages파일은 syslog의 로그 파일이다.wtmp는 시스쳄의 모든 사용자 로그인과 로그 아웃에 대한 정보르 저장하고 있는 파일이고,messages는 커널과 시스템의 모든 출력 메세지를 저장하고 있는 파일이다./var/log 안의 파일들은 시스템의 사용량에 따라 그 크기가 무한대로 증가할 있으므로 정기적으로 파이들을 삭제하는 등 디렉토리 관리가 필요하다

◎ /var/run
시스템의 현재 정보들을 저장하고 있는 디렉토리이다./var/run/xinetd.pid 파일의 경우 현재 사용중인 xinetd 데몬의 프로세스 번호를 저장하고 있다.

◎ /var/spool
메일이나 뉴스, 프린터 큐 등고 같은 시스템상에서 대기 상태에 있는 작업들을 위한 디렉토리이다. 각각의 대기 작업들은 모두 /var/spool 아래 고유의 디렉토리에 위치하게 된다. 예를 들어 시스템의 계정 사용자들의 메일은 /var/spool/mail 에 저장된다.

◎ /var/tmp
/tmp에 저장된 임시 파일들중에 오래 보관되어야 할 임시 파일들이 저장되는 디렉토리이다.

◎ /tmp
이름에도 알 수 있듯이 임시 파일들을 위한 디렉토리이다.

◎ /root
시스템 관리자의 홈 디렉토리이다

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

'System > Linux Kernel' 카테고리의 다른 글

Device Tree, 리눅스 커널 4.0  (0) 2015.08.29
메모리관리  (0) 2015.08.18
인터럽트 / 트랩  (0) 2015.08.16
VFS, Virtual File System  (0) 2015.08.16
리눅스 부팅과정과 런레벨  (0) 2015.08.13

+ Recent posts