Fallback allocation

What is fallback allocation?

  • 시스템에 존재하는 페이지는 migrate type이라는 속성을 가지고 있음
    • enum migratetype
  • 페이지 할당은 어떤 migrate type의 페이지를 할당할지 정해서 시도됨
  • 할당을 요청할 페이지의 migrate type은 할당 요청시 전달된 gfp flag에 의해 결정됨
    • gfpflags_to_migratetype()
  • fastpath 페이지 할당시에 시도한 migrate type에서 할당이 불가할 경우 fallback migrate type으로 시도하는 할당을 의미함

When does fallback allocation begin?

fallback allocation은 페이지 할당자가 지정된 migrate type과 order로 시도한 fastpath 페이지 할당이 실패했을 때 __rmqueue()에서 호출되는 __rmqueue_fallback()에서 시작된다.


enum migratetype - migrate type of page

enum migratetype {

 MIGRATE_UNMOVABLE,

 MIGRATE_MOVABLE,

 MIGRATE_RECLAIMABLE,

 MIGRATE_PCPTYPES,

 MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES,

#ifdef CONFIG_CMA

 MIGRATE_CMA,

#endif

#ifdef CONFIG_MEMORY_ISOLATION

 MIGRATE_ISOLATE,

#endif

 MIGRATE_TYPES

};

migrate type은 6개로 이루어져 있음.(MIGRATE_TYPES, MIGRATE_PCPTYPES 제외)


gfpflags_to_migratetype() - get migrate type from gfp flags

#define GFP_MOVABLE_MASK (__GFP_RECLAIMABLE|__GFP_MOVABLE)

#define GFP_MOVABLE_SHIFT 3


static inline int gfpflags_to_migratetype(const gfp_t gfp_flags)

{

 VM_WARN_ON((gfp_flags & GFP_MOVABLE_MASK) == GFP_MOVABLE_MASK);

 BUILD_BUG_ON((1UL << GFP_MOVABLE_SHIFT) != ___GFP_MOVABLE);

 BUILD_BUG_ON((___GFP_MOVABLE >> GFP_MOVABLE_SHIFT) != MIGRATE_MOVABLE);


if (unlikely(page_group_by_mobility_disabled))

 return MIGRATE_UNMOVABLE;


 return (gfp_flags & GFP_MOVABLE_MASK) >> GFP_MOVABLE_SHIFT;

}

  • @gfp_flags로 전달된 gfp flag의 두 비트(reclaimable, movable)의 존재여부를 이용해서 migrate type을 구함.
    • nothing -> MIGRATE_UNMOVABLE
    • __GFP_RECLAIMABLE -> MIGRATE_RECLAIMABLE
    • __GFP_MOVABLE -> MIGRATE_MOVABLE
    • __GFP_RECLAIMABLE | __GFP_MOVABLE -> warning
  • mobility를 이용한 page group 기능을 사용하기에는 시스템 메모리가 매우 적은 경우에는 gfp flag와 상관없이 무조건 MIGRATE_UNMOVABLE만 사용한다. page_group_by_mobility_disabled 변수는 부팅타임에 true로 설정된다.
    • build_all_zonelists()

fallback migrate type list

static int fallbacks[MIGRATE_TYPES][4] = {

 [MIGRATE_UNMOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_MOVABLE, MIGRATE_TYPES },

 [MIGRATE_RECLAIMABLE] = { MIGRATE_UNMOVABLE, MIGRATE_MOVABLE, MIGRATE_TYPES },

 [MIGRATE_MOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_TYPES },

#ifdef CONFIG_CMA

 [MIGRATE_CMA] = { MIGRATE_TYPES },

#endif

#ifdef CONFIG_MEMORY_ISOLATION

 [MIGRATE_ISOLATE] = { MIGRATE_TYPES },

#endif

};

  • 해당 배열은 각 migrate type마다 가지고 있는 fallback migrate type list로 구성되어 있음
  • list는 MIGRATE_TYPES를 끝으로 가지고 있으며 해당 type은 fallback allocation에 사용되지 않음


'커널 분석' 카테고리의 다른 글

[bottom half] softirq 등록과 처리과정  (0) 2018.09.08

1. softirq란?

2. softirq 핸들러 등록과정

softirq는 커널 버전 4.13 기준으로 총 10개가 존재한다.


enum

{

    HI_SOFTIRQ=0,

    TIMER_SOFTIRQ,

    NET_TX_SOFTIRQ,

    NET_RX_SOFTIRQ,

    BLOCK_SOFTIRQ,

    IRQ_POLL_SOFTIRQ,

    TASKLET_SOFTIRQ,

    SCHED_SOFTIRQ,

