Kernel/Theory

[Linux Kernel] alloc_thread_stack_node() 함수 분석

Karatus 2021. 9. 29. 01:00
반응형

'디버깅을 통해 배우는 리눅스 커널의 구조와 원리' 책을 읽으면서 정리를 하다가 한 가지 코드 상의 차이를 발견했다.

커널 버전은 책에 나온 대로 v4.19다.

 

개요

프로세스가 새로 생성될 때 불리는 _do_fork() 함수 내 copy_process() 함수에서 일어나는 동작 중 하나로 프로세스가 이용할 스택을 할당하는 게 있다.

태스크 디스크립터 생성하고 slab cache에서 스택 공간 할당받는 함수인 alloc_thread_stack_node() 함수가 있는데 책에 있는 코드와 구현 상의 차이가 있길래 초보자 입장에서는 흥미롭게 다가왔다.

Before

static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node)
{
	...
    
    return page ? page_address(page) : NULL;
}

After

static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node)
{
	...
    
    if (likely(page)) {
		tsk->stack = page_address(page);
		return tsk->stack;
	}
	return NULL;
}

책의 저자이신 AustinKim(김동현)님이 쓸 때만 해도 v4.19.98 이하 버전이라 Before의 소스였는데 v4.19.99로 올라오면서 뭔가 더 다듬어진 코드로 바뀐 걸 확인할 수 있었다.

그냥 '음 바뀌었구나...'라고 생각하고 넘어갈 수도 있었지만 문득 궁금해졌다. 정확히 무슨 이유 때문에 저렇게 패치를 한 걸까?

 

Search

Kernel Mailing List의 방대한 아카이브를 처음으로 찾아보는 거라 좀 긴장했는데 구글링 해서 도움 되는 사이트들을 이용해서 찾았다.

▶ 검색에 쓰인 사이트들

더보기
더보기

https://unix.stackexchange.com/questions/90080/how-do-i-search-the-linux-kernel-mailing-list-archives

 

How do I search the linux kernel mailing list archives?

I want to research why a Linux kernel feature appears to be missing from my Linux install by searching the Linux kernel mailing list for recent discussions on the subject. The only site that I've ...

unix.stackexchange.com

답변의 여러 링크 중 실질적으로 도움을 받은 사이트 ↓

https://marc.info/?l=linux-kernel 

 

MARC: Mailing list ARChives

 

marc.info

Tip) 커널 버전을 특정해서 검색해도 좋고 author를 기준으로 검색해도 좋고 다 좋은데

원하는 커널 버전 + 궁금한 파일의 이름(이 글 기준으로는 fork) + 함수 이름 혹은 특정 변수

를 알고 검색하면 쉽게 찾을 수 있다.

그래도 못 찾겠으면 특정 버전의 리뷰 안에 리스트 있으니까 검색해서 찾으면 된다.

ex. [PATCH 4.19 000/639] 4.19.99-stable review

 

여차저차 해서 Andrea Arcangeli 님이 리퀘스트한 메일 내용을 볼 수 있었다.

https://marc.info/?l=linux-kernel&m=157986512931731&w=2

 

'[PATCH 4.19 454/639] fork,memcg: alloc_thread_stack_node needs to set tsk->stack' - MARC

 

marc.info

수정한 이유는 다음과 같다.

페이지를 할당한 다음에는 반드시 가상 주소로 변환해야 하는데 해당 가상화에 관여하는 config 옵션이 VMAP_STACK=y다. 일반적인 상황에서 Enterprise kernel은 이 설정을 바꾸지 않지만 custom 해서 성능상 이득을 보기 위해 해당 옵션을 n으로 설정해 꺼놓고 사용했다.

여기서 기존 코드는 tsk->stack을 초기화해주지 않음으로 생겨나는 dangling pointer 때문에 free_thread_stack() 함수에서 compaction fail이 일어나 크래시가 발생한다는 것이다.

Before, After 코드는 해당 옵션이 꺼진 상태에서 alloc_thread_stack_node() 함수가 매크로에 의해 정의되는 코드다. 보면 실제로 tsk->stack이 초기화되지 않는다. 이 때문에 free_thread_stack() 함수를 부를 때 초기화되지 않은 tsk->stack을 free 하려고 해서 크래시가 일어나는 것이다.

결국 Andrea Arcangeli 님이 회사에서 BSP 개발하다가 일어난 버그 고치기 위해 컨트리뷰션 한 것이라 판단할 수 있다.

 

Conclusion

간단한 코드 리뷰였지만 처음이라 설레었다. 덕분에 커널 세계에 발톱 끝을 담가본 느낌이다.

하지만 아직 기본기가 탄탄하지 않으니 앞으로 열심히 해서 오픈 소스 컨트리뷰터가 되고 싶다 ㅎㅎ.


Reference

 

Dangling pointer - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search Pointer that does not point to a valid object Dangling pointers and wild pointers in computer programming are pointers that do not point to a valid object of the appropriate type. Thes

en.wikipedia.org

 

 

fork.c - kernel/fork.c - Linux source code (v4.19.206) - Bootlin

 

elixir.bootlin.com

 

반응형