2025의 게시물 표시

리눅스 커널 - Process and Interrupt Context Synchronization

이미지
프로세스 컨텍스트와 인터럽트 컨텍스트에 대한 내용은 다음 페이지에서 다루었다:  프로세스/인터럽트 컨텍스트 프로세스 컨텍스트와 인터럽트 컨텍스트에서 같은 critical section에 접근하는 시나리오에 대해서 생각해보자. 이 시나리오에서는 데드락이 발생할 수 있는데 상황은 아래와 같다. 1. 프로세스 컨텍스트에서 스핀락을 잡는다. 2. 인터럽트가 발생하여 인터럽트 핸들러가 동작하고 스핀락을 잡으려고 한다. 위와 같은 상황에서 프로세스 컨텍스트가 스핀락을 해제해야 하는데, 인터럽트 핸들러에 의해 CPU를 빼앗겨 스핀락을 해제할 수 없다. 인터럽트 핸들러는 스핀락을 잡을 수 없다. 아래 그림에서 Problem situation에 해당한다. 이러한 데드락 상황을 피하기 위해서, 프로세스 컨텍스트에서 인터럽트를 disable 후 스핀락을 얻으면 된다. 아래 그림의 Solution에 해당한다. spin_lock_irqsave() 함수로 현재 인터럽트 상태(disable이었는지 enable이었는지)를 저장하고 인터럽트를 disable 한 뒤 스핀락을 획득한다. spin_unlock_irqrestore()는 스핀락을 해제하고 저장해놨던 이전 인터럽트 상태를 복원한다. 이야기를 더 진행하기 위해 먼저 bottom half context를 소개한다. 이 컨텍스트는 인터럽트 컨텍스트의 일종인데, 인터럽트는 enable 되어 있고  블로킹 함수는 부르면 안 되는 상태이다. 인터럽트 핸들러에서 전반부 작업이 끝나고 나서 도는 softirqs와 tasklets이 bottom half context에서 도는 것이다 (이후에 ksoftirqd에 의해 도는 softirq는 프로세스 컨텍스트에서 돈다.). Bottom half context와 critical section을 공유하는 프로세스 컨텍스트의 경우 spin_lock_bh() 함수로 스핀락을 잡아야 한다 (ksoftirqd에 의해 도는 softirq는 spin_lock()으로 잡는다.). spin_lock_bh(...

리눅스 커널 - Race Condition 회피 방법 (Atomic operations, Disabling Preemption, Spin Locks)

리눅스 커널은 symmetric multi-processing (SMP)를 지원하며, 이는 race condition을 회피/대응할 수 있어야 한다는 말이다 (single core라고 하더라도 preemption 및 interrupt에 의해 동시성은 위협 받을 수 있다.). SMP: 여러 개의 코어가 같은 메인 메모리를 공유하는 구조. 즉, 공유 메모리의 같은 address에 대한 접근이 동시(race condition)에 일어날 수 있다. race condition에 대응하기 위해 critical section이 어디인지 알고 있다는 가정 하에 다음 접근 법을 선택할 수 있다. critical section을 atomic하게 처리 (atomic instruction 이용) critical section 도중 preemption을 disable lock을 잡아서 serialize 시킨다 (critical section에 한 스레드만 존재할 수 있도록 한다) Atomic Operations 하드웨어에서 제공하는 atomic operation (instruction)을 이용하면 락을 잡지 않고도 atomic operation을 보장받을 수 있다. 예시: atomic_inc(), atomic_dec(), test_bit(), set_bit(), change_bit() 등 Atomic operation은 하드웨어 레벨에서 락을 잡기 때문에 시스템 레벨에서 잡는 것 보다는 가볍지만 여전히 비싼(expensive) operation이다. Disabling Preemption local_irq_disable()로 인터럽트를 막고, preempt_disable()로 커널 스케줄러에 의한 선점을 막을 수 있다. Spin Locks 스핀락은 락을 얻을 때까지 busy waiting을 한다. 락을 잡고 critical section 수행 후에 락을 해제하여 operation을 serialize 한다. 스핀락 이용 시, 특정 메모리 주소의 값을 동시에 여러 스레드가 보고 락을 얻을...

리눅스 커널 인터럽트 흐름 (Interrupt Flow)

이미지
인터럽트 시리즈 인터럽트 처리 이해 기본 (basic understanding interrupt handling ) 인터럽트 방식 비교 - Legacy, MSI, MSI-X 리눅스 커널 인터럽트 흐름 (Interrupt Flow) Process 수행 중 device에서 인터럽트 발생 돌고 있던 process의 context가 저장됨 인터럽트 핸들러 진입. 이때부터 인터럽트 context 이다. 인터럽트 context에서는 context switch가 불가한데, 이는 현재 수행중인 작업을 그만두고 CPU를 놔버리면 안 된다("블로킹 함수를 부르면 안 된다"라고도 함)는 뜻. 인터럽트 핸들러 동작을 모두 끝내고 IRET를 통해서만 CPU를 그만 독점해야한다. IRQ disable하여 다른 인터럽트 핸들러가 수행되지 않도록 함.  해당 인터럽트에 맞는 디바이스들의 핸들러 들이 동작함 IRQ enable하여 다른 인터럽트 핸들러 동작을 허용. 여기까지가 인터럽트 전반부 작업이다 (Top half). 수행할 softirq나 tasklet이 있다면 후반부 작업을 바로 수행 (이때 IRQ는 enable 상태이므로 다른 인터럽트 핸들러가 끼어들 수 있다.) 일을 모두 마쳤다면 IRET instruction이 수행되어 저장된 context를 불러와서 기존에 돌던 process를 재시작(resume). 이때 인터럽트 context에서 process context로 전환된다. 만약 돌아야 하는 workqueue나 지연된 softirq가 있다면 스케줄링 되었을 때 수행됨. 이때 softirq는 단시간 내에 끝나지 않아서, IRET 전에 중지되었던 softirq 이다. 이런 지연된 softirq는 ksoftirqd 커널 스레드에 의해 실행되며 프로세스 컨텍스트에서 수행된다. workqueue 또한 프로세스 컨텍스트에서 수행된다. 용어 maskable: 대부분의 인터럽트, 인터럽트가 disable 되어있으면 일시적으로 interrupt handler가 도는 것을 연기...

인터럽트 방식 비교 기본 - Legacy, MSI, MSI-X

이미지
 인터럽트 시리즈 인터럽트 처리 이해 기본 (basic understanding interrupt handling ) 인터럽트 방식 비교 - Legacy, MSI, MSI-X 리눅스 커널 인터럽트 흐름 (Interrupt Flow) MSI: PCI 2.2에서 도입 MSI-X: PCI 3.0에서 도입 --> PCIe 7.0 까지도 MSI 및 MSI-X는 표준 인터럽트 방식임

인터럽트 처리 이해 기본 (basic understanding interrupt handling )

이미지
인터럽트 시리즈 인터럽트 처리 이해 기본 (basic understanding interrupt handling ) 인터럽트 방식 비교 - Legacy, MSI, MSI-X 리눅스 커널 인터럽트 흐름 (Interrupt Flow) 하드웨어 인터럽트 컨트롤러(이하 컨트롤러)로부터 소프트웨어 인터럽트 핸들러에 이르기까지에 대한 논리적인 과정을 그림으로 표현하였다. (The logical process from the hardware interrupt controller to the software interrupt handler is illustrated in the above diagram.) IRQ는 전통적으로는 물리적인 전기선으로 이해될 수 있으며, 인터럽트 소스 (예: 키보드, 마우스, 스토리지, 네트워크 카드 등) 로부터 CPU에 이르는 길로 이해하면 된다. 현대적으로는 IRQ는 논리적인 라인으로 인터럽트를 CPU에 전달하는 역할을 한다. 1. IRR은 Interrupt Request Register로서 1-bit register이다. 즉 각 인터럽트가 현재 있는지/없는지만 인식하는데, 이는 이미 쌓인 인터럽트에 대한 중복된 인터럽트 핸들링이 발생하지 않을 것임을 의미한다. 2. IRR에 쌓인 인터럽트들은 우선순위(priority)를 가지며, 우선순위가 높은 인터럽트가 먼저 선택된다. 선택된 인터럽트는 mask 된다 (Mask register에 mask되었다고 표시된다). Mask 된다는 것의 의미는 disable 된다는 것이고, 해당 인터럽트가 컨트롤러에 의해 다시 선택되는 것을 방지한다. 즉, 처리중인 인터럽트를 또 처리하려고 하지 않는다. 3. 우선순위가 높아 선택된 인터럽트 신호는 CPU에게 보내진다. MSI, MSI-X 처럼 message based interrupt 일 수도 있고, legacy interrupt (물리적인 IRQ 라인을 통해 인터럽트 전달) 일 수도 있다. 4. 인터럽트를 받은 CPU는 해당 IRQ 번호에 맞는 interrupt...

리눅스 커널 파일시스템 기본 [1]

이미지
파일시스템이란 하드디스크, SSD, 플래시 메모리와 같은 저장장치 위에 파일과 디렉터리를 체계적으로 정리(organize)하는 방법을 말합니다. 파일시스템의 종류는 매우 다양합니다 (FAT, ext4, btrfs, NTFS 등). 그리고 한 대의 컴퓨터에서 같은 파일시스템 종류가 여러 개 동시에 사용될 수도 있습니다. 파일시스템마다 파일과 디렉터리, 사용자 데이터, 그리고 내부적으로 사용하는 메타데이터를 관리하는 방식이 서로 다르긴 하지만, 거의 모든 파일시스템에 공통적으로 사용되는 몇 가지 기본 개념들이 있습니다 (이 중 일부 개념은 저장장치(storage)와 메모리 양쪽에 존재하고, 일부는 메모리에만 존재합니다.): 슈퍼블록(superblock) : 해당 파일시스템의 기본 정보를 담고 있습니다. 예를 들어 블록 크기, 루트 아이노드, 파일시스템 전체 크기 같은 정보죠. 슈퍼블록은 저장장치와 메모리 모두에 존재하는데, 메모리에는 속도 향상을 위한 캐싱 용도로 복사되어 있습니다. 파일(file) :현재 열려있는 파일에 관한 정보(예: 현재 읽기 위치 등)를 담고 있는데, 이 정보는 메모리에만 존재합니다. 아이노드(inode) : 아이노드는 디스크에 저장된 파일을 고유하게 식별하는 역할을 합니다. 아이노드는 파일 크기, 접근 권한, 파일 종류 등 다양한 속성도 함께 가지고 있죠. 이 아이노드는 저장장치와 메모리 양쪽에 존재하며, 메모리에는 캐시 목적 등으로 복사되어 있습니다. 덴트리(dentry) : 덴트리(dentry)는 파일 이름과 아이노드(inode)를 연결하는 역할을 합니다. 덴트리 역시 저장장치와 메모리 양쪽에 존재하며, 메모리에는 캐싱 목적으로 복사되어 있습니다. struct ext4_inode 내부의 i_block에서 스토리지의 각 block들을 가리킨다. EXT4_N_BLOCKS 크기는 15로 ext4가 지원하는 데이터 블록 주소 지정 방식의 표준 크기이며, 이를 통해 작은 파일부터 아주 큰 파일까지 효율적으로 저장 위치를 관리할 수 있습니...

리눅스 커널 코드 레이아웃

리눅스 소스코드의 top level directory Top level directory 들 중 주요한 것들을 살펴보자. arch - architecture specific code 이다. 각 아키텍처의 디렉토리 들이 있음 (arm, x86 등). block- block device에 대한 읽기/쓰기 관련 코드 drivers - 다양한 디바이스에 대한 커널 드라이버 fs - generic filesystem code 이다. kernel - process management code (scheduler, tracing, generic irq code, locking 등) mm - memory management code. physical/virtual memory를 모두 포함한다.

리눅스 커널 파일 시스템 [6] Folio

리눅스 커널 파일 시스템 이해를 위해 먼저 folio 개념에 대해 이해할 필요가 있다. 1. Folio의 탄생 배경과 역사 Folio는 리눅스 커널의 메모리 관리 시스템을 현대화하고, 특히 THP(Transparent Huge Pages)와 같은 대규모 페이지 관리의 복잡성을 해결하기 위해 도입되었습니다. 기존의 리눅스 커널은 메모리 관리의 기본 단위로 struct page 를 사용했습니다. struct page 는 실제 물리 메모리의 단일 페이지(일반적으로 4KB)를 나타내는 메타데이터 구조체입니다. 하지만 기술의 발전과 함께 메모리 집약적인 애플리케이션이 증가하면서, 4KB 페이지 단위로 메모리를 관리하는 것이 비효율적이라는 문제가 대두되었습니다. 예를 들어, 2MB 크기의 THP를 관리하기 위해서는 512개의 struct page 를 개별적으로 다루어야 했습니다. 이로 인해 메모리 관리 코드의 복잡성이 증가하고, 성능 저하의 원인이 되었습니다. Folio는 이러한 문제점을 해결하기 위해 2021년 리눅스 5.16 버전에 처음 도입되었습니다. Folio는 기존의 struct page 를 추상화하여, 여러 개의 연속된 물리 페이지(Contiguous Physical Pages)를 하나의 논리적 그룹으로 묶는 새로운 개념입니다. 이는 메모리 관리 코드를 단순화하고, 대규모 페이지를 더 효율적으로 다룰 수 있도록 하기 위함입니다. 2. Folio의 현재 모습과 역할 Folio는 struct page 의 상위 개념으로, 하나 이상의 연속된 페이지들을 나타내는 단일 객체입니다. 현재 리눅스 커널은 메모리 관리를 위해 대부분 Folio를 사용하며, 기존 struct page 기반의 API들을 Folio 기반으로 전환하고 있습니다. Folio의 주요 역할은 다음과 같습니다. 메모리 관리의 통일된 인터페이스 제공: Folio는 파일 시스템 캐시, 스왑, THP 등 다양한 메모리 관리 기능에 대해 일관된 인터페이스를 제공합니다. 기존에는 각 기능마다 페이지를 다루는...

리눅스 커널 파일 시스템 [5] Write

리눅스 커널 파일 시스템 Read [1] 리눅스 커널 파일 시스템 Read [2] 리눅스 커널 파일 시스템 Read [3] 리눅스 커널 파일 시스템 Read [4] Now, let's take a look at the write process. We'll examine what happens when a write system call is invoked and which kernel functions are called along the way. 나중에 영어로 바꾸는 작업을 해야겠다. 자 이제 write 시스템콜이 불렸을 때 커널의 어떤 함수들이 호출되는지 알아보자. 여전히 ext4 기준으로 살펴볼 것이다. SYSCALL_DEFINE3(write, ...) --> ksys_write() --> vfs_write() --> rw_verify_area() (유저 포인터 유효성, 파일 모드 검사) -- file->f_op->write_iter 가 있는지 검사 여기서 잠깐 write()가 있고 write_iter()가 있다. 무슨 차이일까? write()는 전통적인 방식이며 write_iter()는 보다 일반화되고 유연한 인터페이스이다. 비동기 I/O (AIO, 즉 write가 끝날 때까지 기다리지 않고 다음 작업 수행하도록 함), vectored I/O (scatter/gather I/O) 등을 지원한다. ext4에서는 write에 해당하는 함수가 없기 때문에 write_iter()가 불릴 것이다. 하지만 그 전에 다양한 I/O를 지원하기 위해 new_sync_write() 함수가 먼저 불려 AIO, vectored I/O 등을 위한 준비를 한다. -- new_sync_write() (중간 레이어) --> file->f_op->write_iter() == ext4_file_write_iter() --> ext4_buffered_write_iter() --> generic_perform_...

리눅스 커널 파일 시스템 [4] 정리 - Read

리눅스 커널 파일 시스템 Read [1] 리눅스 커널 파일 시스템 Read [2] 리눅스 커널 파일 시스템 Read [3] 1. 시스템콜이 vfs를 거쳐 각 파일시스템으로 간다. 2. 각 파일시스템에서 read를 어떻게 처리할지 결정 (Storage에서 바로 읽을지, Page cache에서 읽을지) 3. (Page cache에서 읽을 경우) mm/filemap.c의 generic_file_read_iter()로 간다. 디렉토리 명 (mm == memory management)에서 볼수 있듯이 이제 메인 메모리의 영역이다. Page cache는 메인 메모리에 저장되어 있다. 4. Storage의 해당 데이터가 메인 메모리에 있는지 살펴본다 (즉, 해당 데이터에 대한 page cache 가 존재하는지 살펴본다.) (이 단계는 filemap_get_pages()의 filemap_get_read_batch()에 의해 수행된다. page cache가 struct address_space *mapping에 존재하는지 살펴본다. 이때 xarray가 사용되는데 (xas_load, xas_next 같은 함수들), xarray는 매우 큰 인덱스 공간을 빠르게 탐색하는 동적 인덱싱 자료구조이다. 기존 radix tree를 대체한다.). 5. 해당 데이터에 대한 Page cache가 없다면 Storage로부터 Page cache에 데이터를 읽어온다 (filemap_read()를 통해 ext_readahead 까지 가게 된다.). 6. Page cache의 데이터를 사용자 공간으로 복사한다 (copy_folio_to_iter()). iocb->ki_pos에 업데이트된 file offset (파일 내에 I/O가 읽거나 쓸 위치)이 저장된다. 아래 함수 흐름을 살펴보자. read system call --> ksys_read() --> vfs_read() --> new_sync_read() --> ext4_file_read_iter() --> generi...

[OPIC] 추가 감정 표현

1. Happiness & Joy I feel happy when I spend time doing my favorite hobby. Paintng makes me feel joyful and relaxed. I was on cloud nine (하늘에 날아오를 듯한) when I finished my project successfully. I always feel upbeat (긍정적인, 낙관적인)after a good workout. I get so much enjoyment from reading a good book. 2. Calm & Relaxation I feel at peace when I listen to music. Yoga helps me feel peaceful and calm. This hobby gives me a blissful state of mind. Whenever I meditate, I feel completely tranquil. 3. Satisfaction, Pride & Accomplishment I feel fulfilled after volunteering at the local shelter. Completing a challenging puzzle gives me a sense of accomplishment. I feel proud of myself when I learn something new. I enjoy the sense of achievement my work brings me (내 일이 나에게 가져다주는 성취감). 4. Excitement & Anticipation I'm excited to start a new hobby. I always look forward to my weekend plans. I get butterflies in my stomach (긴장하거나 떨리다, 가슴이 조마조마하다) before trying something new. I was pu...

[OPIC] 기분/감정 표현

1. 평화로움/편안함 (Feeling Peaceful/Relaxed) I feel at peace when I'm floating on the water. Being in nature always makes me feel calm and relaxed. Swimming helps me clear my mind and forget about stress. I love the tranquil(고요한/평온한) atmosphere at the pool. 2. 행복/즐거움 (Feeling Happy/Joyful) I feel so happy when I spend time with my friends. It's always fun to try new activities. I get excited whenever I go swimming. I feel a sense of joy when I achieve somthing new. 3. 스트레스 해소/기분 전환 (Relieving Stress/Refreshing) Swimming is a great way for me to relieve stress. After exercising, I feel refreshed and energized. When I'm stressed out, I go for a swim to clear my head. 4. 자신감/성취감 (Confidence/Achievement) I feel proud of myslef when I learn a new skill. Completing a difficult workout gives me a sense of accomplishment. I gain confidence every time I improve my swimming skills. 5. 아쉬움/실망 (Disappointment/Regret) I feel disappointed when I can't go swimming because of the weather. So...

[OPIC] 문장 구조

 1. 원인 - 결과 구조 (Cause and Effect) I started swimming because I wanted to stay healthy. Since I began this hobby, I have felt much happier. 2. 비교, 대조 구조 (Comparison/Constrast) Swimming is more relaxing than running. Unlike other sports, swimming helps me clear my mind. 3. 경험 설명 구조 (Experience/Storytelling) One time , I forgot my swimsuit, so I had to borrow one from a friend. I remember the first time I learned how to float on water. 4. 의견 제시 구조 (Giving Opinions) In my opinion , swimminig is the best exercise. I believe that everyone should learn how to swim. 5. 조건문 (Conditional Sentences) If I have free time , I usually go swimming. If I hadn't learned to swim, I would have missed out on many fun experiences. 6. 이유 설명 구조 (Explaining Reasons) The reason I enjoy swimming is that it helps me relax after a long day. I like outdoor pools because I can enjoy the sunshine. 7. 과거와 현재 비교 (Past vs. Present) When I was younger , I was afraid of water. Now, I love swimming. In the pas...

리눅스 커널 파일 시스템 [3] 코드 분석 - page_cache_sync_ra()

리눅스 커널 파일 시스템 Read [1] 리눅스 커널 파일 시스템 Read [2] 리눅스 커널 파일 시스템 Read [3] 리눅스 커널 파일 시스템 Read [4]   이전 게시물 void page_cache_sync_ra(struct readahead_control *ractl, unsigned long req_count) { pgoff_t index = readahead_index(ractl); bool do_forced_ra = ractl->file && (ractl->file->f_mode & FMODE_RANDOM); struct file_ra_state *ra = ractl->ra; unsigned long max_pages, contig_count; pgoff_t prev_index, miss; /* * Even if readahead is disabled, issue this request as readahead * as we'll need it to satisfy the requested range. The forced * readahead will do the right thing and limit the read to just the * requested range, which we'll set to 1 page for this case. */ if (!ra->ra_pages || blk_cgroup_congested()) { if (!ractl->file) return; req_count = 1; do_forced_ra = true; } /* be dumb */ if (do_forced_ra) { force_page_cache_ra(ractl, req_count); return; } max_pages = ractl_max_pages(ractl, req_count); prev_index = (unsig...

리눅스 커널 파일 시스템 - F2FS

F2FS Flash Friendly File System (F2FS), Embedded Linux Conference  (2013-02-22) 위 발표자료를 보면서 공부해보자. Log-structured File System (LFS) fits well to FTL devices. data와 metadata를 연속적으로 "쓰기"한다. 논문을 봐야 이해가 될 것 같다. 논문은 2015년이다. https://www.usenix.org/system/files/conference/fast15/fast15-paper-lee.pdf 문제점: Frequent random writes --> internal fragmentation --> I/O latency, device lifetime에 악영향 해결책: Log-structured file system (LFS) 과 copy-on-write (CoW) 결합 예를 들어 BTRFS파일시스템은 NAND flash SSD에서 성능이 잘 나올 것임 - 하지만 Flash storage에 대한 고려가 부족하여 성능과 lifetime이 아주 좋지는 않을 것임. LFS 기존 데이터를 덮어쓰지 않고 새로운 공간에 기록 후 추후 Garbage Collection (GC) 한다. random/sequential write에는 잘 맞지만 sequential read 시에는 성능 떨어질 수 있음. CoW 수정이 일어나면 기존 데이터를 덮어쓰지 않고, 새로 복사본을 만들어 그 복사본에 수정하는 기법. 데이터 일관성 유지 (crash 나도 기존 데이터 존재함)에 도움이 된다. 그리고 overwrite에 취약한 SSD에 좋다. (예시: Btrfs) 일관성 유지 측면: 1. 파일 A가 block #100 ~ #110 차지 2. 파일 A 일부 수정 요청 3. 파일 시스템은 block #100 덮어쓰지 않음 4. 대신 block #200에 새로 쓴 뒤, inode를 block #200으로 바꿈 5. crash 나도 block...

리눅스 커널 파일 시스템 [2] 코드 분석 - generic_file_read_iter()

리눅스 커널 파일 시스템 Read [1] 리눅스 커널 파일 시스템 Read [2] 리눅스 커널 파일 시스템 Read [3] 리눅스 커널 파일 시스템 Read [4] Page cache와 관련된 코드를 함께 먼저 보기 위해 generic_file_read_iter() 부터 분석한다. 이전 게시물 mm/filemap.c generic_file_read_iter() 정의 먼저 이 함수 위 주석을 보자. /**  * generic_file_read_iter - generic filesystem read routine  * @iocb: kernel I/O control block  * @iter: destination for the data read  *  * This is the "read_iter()" routine for all filesystems  * that can use the page cache directly .  *  * The IOCB_NOWAIT flag in iocb->ki_flags indicates that -EAGAIN shall  * be returned when no data can be read without waiting for I/O requests  * to complete ; it doesn't prevent readahead. --> IOCB_NOWAIT flag가 있으면 prefetch를 막지 않는다고 함. --> "I/O requests가 complete 되는 것을 기다리지 않고" -EAGAIN이 리턴된다는 것임. --> Prefetch (readahead) 던져 놓고 리턴될거야~ 라는 것인 듯.  *  * The IOCB_NOIO flag in iocb->ki_flags ...

리눅스 커널 파일 시스템 [1] Top View 및 코드 분석 그리고 그 너머

리눅스 커널 파일 시스템 Read [1] 리눅스 커널 파일 시스템 Read [2] 리눅스 커널 파일 시스템 Read [3] 리눅스 커널 파일 시스템 Read [4] 본 공부에서 다루게 되는 내용 및 리눅스 커널 버전 선정