    HRTIMER_SOFTIRQ,

    RCU_SOFTIRQ,

    NR_SOFTIRQS

};


softirq 등록은 open_softirq()을 호출해서 처리한다.


<kernel/softirq.c>

static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;


void open_softirq(int nr, void (*action)(struct softirq_action *))

{

    softirq_vec[nr].action = action;

}


위 함수를 통해 각각의 softirq에 등록된 핸들러 정보는 다음과 같다.


block/blk-softirq.c <<blk_softirq_init>>

 open_softirq(BLOCK_SOFTIRQ, blk_done_softirq);

kernel/rcu/tiny.c <<rcu_init>>

 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);

kernel/rcu/tree.c <<rcu_init>>

 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);

kernel/sched/fair.c <<init_sched_fair_class>>

 open_softirq(SCHED_SOFTIRQ, run_rebalance_domains);

kernel/softirq.c <<softirq_init>>

 open_softirq(TASKLET_SOFTIRQ, tasklet_action);

kernel/softirq.c <<softirq_init>>

 open_softirq(HI_SOFTIRQ, tasklet_hi_action);

kernel/time/timer.c <<init_timers>>

 open_softirq(TIMER_SOFTIRQ, run_timer_softirq);

lib/irq_poll.c <<irq_poll_setup>>

 open_softirq(IRQ_POLL_SOFTIRQ, irq_poll_softirq);

net/core/dev.c <<net_dev_init>>

 open_softirq(NET_TX_SOFTIRQ, net_tx_action);

net/core/dev.c <<net_dev_init>>

 open_softirq(NET_RX_SOFTIRQ, net_rx_action);


이렇게 등록된 핸들러는 softirq 처리가 필요할 때 호출된다. pending softirq라고 하며 아래와


3. pending softirq 설정

4. softirq 처리과정

인터럽트 처리를 위해 호출되는 함수는 handle_domain_irq()이다. 이 함수는 바로 __handle_domain_irq()을 호출하도록 구현되어 있다. 올바른 인터럽트 번호라면 결국 generic_handle_irq()을 호출해서 등록된 인터럽트 핸들러를 호출하게 된다. softirq는 호출된 인터럽트 핸들러가 종료된 이후 호출되는 irq_exit()에서 처리될 수가 있다.



<kernel/softirq.c> - irq_exit()

/*

 * Exit an interrupt context. Process softirqs if needed and possible:

 */

void irq_exit(void)

{

 ...

 if (!in_interrupt() && local_softirq_pending())

     invoke_softirq();


invoke_softirq()는 아래 조건을 모두 만족할 경우 호출되어 pending된 softirq를 처리한다.


  • NMI,IRQ,SoftIRQ 컨텍스트이거나 BH disabled
  • current cpu에 pending된 softirq가 있음


<kernel/softirq.c> - invoke_softirq()

static inline void invoke_softirq(void)

{

 if (ksoftirqd_running())

 return;


 if (!force_irqthreads) {

#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK

 __do_softirq();

#else

 do_softirq_own_stack();

#endif

 } else {

 wakeup_softirqd();

 }

}

invoke_softirq()에서는 네 경우로 나눠서 pending된 softirq를 처리한다


  • softirqd가 이미 실행중인 경우
  • softirqd가 미실행중 && force threading of a irq handler가 활성화 && 인터럽트 스택이 존재
  • softirqd가 미실행중 && force threading of a irq handler가 활성화 && 인터럽트 스택이 없음
  • softirqd가 미실행중 && force threading of a irq handler가 비활성화

2,3번의 경우는 결국 __do_softirq()을 호출하게 된다.


<kernel/softirq.c> - __do_softirq()

asmlinkage __visible void __softirq_entry __do_softirq(void)

{

    pending = local_softirq_pending();

    ...

    while ((softirq_bit = ffs(pending))) {

        ...

        h += softirq_bit - 1;

        ... 

        h->action(h);

        ...

        h++;

        ...

        pending >>= softirq_bit;

__do_softirq()에서는 먼저 current cpu의 pending softirq 정보를 구한다. 이 정보는 총 32개의 비트로 구성되어 있다.


<include/linux/irq_cpustat.h>

#define local_softirq_pending() \

__IRQ_STAT(smp_processor_id(), __softirq_pending)

#define __IRQ_STAT(cpu, member) (irq_stat[cpu].member)


while()에서는 비트맵에 설정된 비트 개수만큼 반복해서 해당 pending softirq의 handler를 호출한다(h->action(h)).

'커널 분석' 카테고리의 다른 글

mm,page allocator - fallback allocation  (0) 2018.09.08

+ Recent posts