Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

8200
629
98815


[리눅스커널] 동기화: 스핀락 자료구조 알아보기 9장. 커널동기화(스핀락/뮤텍스)

스핀락 구조체나 자료구조는 다음과 같은 관점으로 분석하면 이해가 빠릅니다. 

    스핀락을 획득하거나 해제할 때 어떤 필드가 바뀔까?
   스핀락을 획득했다고 어떻게 판단할까?

이 점을 염두하고 스핀락을 표현하는 자료구조를 분석하겠습니다. 다음은 스핀락을 표현하는 자료구조인 spinlock_t 구조체 선언부입니다.
[https://elixir.bootlin.com/linux/v4.19.30/source/include/linux/spinlock_types.h]
1 typedef struct spinlock {
2 union {
3 struct raw_spinlock rlock;
4 };
5 } spinlock_t;

spinlock_t은 struct spinlock 자료형이며 struct raw_spinlock 타입인 rlock 필드로 구성돼 있습니다.

이어서 struct raw_spinlock 구조체를 볼까요?
[https://elixir.bootlin.com/linux/v4.19.30/source/include/linux/spinlock_types.h]
typedef struct raw_spinlock {
arch_spinlock_t raw_lock;
#ifdef CONFIG_DEBUG_SPINLOCK
unsigned int magic, owner_cpu;
void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
} raw_spinlock_t;

라즈비안에서는 기본으로 CONFIG_DEBUG_SPINLOCK와 CONFIG_DEBUG_LOCK_ALLOC 컨피그가 꺼져 있습니다. 따라서 struct raw_spinlock 구조체 선언부는 다음과 같습니다.
typedef struct raw_spinlock {
arch_spinlock_t raw_lock
} raw_spinlock_t;

raw_spinlock_t은 struct raw_spinlock 자료형이며 struct arch_spinlock_t 타입인 raw_lock 필드로 구성돼 있습니다. 이어서 arch_spinlock_t 구조체를 볼까요?
[https://elixir.bootlin.com/linux/v4.19.30/source/arch/arm/include/asm/spinlock_types.h]
typedef struct {
union {
u32 slock;
struct __raw_tickets {
u16 owner;
u16 next;
} tickets;
};
} arch_spinlock_t;

arch_spinlock_t 구조체 세부 필드는 위와 같습니다.  
union 키워드로 u32 slock와 struct __raw_tickets 구조체로 구성돼 있습니다.

struct __raw_tickets 구조체 필드는 각각 u16 owner와 u16 next 인 것입니다.

구조체 선언부를 보니 조금 복잡한 것 같습니다.
분석한 내용을 정리하면 spinlock_t 구조체는 다음 흐름으로 계속 캐스팅을 할 수 있습니다.
spinlock_t(struct spinlock): 리눅스 커널 공통
raw_spinlock_t(struct raw_spinlock): 아키텍처 인터페이스 자료구조
arch_spinlock_t(struct __raw_tickets): 아키텍처 내 자료구조

이렇게 스핀락 구조체 선언부가 복잡한 이유는 스핀락 자료구조는 아키텍처(ARMv7, ARMv8, x86, PowerPC)마다 다르기 때문입니다. 

    그러면 spinlock_t 구조체는 리눅스 커널에서 어떻게 동작할까요?

리눅스 커널에서 아키텍처에 무관한 함수에 스핀락 함수를 호출할 때 spinlock_t 구조체를 씁니다. 그런데 아키텍처에 따라 커널 빌드를 하면 spintlock_t 구조체는 아키텍처에 맞는 자료 구조로 변환되서 컴파일이 됩니다.

이번에는 spinlock_t 구조체를 Trace32로 확인해 볼까요? 
(spinlock_t *) (spinlock_t*)0xb7e0eb00 
  (struct raw_spinlock) rlock = (
    (arch_spinlock_t) raw_lock = (
      (u32) slock = 0x134C134C,
      (struct __raw_tickets) tickets = (
        (u16) owner = 0x134C,
        (u16) next = 0x134C))))

위 디버깅 정보와 같이 spinlock_t 구조체는 struct raw_spinlock 그리고 arch_spinlock_t 타입으로 캐스팅될 수 있습니다. spinlock_t 구조체의 실체는 arch_spinlock_t이며 struct __raw_tickets 구조체 owner와 next 필드로 구성돼 있습니다. 생각보다 구조체는 간단합니다.

결국 실제 스핀락 동작을 표현하는 struct __raw_tickets 구조체 필드는 보면 owner가 0x134C 그리고 next가 0x134C이며 slock은 0x134C134C입니다.

이번에는 다른 아키텍처에서 spinlock_t 구조체를 확인해볼까요? 다음은 64비트 x86 아키텍처에서 본 spinlock_t 구조체입니다.
01  (spinlock_t *) (spinlock_t*)0xFFFFFFFF8164A340  
02    (struct raw_spinlock) rlock = (
03      (arch_spinlock_t) raw_lock = (
04        (__ticketpair_t) head_tail = 0x13001300,
05        (struct __raw_tickets) tickets = (
06          (__ticket_t) head = 0x1300,
07          (__ticket_t) tail = 0x1300))))

라즈비안에서 확인한 spinlock_t 구조체와는 약간 다릅니다. 03번째 줄 까지 구조체는 같으나, 04~07번째 줄은 다릅니다. 

이렇게 스핀락 자료구조를 여러 구조체로 캐스팅하는 이유는 무엇일까요? 

    리눅스 커널 전체 코드에서 스핀락 공용 함수와 자료구조로 스핀락을 쓰고 싶다. 
     그런데 CPU 아키텍처(ARMv7, ARMv8, x86)별로 스핀락 구현부는 다르다.

이렇게 아키텍처별로 호환성을 유지하며 스핀락 구조체를 쓰기 위해 이 방식으로 spinlock_t 구조체를 선언한 것입니다.


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

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

#Reference(커널 동기화)
커널 동기화 기본 개념 소개
레이스 발생 동작 확인
커널 동기화 기법 소개
스핀락
뮤텍스란
커널 동기화 디버깅



핑백

덧글

댓글 입력 영역