Transcript 슬라이드 1
리눅스 커널 분석 강사명 : 김정인 email : [email protected] 수업자료 ( 소스 / ppt 자료 ) ftp server : 156.147.178.179 id/passwd : linux / linux 강의 배포자료 : 이동식 디스크 ( 커널수업자료.egg ) 리눅스 커널 분석 1. 완벽한 C 언어 2. 커널 고급 자료구조 ( generic linked list, hash, RB Tree ) 3. 리눅스 시스템 프로그램 ( R. stevens ) 4. 네크워크 프로그램 ( R. stevens ) 5. 가상 파일 시스템 ( file system, driver , inode, file, ... ) 6. 프로세스 ( schedule , context switching , fork, exit, wait.. 7. 메모리 ( paging , buddy system, slab allocator ) 실습 환경 구축 vmplayer 삭제후 vmworkstation 설치(VMware-workstation-full-7.0.0-2037 key.txt에 있는 serial key 입력 linux login 일반계정 : linux/linux 루트권한으로 변경 $ su password : linux # ( vmware 에서 login ) 루트계정 : root/linux ( putty 에서 login ) # windows alftp putty linux ftp 21 vmnet8 : 192.168.100.1 ssh 22 eth0 : 192.168.100.133 네트워크 설정 vmware 에서 edit >> virtual network editor 네트워크 test windows에서 cmd 실행 C:\Documents and Settings\user>ipconfig VMnet8: . : 192.168.100.1 C:\Documents and Settings\user> ping 192.168.100. linux에서 터미널 실행 ( vmware ) root@ubuntu:~# ifconfig eth1 Link encap:Ethernet HWaddr 00:0c:29:2a inet addr:192.168.100.133 root@ubuntu:~# ping 192.168.100.1 네트워크 test linux의 데몬 확인 tcp 데몬 확인 root@ubuntu:~# netstat -at tcp 0 0 *:ssh tcp 0 0 *:ftp LISTEN LISTEN root@ubuntu:~# netstat -atn tcp 0 0 0.0.0.0:22 LISTEN tcp 0 0 0.0.0.0:21 LISTEN 원격 접속을 위한 putty 설정 ftp 설정 재부팅 후 network 설정 방법 I ifconfig 시 eth2, eth3으로 나올경우 다음 조치 수행 # vi /etc/network/interfaces auto eth2 iface eth2 inet static address 192.168.10.3 netmask 255.255.255.0 network 192.168.10.0 broadcast 192.168.10.255 gateway 192.168.10.1 auto eth3 iface eth3 inet dhcp 위와 같이 수정후 네트워크 재기동 # /etc/init.d/networking restart 재부팅 후 network 설정 방법 II ifconfig 시 eth2, eth3으로 나올경우 1. /etc/udev/rules.d/70-persistent-net.rules 파일에서 랜 MAC 어드레스에 해당하는 라인을 지우거나 주석처리한다. #SUBSYSTEM=="net", ATTR{address}=="00:0c:29:2a:f1:69" #SUBSYSTEM=="net", ATTR{address}=="00:0c:29:2a:f1:73" 2. 현재 MAC 어드레스로 /etc/udev/rules.d/70-persistent-n 파일을 업데이트하기 위해 아래 명령들을 시작한다 # /etc/init.d/udev restart # modprobe -r pcnet32 # modprobe pcnet32 위 명령 실행시 /etc/udev/rules.d/70_persistent-net.rules 파일의 MAC 어드레스 부분은 아래처럼 새로운 값으로 변경됨 3. 네트워크 재기동 # /etc/init.d/networking restart 소스 분석을 위한 환경설정 ( ctags ) 설치 # apt-get install ctags tag 파일 생성 # cd /usr/src/linux # ctags -R * # ls -l tags 검색 # vi a.c task_struct ctrl + ] : 정의로 이동 g + ] : 여러개의 정의 ctrl + t : 돌아오기 No write since last change 위 에러가 났을경우 반드시 저장후 이동 :w 소스 분석을 위한 환경설정 ( ctags ) 모든 디렉토리에서 검색 가능하게 하기 # cd # pwd /root # vi ~/.vimrc set set set set sw=4 ts=4 cindent tags+=/usr/src/linux/tags 자동들여 쓰기 { int i; } =% : 블럭 들여쓰기 gg=G : 파일 전체 들여쓰기 명령모드 편집모드 int main() i,o,O a,I,A ESC EX 모드 : -- INSERT -- ESC :w 파일의 저장 :q 파일을 나감 :wq 저장 후 나감 : 명령모드 편집모드 int main() i,o,O a,I,A ESC EX 모드 : : ESC -- INSERT -x : 한글자 지우기 cw : 한단어 치환 r : 한글자 치환 2s : 두글자 치환 . : 이전 명령의 반복 yy p dd u : 한줄 복사 : 붙혀 넣기 : 한줄 잘라내기 : undo linked list 구현 step1 typedef struct _node { int data; struct _node *next; } NODE; 2 head NODE *head; void insert_data( int data ) { NODE *temp = (NODE*)malloc( sizeof(NODE) ); temp->data = data; temp->next = head; head = temp; } 1 0 linked list 구현 step1 2 [head]->[2]->[1] 1 0 head void display(void) { NODE *temp; system("clear"); printf("[head]"); for( temp = head; temp != 0 ; temp = temp->next ) printf("->[%d]", temp->data ); printf("\n"); getchar(); } linked list 구현 step1 head s 3 2 0 1 void insert_data( int data ) { NODE *temp = (NODE*)malloc( sizeof(NODE) ); temp->data = data; temp->next = s->next; s->next = temp; } 문제점 : 삽입/삭제시 일반성이 없다. 이유 : head가 node 가 아니기 때문 해결책 : head도 node를 갖게 하자 linked list 구현 step2 head temp void init( void ) 0 { head = (NODE*)malloc( sizeof(NODE) ); head->next = 0; } void insert_data( int data ) { NODE *temp = (NODE*)malloc( sizeof(NODE) ); temp->data = data; temp->next = head->next; head->next = temp; } linked list 구현 step2 void display(void) { NODE *temp; head 0 system("clear"); printf("[head]"); for( temp = head->next; ; temp = temp->next ) printf("->[%d]", temp->data ); // (*temp).dat printf("\n"); getchar(); } 문제점 : NULL 로 끝나는 것이 문제 이유 : NULL을 역참조할 수 있는 위험성이 있다. 해결책 : NULL 대신 tail로 끝나게 하자 linked list 구현 step3 head tail NODE *head, *tail; void init( void ) { head = (NODE*)malloc( sizeof(NODE) ); tail = (NODE*)malloc( sizeof(NODE) ); head->next = tail; tail->next = tail; } linked list 구현 step3 head tail void insert_data( int data ) { NODE *temp = (NODE*)malloc( sizeof(NODE) ); temp->data = data; temp->next = head->next; head->next = temp; } 문제점 : list가 메모리에 의존적이다. ( heap ) 이유 : memory pooling 기법 사용 못함 해결책 : malloc 을 삽입코드에서 제거 하자. linked list 구현 step4 void insert_data( NODE *temp ) { temp->next = head->next; head->next = temp; } NODE a[7]; a[i].data = i+1; insert_data( a+i ); head tail linked list 구현 step4 void insert_data( NODE *temp ) { temp->next = head2->next; head2->next = temp; } 문제점 : 프로세스내에 list가 하나만 존재 가능 하다. 이유 : head와 tail이 코드내에 있다. 해결책 : head와 tail을 인자로 처리 해야 함 linked list 구현 step5 void insert_data( NODE *head, NODE *temp ) { temp->next = head->next; head->next = temp; } // --------------------------insert_data( head1, temp ); insert_data( head2, temp ); 문제점 : 프로세스내에 list가 하나만 존재 가능 하다. 이유 : head와 tail이 코드내에 있다. 해결책 : head와 tail을 인자로 처리 해야 함 linked list 구현 step5 void init( NODE **head, NODE **tail ) { *head = (NODE*)malloc( sizeof(NODE) ); *tail = (NODE*)malloc( sizeof(NODE) ); (*head)->next = *tail; (*tail)->next = *tail; } init( &head, &tail ); 문제점 : 프로세스내에 list가 하나만 존재 가능 하다. 이유 : head와 tail이 코드내에 있다. 해결책 : head와 tail을 인자로 처리 해야 함 linked list 구현 step5-1 void init( NODE *head, NODE *tail ) { head->next = tail; tail->next = tail; } init( &head, &tail ); display( &head, &tail ); insert_data( &head, ); NODE head, tail; 문제점 : 프로세스내에 list가 하나만 존재 가능 하다. 이유 : head와 tail이 코드내에 있다. 해결책 : head와 tail을 인자로 처리 해야 함 linked list 구현 step5-1 void init( NODE *head, NODE *tail ) { head->next = tail; tail->next = tail; } init( &head, &tail ); display( &head, &tail ); insert_data( &head, ); NODE head, tail; 문제점 : tail 이 과연 필요 한가? 이유 : head와tail을 둘다 관리하기가 불편 해결책 : head가 tail 역할을 하면 된다. linked list 구현 step6 head void init( NODE *head) { head->next = head; } void insert_data( NODE *head, NODE *temp ) { temp->next = head->next; head->next = temp; } 문제점 : tail 이 과연 필요 한가? 이유 : head와tail을 둘다 관리하기가 불편 해결책 : head가 tail 역할을 하면 된다. 2 1 linked list 구현 step6 head void init( NODE *head) { head->next = head; } void insert_data( NODE *head, NODE *temp ) { temp->next = head->next; head->next = temp; } 문제점 : 역순 검색이 가능한가? 이유 : 검색의 성능이 떨어진다. 해결책 : reverse함수를 구현 하면 된다. 2 1 linked list 구현 step7 head 3 2 1 next curr prev reverse( NODE *head ){ NODE *prev =head; NODE *curr = prev->next; NODE *next; while( curr != head ) { next = curr->next; curr->next = prev; prev = curr; curr = next; } head->next = prev; } linked list 구현 step1 typedef struct _node { int data; struct _node *next, *prev; } NODE; head NODE head; void insert_data( NODE *head, NODE *temp ) { temp->next = head->next; head->next = temp; temp->prev = temp->next->prev; temp->next->prev = temp; } 1 prev temp 1 next void __insert_data( NODE *prev, NODE *next, NODE *temp ){ temp->next = next; prev->next = temp; temp->prev = prev; next->prev = temp; } void insert_front( NODE *temp ){ __insert_data( head, head->next, temp ); } void insert_back( NODE *temp ){ __insert_data( head->prev, head, temp ); } prev temp typedef struct _node { void *data; struct _node *next, *prev; } NODE; void __insert_data( NODE *prev, NODE *next , NODE *temp ) { temp->next = next; prev->next = temp; temp->prev = prev; next->prev = temp; } 문제점 : list가 data type에 의존적이다. 이유 : NODE 안에 data가 있기 때문 해결책 : void *를 이용하여 일반화 하라 ne prev temp "홍길동" "이순신" next "임꺽정" typedef struct _node { void *data; struct _node *next, *prev; } NODE; //------------------------------------------typedef struct { char name[20]; } SAWON; prev "홍길동" temp next "임꺽정" 문제점 : loose coupling 문제 이유 : 메모리 할당/해지 시기가 다를수 있다. 해결책 : list에 data를 넣지 말고 data에 list를 넣 어라. typedef struct _node { struct _node *next; struct _node *prev; } NODE; //--------------------typedef struct { char name[20]; NODE list; } SAWON; SAWON* NODE* NODE* 980 NODE* 1000 "홍길동" "이순신" NODE* NODE* NODE* NODE* (SAWON*)((char*)temp - ( sizeof(SAWON) - sizeof(NODE 문제점 : 하나의 노드가 여러개의 list에 포함 될수 없다. 이유 : list가 가장 마지막 멤버일 경우에만 유효 한다. 해결책 : 구조체의 멤버 오프셋 포인터를 이용하면 된다. 0 1000 20 1020 28 1028 "홍길동" NODE* NODE* #define list_entry(ptr,type,member) \ ((type*)((char*)ptr - (int)&((type*)0)->member )) 문제점 : 하나의 노드가 여러개의 list에 포함 될수 없다. 이유 : list가 가장 마지막 멤버일 경우에만 유효 한다. 해결책 : 구조체의 멤버 오프셋 포인터를 이용하면 된다. struct list_head { struct list_head *next, *prev; }; void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next){ next->prev = new; new->next = next; new->prev = prev; prev->next = new; } void list_add(struct list_head *new, struct list_hea __list_add(new, head, head->next); } void list_add_tail(struct list_head *new, struct lis __list_add(new, head->prev, head); } #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0) #define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) *__mptr = (type *)( (char *)__mptr - offsetof(type,memb #define list_entry(ptr, type, member) \ container_of(ptr, type, member) struct task_struct { ... struct list_head tasks; ... struct list_head children; ... struct list_head sibling; ... }; struct inode { ... struct list_head i_list; struct list_head i_sb_list; struct list_head i_dentry; ... }; struct hlist_head { struct hlist_node *first; }; struct hlist_node { struct hlist_node *next, **pprev; }; struct hlist_head head[5] = { 0, }; head [0] [1] [2] [3] [4] 10 .next .pprev 13 .next .pprev pid%10 struct hlist_head head[8] = { 0, }; static unsigned int pidhash_shift = 3; #define GOLDEN_RATIO_PRIME_32 0x9e370001UL static inline u32 hash_32(u32 val=8987, unsigned int { u32 hash = val * GOLDEN_RATIO_PRIME_32; return hash >> (32 - bits); } #define hash_long(val, bits) hash_32(val, bits) #define pid_hashfn(pid) \ hash_long( pid, pidhash_shift) first head [0] 0 h [1] [2] 0 [3] 0 n 2000 * .next ** .pprev 1000 0 .next ** .pprev void hlist_add_head(struct hlist_node *n, struct hlis { struct hlist_node *first = h->first; n->next = first; if (first) first->pprev = &n->next; h->first = n; n->pprev = &h->first; } typedef struct _node { int data; struct _node *left; struct _node *right; } NODE; NODE *root; 1 2 4 3 5 6 7 pedef enum { LEFT, RIGHT } FLAG ; id insert_data( int data, NODE *s, FLAG flag ) root NODE *temp; temp=malloc(sizeof(NODE)); temp->data = data; temp->left = 0; temp->right = 0; if( root == 0 ) { root = temp; return; } if( flag == LEFT ) s->left = temp; else if( flag == RIGHT ) s->right = temp; s 1 tem 2 0 0 3 0 0 in-order traverse 1 left - root - right 2 3 4 void in_order( NODE *temp ) { 4 2 if( temp == 0 ) return ; in_order( temp->left ); printf("%4d", temp->data ); in_order( temp->right ); } 5 5 1 6 6 3 7 7 in-order traverse right - root - left 1 void display( NODE *temp ) { 4 int i; static int indent=-1; if( temp == 0 ) return ; indent++; display( temp->right ); for(i=0; i<indent; i++ ) printf("%4c", ' ' ); printf("%4d\n", temp->data ); display( temp->left ); indent--; } 2 3 5 6 7 7 3 6 1 5 2 4 void __display( NODE *temp, int (*a)[10], int *row, int *col ) 1 { if( temp == 0 ) 2 3 return ; ++*row; 4 5 6 __display( temp->left ); a[*row][*col] = temp->data; 1 ++*col; 2 5 __display( temp->right ); 4 5 6 7 --*row; } void display( NODE *temp ) { int a[10][10], row=-1, col=0; __display( temp , a, &row, &col); ... O( n ); O( log2n ); int a[7] = { 4 , 2 , 1, 3, 6, 5, 7 }; 4 2 1 6 3 5 7 root if( root == 0 ) { root = temp; prev return; 4 } p=0 while( p ) 0 { temp prev = p; if( p->data > data ) 2 p = p->left; 0 else if ( p->data < data ) 0 p = p->right; } if( prev->data > data ) prev->left = temp; else prev->rigth = temp; } oid insert_data( int data ) p ** NODE *temp; NODE **p = &root; temp=malloc(sizeof(NODE)); temp->data = data; temp->left = 0; temp->right = 0; while( *p ) temp { if( (*p)->data > data ) p = &(*p)->left; else if ( (*p)->data < data ) 1 p = &(*p)->right; 0 } 0 *p = temp; root 4 0 2 3 0 0 1 2 0 1 2 3 4 5 6 3 4 1 2 3 4 5 6 7 5 6 7 4 2 1 NODE *bal( int *a , int { int mid = n/2; if( n<=0 ) return 0; temp=malloc(); temp->data = a[mi temp->left = bal( temp->right= bal( return temp; 6 3 5 7 } AVL 2-3 2-3-4 B B+ B* .... RB tree 1 RB tree 공리 1. root 노드는 언제나 검정이다. 2. 새로운 노드는 빨강이다. RB tree 공리 1 2 1. root 노드는 언제나 검정이다. 2. 새로운 노드는 빨강이다. RB tree 공리 1 2 3 2 1 3 1. root 노드는 언제나 검정이다. 2. 새로운 노드는 빨강이다. 3. 부모노드가 빨강이면 회전한다. RB tree 공리 2 1 3 4 2 1 3 4 2 1 3 4 1. root 노드는 언제나 검정이다. 2. 새로운 노드는 빨강이다. 3. 부모노드도 빨강이고 삼촌도 빨강이면 color flip 4. 부모노드가 빨강이면 회전한다. RB tree 공리 2 0. 밸런스는 root 노드로 부터 모든 단말노드로 가는 경로의 검정 노드의 수가 같으면 맞는 것으로 간주 한다. 1. root 노드는 언제나 검정이다 2. 새로운 노드는 빨강이다. 3. 부모노드도 빨강이고 삼촌도 빨강이면 color flip 4. 부모노드가 빨강이면 회전한다 3 4 5 2 1 4 3 5 RB tree 공리 2 4 3 5 6 2 4 3 5 6 0. 밸런스는 root 노드로 부터 모든 단말노드로 가는 경로의 검정 노드의 수가 같으면 맞는 것으로 간주 한다. 1. root 노드는 언제나 검정이다 2. 새로운 노드는 빨강이다. 3. 부모노드도 빨강이고 삼촌도 빨강이면 color flip 4. 부모노드가 빨강이면 회전한다 RB tree 공리 2 4 3 5 6 2 7 4 3 6 5 7 0. 밸런스는 root 노드로 부터 모든 단말노드로 가는 경로의 검정 노드의 수가 같으면 맞는 것으로 간주 한다. 1. root 노드는 언제나 검정이다 2. 새로운 노드는 빨강이다. 3. 부모노드도 빨강이고 삼촌도 빨강이면 color flip 4. 부모노드가 빨강이면 회전한다 RB tree 공리 2 4 3 0. 밸런스는 root 노드로 부터 모든 단말노드로 가는 경로의 검정 노드의 수가 같으면 맞는 것으로 간주 한다. 1. root 노드는 언제나 검정이다 2. 새로운 노드는 빨강이다. 3. 부모노드도 빨강이고 삼촌도 빨강이면 color flip 4. 부모노드가 빨강이면 회전한다 6 7 5 2 8 4 3 6 7 5 8 4 2 [ 4] < 2> [ 1] [ 3] 6 3 5 7 8 < 6> [ 5] [ 7] < 8> 2 - 4 - 3 2 4 3 2 - 3 - 4 3 - 2 - 4 2 parent left rotate 3 4 gparent right rotate color flip 3 2 4 4 - 2 - 3 4 2 4 - 3 - 2 3 3 - 2 - 4 4 3 parent left rotate 2 3 2 gparent right rotate color flip 4 struct rb_node { unsigned long rb_parent_color; struct rb_node *rb_right; struct rb_node *rb_left; } __attribute__((aligned(sizeof(long)))); struct rb_root { struct rb_node *rb_node; }; struct rb_root root = { 0 } ; 01100100 01101001 rb_parent_color & ~3 rb_parent_color & 1 #define #define #define #define #define #define rb_parent(r) ((struct rb_node *)((r)->rb_pa rb_color(r) ((r)->rb_parent_color & 1) rb_is_red(r) (!rb_color(r)) rb_is_black(r) rb_color(r) rb_set_red(r) do { (r)->rb_parent_color &= ~ rb_set_black(r) do { (r)->rb_parent_color |= static inline void rb_set_parent(struct rb_node *rb, { rb->rb_parent_color = (rb->rb_parent_color & } static inline void rb_set_color(struct rb_node *rb, i { rb->rb_parent_color = (rb->rb_parent_color & } void rb_link_node(struct rb_node * node, struct rb_no struct rb_node ** rb_ { node->rb_parent_color = (unsigned long )paren node->rb_left = node->rb_right = NULL; *rb_link = node; } rb_link ** 1 0 0 0 0 root 2 0 0 0 0 SAWON * __rb_insert_data(struct rb_root* root, int data, struct rb_node * node) { struct rb_node ** p = &root->rb_node; struct rb_node * parent = NULL; SAWON *s; while (*p) { parent = *p; s = rb_entry(parent, SAWON, tree); if (data < s->data) p = &(*p)->rb_left; else if (data > s->data) p = &(*p)->rb_right; else return s;