본문 바로가기
Kernel/Documentation

[Linux Kernel] 리눅스 커널 개발 가이드: Advanced Topics

by hyeyoo 2021. 9. 16.
※ 이 블로그의 글은 글쓴이가 공부하면서 정리하여 쓴 글입니다.
※ 최대한 내용을 검토하면서 글을 쓰지만 틀린 내용이 있을 수 있습니다.
※ 만약 틀린 부분이 있다면 댓글로 알려주세요.
 

7. Advanced topics — The Linux Kernel documentation

At this point, hopefully, you have a handle on how the development process works. There is still more to learn, however! This section will cover a number of topics which can be helpful for developers wanting to become a regular part of the Linux kernel dev

www.kernel.org

매번 썸네일용 사진 고르는 것도 일이다. 오늘은 심플하게 가자.

 

여기까지 읽었으면 어떻게 커널을 개발하는지 감이 왔을 것이다. 하지만 아직 배울게 좀더 남았다! 이 글에서는 개발자들이 리눅스 커널을 정규적으로 개발하는 데 도움이 되는 내용을 다룰 것이다.

7.1 Managing patches with git

리눅스에서 분산 버전 컨트롤 시스템을 사용한 것은 Linus가 BitKeeper라는 사유 소프트웨어를 갖고 놀기 시작한 2002년 부터이다. BitKeeper는 논란이 되긴 했지만, BitKeeper가 가진 소프트웨어 버전 관리라는 개념 자체는 의미가 있었다. 분산 버전 컨트롤 시스템은 커널의 개발에 속도를 가했다. 당시에는 BitKeeper 밖에 없었지만 지금은 무료로 쓸 수 있는 툴이 여럿 있다. 좋든 나쁘든 리눅스 커널은 git에 정착했다.

 

git으로 패치를 관리하면 좀더 일이 수월해진다. (특히 패치가 매우 많아질 때) 물론 Git도 단점이 있다. git은 나온지 얼마 안됐고, 강력한 도구라서 지금도 개발자들 사이에서 널리 퍼지고 있다. 이 글에서는 git의 사용법을 다루지는 않을 것이다. 대신 git을 커널 개발 프로세스에서 어떻게 사용할지를 다룬다. git에 대한 정보를 얻으려면:

 

 

Git

 

git-scm.com

 

Git User Manual

Many of the higher-level commands were originally implemented as shell scripts using a smaller core of low-level Git commands. These can still be useful when doing unusual things with Git, or just as a way to understand its inner workings. High-level opera

mirrors.edge.kernel.org

우선 깃에 익숙해질 필요가 있다. 메인라인 저장소를 클론하고, 히스토리를 읽어보고, 수정한 내용을 커밋하고, 브랜치를 다루는 법 등을 알아야한다. 그리고 히스토리를 다시 작성하는 것도 (rebase 처럼) 유용하다. Git에는 index, refs, branches, fast-forward muerges, pushes, pulls, detached heads 등 다양한 개념이 존재하므로 이런 것들도 알아두어야 한다. Git은 두렵게 느껴질 수 있지만 배우다보면 그렇게 어렵지는 않다. git으로 패치를 만들어서 이메일로 제출하는 것도 좋은 연습이 된다.

 

물론 git으로 수정한 것을 다른 사람들이 사용할 수 있게 하려면 서버가 필요하다. git-daemon으로 서버를 만드는 것도 복잡하지 않고 인터넷에 잘 나와있다. 아니면 github같은 무료 호스팅 사이트를 찾아보는 것도 나쁘지 않다. 아니면 kernel.org 계정을 받아서 사용할 수도 있지만, 계정을 얻기가 쉽지는 않다. 자세한 건 https://www.kernel.org/faq.html를 참고하자.

 

