Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

230224
1178
109352


리눅스 커널 기여(Contribution) - 패치 작성 및 패치 반영(Contribution) 확인하기 Linux Kernel Contribution


From...


이전 시간에는 리눅스 커널 기여(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 


패치 확인하기 

아래 커널 메일링 리스트 아카이브 사이트에 가보면,

제가 올린 패치를 확인할 수 있는데 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일 후에 아래 사이트에서 가보니,
 
제가 작성한 패치가 리눅스 커널 메인 소스 코드에 반영(Upstream)된 것을 확인할 수 있습니다.

위치




 

"혹시 궁금한 점이 있으면 댓글로 질문 남겨주세요. 아는 한 성실히 답변 올려드리겠습니다!" 

Thanks,
Austin Kim(austindh.kim@gmail.com)

핑백

덧글

댓글 입력 영역