리눅스 커널 기여(Contribution) - 패치 작성 및 패치 반영(Upstream) 확인하기
이전 시간에는 리눅스 커널 기여(Contribution) 하기 전에 준비해야 할 사항을 소개했습니다.
- gmail 계정 생성
- mutt 설치 및 설정
이번 시간에는 커널 패치를 작성해보고 패치를 리눅스 매인테이너(Maintainer)에게 보내는 과정을 소개합니다.
그리고 업스트림(Upstream)된 패치를 확인하는 방법도 말씀드리겠습니다.
<< 오류 코드 확인하기 >>
먼저 패치를 작성하기 전 커널 코드를 볼까요?
참고로 다음 함수는 AMD/PowerPlay 드라이버입니다.
[drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c] 01 static int smu8_start_smu(struct pp_hwmgr *hwmgr) 02 { 03 struct amdgpu_device *adev = hwmgr->adev; 04 05 uint32_t index = SMN_MP1_SRAM_START_ADDR + 06 SMU8_FIRMWARE_HEADER_LOCATION + 07 offsetof(struct SMU8_Firmware_Header, Version); 08 09 if (hwmgr == NULL || hwmgr->device == NULL) 10 return -EINVAL; 11 12 cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index); 13 hwmgr->smu_version = cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA); 14 pr_info("smu version %02d.%02d.%02d\n",
먼저 03번째 줄 코드를 보겠습니다.
03 struct amdgpu_device *adev = hwmgr->adev;
위 코드 왼쪽 부분을 눈으로 따라가 봅시다.
struct pp_hwmgr 타입인 hwmgr 포인터의 adev 필드를 struct amdgpu_device 구조체 타입인 adev에 저장합니다.
뭐가, 문제란 소리지?
조금만 더 읽어주세요. 다음 09~10번째 줄 코드를 분석하겠습니다.
09 if (hwmgr == NULL || hwmgr->device == NULL) 10 return -EINVAL;
smu8_start_smu() 함수 인자로 전달된 'hwmgr' 포인터나 'hwmgr->device' 포인터가 NULL이면
-EINVAL를 반환합니다.
여기까지 코드를 분석하고 나면 '뭐가 문제지?'란 생각이 들 수 있습니다. 하지만 논리적인 오류가 있습니다.
09~10번째 줄 코드와 같이 'hwmgr' 포인터나 'hwmgr->device' 포인터가 NULL을 체크한 다음에
다음 코드를 실행했어야 합니다.
03 struct amdgpu_device *adev = hwmgr->adev;
'hwmgr' 포인터가 NULL이면 03번째 줄에서 NULL Pointer Dereference(NULL 포인터 역참조)로 커널 패닉이 먼저 발생합니다.
<< 패치 코드 작성하기 >>
오류 코드를 확인한 다음에 패치 코드를 작성했습니다.
[drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c] 01 static int smu8_start_smu(struct pp_hwmgr *hwmgr) 02 { 03 struct amdgpu_device *adev; 04 05 uint32_t index = SMN_MP1_SRAM_START_ADDR + 06 SMU8_FIRMWARE_HEADER_LOCATION + 07 offsetof(struct SMU8_Firmware_Header, Version); 08 09 if (hwmgr == NULL || hwmgr->device == NULL) 10 return -EINVAL; 11 12 adev = hwmgr->adev; 13 14 cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index); 15 hwmgr->smu_version = cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA); 16 pr_info("smu version %02d.%02d.%02d\n",
09~10번째 줄 코드와 같이 'hwmgr' 포인터나 'hwmgr->device' 포인터가 NULL을 먼저 체크한 다음에
다음 12번째 줄 코드를 실행합니다.
12 adev = hwmgr->adev;
이제 패치 코드 포멧으로 확인해보겠습니다.
austindh.kim~/src/linux_kernel_source/linux-next$ git diff diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c index 8189fe4..4728aa2 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c @@ -722,16 +722,17 @@ static int smu8_request_smu_load_fw(struct pp_hwmgr *hwmgr) static int smu8_start_smu(struct pp_hwmgr *hwmgr) { - struct amdgpu_device *adev = hwmgr->adev; + struct amdgpu_device *adev; uint32_t index = SMN_MP1_SRAM_START_ADDR + SMU8_FIRMWARE_HEADER_LOCATION + offsetof(struct SMU8_Firmware_Header, Version); - if (hwmgr == NULL || hwmgr->device == NULL) return -EINVAL; + adev = hwmgr->adev; + cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index); hwmgr->smu_version = cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA); pr_info("smu version %02d.%02d.%02d\n",
<< 패치 커밋 생성하기 >>
이제는 리눅스 커널 메인테이너에게 보낼 커밋 패치를 작성해보겠습니다.
먼저 'git status' 명령어를 입력해볼까요?
austindh.kim~/src/linux_kernel_source/linux-next$ git status On branch master Your branch is up-to-date with 'origin/master'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c
이번에는 커밋을 하나 생성합니다.
austindh.kim~/src/linux_kernel_source/linux-next$ git add drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c austindh.kim~/src/linux_kernel_source/linux-next$ git commit -m "drm/amdgpu: Move null pointer dereference check"
커밋에 대한 설명이 필요하니 'git commit --amend' 명령어를 입력해 패치 내용을 추가합니다.
austindh.kim~/src/linux_kernel_source/linux-next$ git commit --amend 1 drm/amdgpu: Move null pointer dereference check 2 3 Null pointer dereference check should have been checked, 4 ahead of below routine. 5 struct amdgpu_device *adev = hwmgr->adev; 6 7 With this commit, it could avoid potential NULL dereference. 8 # Please enter the commit message for your changes. Lines starting 9 # with '#' will be ignored, and an empty message aborts the commit. 10 # 11 # Date: Thu Aug 30 17:07:04 2019 +0900 12 # 13 # On branch master 14 # Your branch is ahead of 'origin/master' by 1 commit. 15 # (use "git push" to publish your local commits) 16 # 17 # Changes to be committed: 18 # modified: drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c 19 #
다음 3~7번째 줄 메시지를 추가했습니다. 패치가 무엇인지 정확히 기입했습니다.
1 drm/amdgpu: Move null pointer dereference check 2 3 Null pointer dereference check should have been checked, 4 ahead of below routine. 5 struct amdgpu_device *adev = hwmgr->adev; 6 7 With this commit, it could avoid potential NULL dereference.
이번에는 'git log -p' 명령어를 입력해 소스 내역과 커밋을 함께 확인합시다.
austindh.kim~/src/linux_kernel_source/linux-next$ git log -p commit 27b1f563c69f6a4af66ea8ccd8a1643c072b8299 Author: Austin Kim <austindh.kim@gmail.com> Date: Thu Aug 29 17:08:38 2019 +0900 drm/amdgpu: Move null pointer dereference check Null pointer dereference check should have been checked, ahead of below routine. struct amdgpu_device *adev = hwmgr->adev; With this commit, it could avoid potential NULL dereference. Signed-off-by: Austin Kim <austindh.kim@gmail.com> --- drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c index 8189fe4..4728aa2 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c @@ -722,16 +722,17 @@ static int smu8_request_smu_load_fw(struct pp_hwmgr *hwmgr) static int smu8_start_smu(struct pp_hwmgr *hwmgr) { - struct amdgpu_device *adev = hwmgr->adev; + struct amdgpu_device *adev; uint32_t index = SMN_MP1_SRAM_START_ADDR + SMU8_FIRMWARE_HEADER_LOCATION + offsetof(struct SMU8_Firmware_Header, Version); - if (hwmgr == NULL || hwmgr->device == NULL) return -EINVAL; + adev = hwmgr->adev; + cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index); hwmgr->smu_version = cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA); pr_info("smu version %02d.%02d.%02d\n",
이번에는 'git format-patch -1' 명령어를 입력해 패치 파일을 하나 생성합니다.
austindh.kim~/src/linux_kernel_source/linux-next$ git format-patch -1 0001-drm_amdgpu_Move_null_pointer_dereference_check.patch
ls '파일명' 포멧으로 명령어를 입력하니 '0001-drm_amdgpu_Move_null_pointer_dereference_check.patch' 파일이 생성됐음을 확인할 수 있습니다.
austindh.kim~/src/linux_kernel_source/linux-next$ ls 0001-drm_amdgpu_Move_null_pointer_dereference_check.patch
이번에는 './scripts/checkpatch.pl' 스크립트를 실행해 패치 코드의 포멧을 확인합니다.
austindh.kim~/src/linux_kernel_source/linux-next$ ./scripts/checkpatch.pl 0001-drm_amdgpu_Move_null_pointer_dereference_check.patch 0001-drm_amdgpu_Move_null_pointer_dereference_check.patch has no style problems, please review. NOTE: If any of the errors are false positives, please report them to the maintainer, see CHECKPATCH in MAINTAINERS.
이제 mutt 프로그램을 사용해 작성한 패치 세트를 커널 메인테이너에게 송부합니다.
austindh.kim~/src/linux_kernel_source/linux-next$ mutt -H 0001-drm_amdgpu_Move_null_pointer_dereference_check.patch
<< 패치 확인하기 >>
아래 커널 메일링 리스트 아카이브 사이트에 가보면,
https://lkml.org/lkml/2019/8/30/644
제가 올린 패치를 확인할 수 있는데 drm/amdgpu subsystem maintainer께서 다음과 같은 커맨드를 하셨음을 알 수 있습니다.
Applied. thanks! Alex
커맨트 내용은 다음과 같습니다.
From Alex Deucher <> Date Fri, 30 Aug 2019 11:09:43 -0400 Subject Re: [PATCH] drm/amdgpu: Move null pointer dereference check share On Fri, Aug 30, 2019 at 8:43 AM Austin Kim <austindh.kim@gmail.com> wrote: > > Null pointer dereference check should have been checked, > ahead of below routine. > struct amdgpu_device *adev = hwmgr->adev; > > With this commit, it could avoid potential NULL dereference. > > Signed-off-by: Austin Kim <austindh.kim@gmail.com> Applied. thanks! Alex > --- > drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c | 5 +++-- > 1 file changed, 3 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c > index 8189fe4..4728aa2 100644 > --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c > +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c > @@ -722,16 +722,17 @@ static int smu8_request_smu_load_fw(struct pp_hwmgr *hwmgr) > > static int smu8_start_smu(struct pp_hwmgr *hwmgr) > { > - struct amdgpu_device *adev = hwmgr->adev; > + struct amdgpu_device *adev; > > uint32_t index = SMN_MP1_SRAM_START_ADDR + > SMU8_FIRMWARE_HEADER_LOCATION + > offsetof(struct SMU8_Firmware_Header, Version); > > - > if (hwmgr == NULL || hwmgr->device == NULL) > return -EINVAL; > > + adev = hwmgr->adev; > + > cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index); > hwmgr->smu_version = cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA); > pr_info("smu version %02d.%02d.%02d\n", > -- > 2.6.2 >
3일 후에 아래 사이트에서 가보니,
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/
제가 작성한 패치가 리눅스 커널 메인 소스 코드에 반영(Upstream)된 것을 확인할 수 있습니다.
리눅스 커널 프로젝트 Contribution(기여)에 관심이 있는 분은 이 포스팅의 글을 참고하시면 좋을 것 같습니다.
(개인블로그)
http://rousalome.egloos.com/
제가 C언어를 몰라서 이 글타래를 이해는 못했지만,,
제가 C언어를 몰라서 이 글타래를 이해는 못했지만,,,
그 느낌만은 진짜 멋있습니다!!! 그저 순수하게 +1 좋아요를 누르고 싶어요!!!
리눅스를 좋아해주셔서 정말 감사드립니다^^^
[크롬북 우분투 18.04에서 댓글을 적었어요]
제 글에 응원주셔서 감사합니다..
이렇게 리눅스를 좋아하시는 분이 있어 기쁩니다.
(개인블로그)
http://rousalome.egloos.com
Gmane 에서 겨우 찾았어요 ;;;
진심으로 축하드립니다! 그리고 감사드립니다^^^
[크롬북 우분투 18.04에서 적었어요]
--
^고맙습니다 감사합니다_^))//
리눅스 커널 메일링 리스트 인증 샷이네요 ^^
제가 올린 패치의 리눅스 커널 메일링 리스트 '인증 샷'까지 올려주셨군요.
감사합니다.
(개인블로그)
http://rousalome.egloos.com
댓글 달기