git으로 작업을 하다보면 브랜치를 많이 쓰게 된다. 각각의 작업은 주제별로 브랜치를 나눠서 독립적으로 진행할 수 있다. 브랜치는 무겁지 않고, 쓰지 않을 이유가 없다. 그리고 개발을 하는 브랜치와 다른 사람들이 pull을 하도록 만드는 브랜치는 구분을 확실하게 해야한다. 후자 브랜치에서 개발을 하면 안된다. 공개적으로 사용하는 브랜치는 주의를 기울여서 만들어야 한다. 따라서 개발용으로 브랜치를 따로 만들고 충분히 개발이 된 후에 공개용 브랜치에 머지하자.

 

Git은 개발 히스토리를 수정할 수 있는 강력한 도구를 제공한다. 문제가 있는 패치 (bisection (이분 탐색으로 문제가 되는 패치를 찾는 방법)을 방해하거나, 명백한 버그가 있는)를 그 자리에서 내용만 고치거나 히스토리에서 아예 없애버릴 수도 있다. 패치 시리즈를 몇달동안 작업했더라도 히스토리를 적절하게 수정해서 항상 최신 메인라인 커널 위에서 작업한 것 처럼 만들 수 있다. 그리고 이렇게 히스토리를 변경한 것은 한 트리에서 다른 트리로 이동할 수 있다. git으로 현명하게 히스토리를 수정하면 큰 문제 없이 깔끔한 패치 시리즈를 만들 수 있다.

 

물론 과도하게 히스토리를 수정하면 문제가 될 수 있다. 히스토리를 수정하면 기존에 테스트한 부분도 다시 테스트해야하기 때문이다. 그리고 히스토리가 계속 바뀌면 개발자들 사이에서 혼란이 생길 수 있다. 따라서 이미 다른 사람에게 공개한 히스토리는 수정하지 않는다는 규칙을 지켜야한다.

 

그래서 공개된 서버에 푸시를 한 이후에는 히스토리를 수정하지 않아야 한다. Git은 fast-forward merge (예를 들어 서로 똑같은 히스토리를 공유하지 않는 패치가 존재)를 못하게 해서 푸시된 이후에는 히스토리 수정을 못하게 강제하려고 한다. fast-forward merge를 강제할 수도 있긴 하다. 이미 공개한 트리의 히스토리를 꼭 수정해야 할 상황도 가끔 있다. 예를 들어 linux-next에서의 충돌을 피하기 위해 히스토리를 수정하는 상황이 있다. 하지만 자주 이런 방법을 사용해서는 안된다. 따라서 개발은 얼마든지 히스토리를 수정할 수 있는 비공개 브랜치에서 한 후에 충분히 준비가 되었을 때 공개해야 한다.

 

메인라인 (또는 당신이 작업하는 기반 트리)에 다른 패치들이 추가됨에 따라서, 그것을 당신이 작업하는 브랜치에 머지해서 최신 상태로 유지하고 싶은 욕구가 들 수 있다. 비공개 브랜치의 경우에는 rebase를 쉽게 할 수 있지만, 이미 공개된 후에는 해서는 안된다. 공개된 브랜치를 최신으로 유지하려면 모두 머지를 해야한다. 물론 머지를 할수도 있지만 계속해서 하다보면 히스토리가 불필요하게 혼란스러워진다. 따라서 이런 경우에는 주기적으로 최신 트리를 머지하지 말고, -rc, -stable 등 특정 릴리즈 지점에서 머지하는 것이 좋다. 만약 실수를 할 것 같다면 비공개 브랜치에서 머지가 제대로 되는지 테스트를 해보자. git의 "rerere" 기능은 이런 상황에서 도움이 된다. rerere는 기존 머지에서 충돌이 어떻게 났는지를 기억하고 같은 일을 다시 반복하지 않게 도와준다. (비공개 브랜치에서 머지를 테스트할 때 해결한 것을 공개 브랜치에서 다시 반복하지 않아도 된다.)

 

사람들이 가장 많이, 그리고 자주 하는 실수는 한 저장소에서 다른 저장소로 수많은 패치를 보내는 것이다. (리뷰가 어려울 정도로) 이러면 리뷰를 하기가 어려워지기 쉽상이다. 커널 개발자들은 이런 상황이 발생하면 불쾌해하는 경향이 있다. git 트리에 리뷰되지 않거나 주제와 관련없는 패치가 가득하면 다른 사람이 pull을 하지 않을 것이다. Linus의 말을 인용해본다.

 

나한테 패치를 보내라. 하지만 내가 그걸 pull하려면 모든 패치를 하나하나씩 확인하는 게 아니라 당신을 신뢰해서 당신이 무슨 작업을 하고 있는지 알아야 한다.
https://lwn.net/Articles/224135/

이런 상황을 피하려면 브랜치의 패치들이 하나의 주제와 관련이 되어있어야 한다. 예를 들어 "driver fixes" 브랜치는 메모리 관리 코드를 수정하면 안된다. 그리고 가장 중요하게, 패치의 리뷰를 우회하기 위해 git 트리를 사용해서는 안된다. 트리와 관련된 메일링 리스트에 트리를 요약해서 설명하고, 때가 되면 linux-next에 수정한 내용을 포함 해달라고 요청해야 한다.

 

다른 사람들이 당신의 트리에 패치를 보낼 때는 리뷰하는 것을 잊지 말자. 그리고 그 패치를 누가작성했는지 올바르게 기록해야 한다. git "am" 도구도 이런 기능이 있지만, 제 3자를 통해 패치를 받은 경우에는 패치에 "From:"을 추가해야 할 수도 있다.

 

pull을 요청할 때는 트리가 어디게 있는지, 어떤 브랜치를 pull해야 하는지, 그리고 pull을 하면 무엇이 바뀌는지 자세하게 설명해야 한다. git request-pull 명령어는 이럴때 유용하게 사용할 수 있다. 이 명령어는 다른 개발자가 보기 쉽게 pull 요청을 형식에 맞춰 작성해준다. 그리고 당신이 수정 사항을 서버에 push했는지도 확인해준다.

 

7.2 Reviewing Patches

몇몇 독자들은 패치 리뷰를 "advanced topics"에서 다루는걸 반대할 것이다. 왜냐하면 처음 시작하는 개발자들조차 패치 리뷰를 해야하기 때문이다. 커널을 개발하는 방법을 배우기엔 코드를 보는 것보다 좋은 방법은 없다는 건 사실이다. 그리고 리뷰어는 항상 부족하므로 코드를 리뷰해서 개발 프로세스 전체에 상당한 기여를 할 수 있다.

 

코드 리뷰가 두려울 수도 있다. 특히 더 경험많은 사람들의 코드를 공개적으로 질문하기가 망설여지는 신입 커널 개발자에게는 더욱 그렇다. 하지만 아무리 경험이 많은 개발자가 작성한 코드라도 항상 개선의 여지는 있다.  아마도 모든 리뷰어에게 도움이 되는 조언은 코드를 비평하는 게 아니라 질문을 하라는 것이다. "이 경우에 락이 어떻게 해제되나요?"라고 뭇는 것이 "락이 잘못되었습니다"라고 말하는 것보다 항상 낫다.

 

개발자에 따라 코드를 다른 관점에 따라 리뷰한다. 몇몇 사람들은 코딩 스타일이나 공백을 중점으로 보기도 하고, 누군가는 패치가 커널에 좋은지 나쁜지를 중점으로 보기도 한다. 또, 누군가는 문제가 있는 락, 과도한 스택 사용, 잠재적 보안 이슈, 다른 코드와 중복되는 부분, 문서화가 충분한지, 성능에 악영향이 있는지, 사용자 공간 ABI가 바뀌는지 등을 점검할 것이다. 커널에 더 나은 코드를 작성할 수 있다면 모든 리뷰는 가치가 있다.

댓글