2014년 4월 8일 화요일

[Linux Kernel] 49주차(2014.04.05) 후기

10차 ARM 리눅스 커널 스터디 49주차(2014.04.05) 후기입니다.

일시 : 2014.04.05 (49주차)

모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C

장소 : 토즈 타워점

장소지원 : NAVER 개발자 커뮤니티 지원 프로그램

참여인원 : 5명

스터디 진도 :

 start_kernel()-> mm_init()->page_cgroup_init_flatmem();
   // null function
 start_kernel()-> mm_init()->mem_init();

mm_init()

mem_map에서 미사용영역(free area)를 찾아서 사용가능한 미사용 영역을 구하고 이것을 커널이 관리할 수 있는 메모리 관리자(memomry allocator)로 설정해 주는 과정 start_kernel이 시작한 이후 몆곳에서 일부 메모리를 할당 받아서 설정한 이후 실행됨
static void __init mm_init(void)
{
 page_cgroup_init_flatmem();
 // null function
 mem_init();
 kmem_cache_init();
 percpu_init_late();
 pgtable_cache_init();
 vmalloc_init();
}

page_cgroup_init_flatmem();

  • mem_init()의 서브 함수
  • null function

mem_init();

  • mem_init()의 서브 함수
  • 1 각 노드에서 hole영역이 있다면 미사용영역으로 설정한다. (우리는 해당없음)
  • 2 bootmem의 page frame의 가용 여부를 나타내는 비트맵의 해당 bit를 초기화함
  • 3 비트맵의 bit가 0으로 초기화된 page를 버디 할당자 (buddy allocator)로 설정해 줌
  • 4 현재 시스템의 가용 memory등에 대한 정보를 출력함
      void __init mem_init(void)
      {
       max_mapnr   = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
    
       free_unused_memmap(&meminfo);
       // bank 0, 1중에 연속되지 않거나 align이 되지 않았다면 free_memmap을 실행
       free_all_bootmem();
    
      ...
      }
    

max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;

// max_mapnr : 10번째 page section 주소 + 0xA0000

free_unused_memmap(&meminfo);

// bank 0, 1중에 연속되지 않거나 align이 되지 않았다면 free_memmap을 실행
static void __init free_unused_memmap(struct meminfo *mi)
{
 unsigned long bank_start, prev_bank_end = 0;
 unsigned int i;

 for_each_bank(i, mi) {
 // for (i = 0; i < (&meminfo)->nr_banks; i++)

  struct membank *bank = &mi->bank[i];

  bank_start = bank_pfn_start(bank);

  bank_start = min(bank_start,
 ALIGN(prev_bank_end, PAGES_PER_SECTION));

  if (prev_bank_end && prev_bank_end < bank_start)
   free_memmap(prev_bank_end, bank_start);

  prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES);
 }

 if (!IS_ALIGNED(prev_bank_end, PAGES_PER_SECTION))
  free_memmap(prev_bank_end,
   ALIGN(prev_bank_end, PAGES_PER_SECTION));
}

free_all_bootmem()

  • 메모리 노드가 가진 모든 페이지의 사용 여부를 나타내는 bdata자료 구조를 사용해서 bootmem map에 해당 영역이 사용 중인지 사용 가능한지를 표시 한다.
  • free_pages_check -> for {list_all_zones_managed_page() } -> free_all_bootmem_core(bdata);
      unsigned long __init free_all_bootmem(void)
      {
       unsigned long total_pages = 0;
       bootmem_data_t *bdata;
    
       reset_all_zones_managed_pages();
    
       list_for_each_entry(bdata, &bdata_list, list)
       // for (bdata = list_entry((&bdata_list)->next, typeof(*bdata), list);
       //     &bdata->list != (&bdata_list);
       //     bdata = list_entry(bdata->list.next, typeof(*bdata), list))
    
        // bdata: &bdata_list, &bdata->list: (&bdata_list)->list
        total_pages += free_all_bootmem_core(bdata);
    
       totalram_pages += total_pages;
    
       return total_pages;
      }
    

free_all_bootmem_core(bdata);

  • free_all_bootmem -> ofor (list_all_zones_managed_page() ) free_all_bootmem_core(bdata);
  • 인자로 전달받은 bdata(node정보)를 이용하여 현재 노드에서 미사용영역(free)의 page를 미사용영역으로 설정함
    static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata) { struct page *page; unsigned long start, end, pages, count = 0;
    if (!bdata->node_bootmem_map)
    return 0;
    
    start = bdata->node_min_pfn; end = bdata->node_low_pfn; bdebug("nid=%td start=%lx end=%lx\n",
    bdata - bootmem_node_data, start, end);
    
    while (start < end) {
    unsigned long *map, idx, vec;
    unsigned shift;
    
    map = bdata->node_bootmem_map;
    
    idx = start - bdata->node_min_pfn;
    
    shift = idx & (BITS_PER_LONG - 1);
    
    vec = ~map[idx / BITS_PER_LONG];
    
    if (shift) {
     vec >>= shift;
     if (end - start >= BITS_PER_LONG)
      vec |= ~map[idx / BITS_PER_LONG + 1] <<
       (BITS_PER_LONG - shift);
    }
    
    if (IS_ALIGNED(start, BITS_PER_LONG) && vec == ~0UL) {
     int order = ilog2(BITS_PER_LONG);
     __free_pages_bootmem(pfn_to_page(start), order);
     count += BITS_PER_LONG;
     start += BITS_PER_LONG;
    } else {
     unsigned long cur = start;
    
     start = ALIGN(start + 1, BITS_PER_LONG);
     while (vec && cur != start) {
      if (vec & 1) {
       page = pfn_to_page(cur);
       __free_pages_bootmem(page, 0);
       count++;
      }
      vec >>= 1;
      ++cur;
     }
    }
    
    }
    page = virt_to_page(bdata->node_bootmem_map); pages = bdata->node_low_pfn - bdata->node_min_pfn; pages = bootmem_bootmap_pages(pages); count += pages; while (pages--)
    __free_pages_bootmem(page++, 0);
    
    bdebug("nid=%td released=%lx\n", bdata - bootmem_node_data, count);
    return count; }
page->_mapcount는 -1로 초기화했었다.

__free_pages_bootmem(struct page *page, unsigned int order)

  • start: 0x20000, pfn_to_page(0x20000): 0x20000의 해당하는 struct page의 주소
  • __free_pages_bootmem(pfn_to_page(start), order);
    void __init __free_pages_bootmem(struct page *page, unsigned int order)
    {
     unsigned int nr_pages = 1 << order;
     unsigned int loop;

     prefetchw(page);

     for (loop = 0; loop < nr_pages; loop++) {
      struct page *p = &page[loop];

      if (loop + 1 < nr_pages)
       prefetchw(p + 1);
      __ClearPageReserved(p);

      set_page_count(p, 0);
     }

     page_zone(page)->managed_pages += 1 << order;

     set_page_refcounted(page);

     __free_pages(page, order);
    }

__free_pages(page, order);

  • page: 0x20000의 해당하는 struct page의 1st page, order: 5
    void __free_pages(struct page *page, unsigned int order)
    {
     if (put_page_testzero(page)) {

      if (order == 0)
       free_hot_cold_page(page, 0);
      else
       __free_pages_ok(page, order);
     }
    }

__free_pages_ok(page, order);

  • page: 0x20000의 해당하는 struct page의 1st page, order: 5
      static void __free_pages_ok(struct page *page, unsigned int order)
      {
       unsigned long flags;
       int migratetype;
    
       if (!free_pages_prepare(page, order))
        return;
    
       local_irq_save(flags);
       __count_vm_events(PGFREE, 1 << order);
       migratetype = get_pageblock_migratetype(page);
       set_freepage_migratetype(page, migratetype);
       free_one_page(page_zone(page), page, order, migratetype);
       local_irq_restore(flags);
      }
    

if (!free_pages_prepare(page, order))

  • page: 0x20000의 해당하는 struct page의 1st page, order: 5
      static bool free_pages_prepare(struct page *page, unsigned int order)
      {
       int i;
       int bad = 0;
    
       trace_mm_page_free(page, order);
    
       kmemcheck_free_shadow(page, order); // null function
    
       if (PageAnon(page))
        page->mapping = NULL;
    
       for (i = 0; i < (1 << order); i++)
        bad += free_pages_check(page + i);
       if (bad)
        return false;
    
       if (!PageHighMem(page)) {
        debug_check_no_locks_freed(page_address(page),PAGE_SIZE<<order);
        debug_check_no_obj_freed(page_address(page),
              PAGE_SIZE << order);
       }
       arch_free_page(page, order);
       kernel_map_pages(page, 1 << order, 0);
    
       return true;
      }
    

free_pages_check(page +i)

call code

// order: 5
    for (i = 0; i < (1 << order); i++)
// page: 0x20000 (pfn)
bad += free_pages_check(page + i);

called code

    static inline int free_pages_check(struct page *page)
    {
     if (unlikely(page_mapcount(page) |
      (page->mapping != NULL)  |
      (atomic_read(&page->_count) != 0) |

pageflags

enum pageflags {
 PG_locked,  /* Page is locked. Don't touch. */
 PG_error,
 PG_referenced,
 PG_uptodate,
 PG_dirty,
 PG_lru,
 PG_active,
 PG_slab,
 PG_owner_priv_1, /* Owner use. If pagecache, fs may use*/
 PG_arch_1,
 PG_reserved,  // ARM10C 20140118, 10
 PG_private,  /* If pagecache, has fs-private data */
 PG_private_2,  /* If pagecache, has fs aux data */
 PG_writeback,  /* Page is under writeback */
 // ARM10C 20140125
 // PG_compound: 14
 PG_compound,  /* A compound page */
 PG_swapcache,  /* Swap page: swp_entry_t in private */
 PG_mappedtodisk, /* Has blocks allocated on-disk */
 // ARM10C 20140125
 // PG_reclaim: 17
 PG_reclaim,  /* To be reclaimed asap */
 PG_swapbacked,  /* Page is backed by RAM/swap */
 PG_unevictable,  /* Page is "unevictable"  */
#ifdef CONFIG_MMU
 PG_mlocked,  /* Page is vma mlocked */
#endif
#ifdef CONFIG_ARCH_USES_PG_UNCACHED
 PG_uncached,  /* Page has been mapped as uncached */
#endif
#ifdef CONFIG_MEMORY_FAILURE
 PG_hwpoison,  /* hardware poisoned page. Don't touch */
#endif
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 PG_compound_lock,
#endif
 __NR_PAGEFLAGS,

 /* Filesystems */
 PG_checked = PG_owner_priv_1,

 /* Two page bits are conscripted by FS-Cache to maintain local caching
  * state.  These bits are set on pages belonging to the netfs's inodes
  * when those inodes are being locally cached.
  */
 PG_fscache = PG_private_2, /* page backed by cache */

 /* XEN */
 PG_pinned = PG_owner_priv_1,
 PG_savepinned = PG_dirty,

 /* SLOB */
 PG_slob_free = PG_private,
};

page_mapcount_reset(struct page *page)

page_mapcount_reset(struct page *page)
{
 atomic_set(&(page)->_mapcount, -1);
}


  (page->flags & PAGE_FLAGS_CHECK_AT_FREE) |
  (mem_cgroup_bad_page_check(page)))) {
  bad_page(page);
  return 1;
 }
 page_nid_reset_last(page);
 if (page->flags & PAGE_FLAGS_CHECK_AT_PREP)
  page->flags &= ~PAGE_FLAGS_CHECK_AT_PREP;
 return 0;
}

if (unlikely(page_mapcount(page) | (page->mapping != NULL) |

 // pageAton 에서 page->mapping : 0으로 초기화
(atomic_read(&page->_count) != 0) |
(page->flags & PAGE_FLAGS_CHECK_AT_FREE) | // pfn_to_page(pfn) 서 page->flags : 0x2000 0000 // free_pages_bootmem(struct page *page, unsigned int order) // 에서 ClearPageReserved(p); // p: 0x20001 (pfn) // page reserved 속성을 clear
(mem_cgroup_bad_page_check(page)))) {
bad_page(page);

PAGE_FLAGS_CHECK_AT_FREE :

PAGE_FLAGS_CHECK_AT_PREP : 0x1FFFF
page->flags :0x200000 (pfn)

page_mapcount_reset(struct page *page)

page_mapcount_reset(struct page *page)
{
 atomic_set(&(page)->_mapcount, -1);
}

arch_free_page(page, order);

// null function
#ifndef HAVE_ARCH_FREE_PAGE
static inline void arch_free_page(struct page *page, int order) { }
#endif
#ifndef HAVE_ARCH_ALLOC_PAGE
static inline void arch_alloc_page(struct page *page, int order) { }
#endif

kernel_map_pages(page, 1 << order, 0);

// null function
static inline void
kernel_map_pages(struct page *page, int numpages, int enable) {}

if (!free_pages_prepare(page, order))

// page: 0x20000의 해당하는 struct page의 1st page, order: 5
static bool free_pages_prepare(struct page *page, unsigned int order)
{
 int i;
 int bad = 0;

// mm_page_free이름으로 아래의 trace 관련 함수가 만들어져 있음
// trace_mm_page_free, register_trace_mm_page_free
// unregister_trace_mm_page_free, check_trace_callback_type_mm_page_free

// page: 0x20000의 해당하는 struct page의 1st page, order: 5
trace_mm_page_free(page, order);
// page: 0x20000의 해당하는 struct page의 1st page, order: 5
 kmemcheck_free_shadow(page, order); // null function

 // page: 0x20000의 해당하는 struct page의 1st page
 // PageAnon(page): 0
 if (PageAnon(page))
  page->mapping = NULL;

// 2014/03/29 종료

 // order: 5
 for (i = 0; i < (1 << order); i++)
  // page: 0x20000 (pfn)
  bad += free_pages_check(page + i);
  // free_pages_check 페이지가 free나 reserved, flags가 있는지
  // 검사하는 함수이다.
 if (bad)
  return false;

 if (!PageHighMem(page)) {
  debug_check_no_locks_freed(page_address(page),PAGE_SIZE<<order);
  // null function
  debug_check_no_obj_freed(page_address(page),
  PAGE_SIZE << order);
  // null function
 }
 arch_free_page(page, order);
 kernel_map_pages(page, 1 << order, 0);

 return true;
}

free_pages_check(page +i)

이 함수는 reserved 되어 있거나 flags에 설정된 값이 있다면 free 영역이 아니므로 bad로 수를 센다.
// order: 5
for (i = 0; i < (1 << order); i++)
// page: 0x20000 (pfn)
bad += free_pages_check(page + i);
free_pages_check(page + i); 의 의미 다음 page를 미리 읽는 것이다.

free_pages_check(page + i)

static inline int free_pages_check(struct page *page)
{
 if (unlikely(page_mapcount(page) |
  (page->mapping != NULL)  |
  (atomic_read(&page->_count) != 0) |
  (page->flags & PAGE_FLAGS_CHECK_AT_FREE) |
  (mem_cgroup_bad_page_check(page)))) {
  bad_page(page);
  return 1;
 }
 page_nid_reset_last(page);
 if (page->flags & PAGE_FLAGS_CHECK_AT_PREP)
  page->flags &= ~PAGE_FLAGS_CHECK_AT_PREP;
  //  NR_PAGEFLAGS 만큼의 하위 비트를 전부 지워줌
  //  NR_PAGEFLAGS : 21
 return 0;
}

if (unlikely(page_mapcount(page) |
(page->mapping != NULL)  |
// PageAnon(page): 0
// if (PageAnon(page))
// page->mapping = NULL;
// pageAton 에서 page->mapping : 0으로 초기화

(atomic_read(&page->_count) != 0) |

(page->flags & PAGE_FLAGS_CHECK_AT_FREE) |
// pfn_to_page(pfn) 서 page->flags : 0x2000 0000
// __ClearPageReserved(p); 에서 reserved를 해제해줌

(mem_cgroup_bad_page_check(page)))) {
bad_page(page);

PAGE_FLAGS_CHECK_AT_FREE :

__count_vm_events(PGFREE, 1 << order);

// pcpu로 할당 받았던 영역에 my_cpu_offset :0에 대한 하는 곳에 order :32 만큼 // 델타를 설정해서 PFFREE라고 설정함
static inline void __count_vm_events(enum vm_event_item item, long delta)
{
 __this_cpu_add(vm_event_states.event[item], delta);
}

::percpu.h

# define __this_cpu_add(pcp, val) __pcpu_size_call(__this_cpu_add_, (pcp), (val))

::percpu.h

#  define __this_cpu_add_1(pcp, val) __this_cpu_generic_to_op((pcp), (val), +=)

::percpu.h

#define __pcpu_size_call(stem, variable, ...)    \
do {         \
 __verify_pcpu_ptr(&(variable));     \
 // __pcpu_size_call (__this_cpu_add_, (pcp),(val))
 // __pcpu_size_call (__this_cpu_add_, vm_event_states.event[7], delta)
 // pcp : vm_event_state.event[7], val : 32
 // vm_event_stat.event[7] :PGFREE

 switch(sizeof(variable)) {     \
 // __verify_pcpu_ptr(&(vm_event_states.event[7]));
 // switch(sizeof(&(vm_event_states.event[7])); 경고용

  case 1: stem##1(vm_event_states.event[7], __VA_ARGS__);break;  \
  // case 1: __this_cpu_add_1( __VA_ARGS__);break;  \
  case 2: stem##2(variable, __VA_ARGS__);break;  \
  case 4: stem##4(variable, __VA_ARGS__);break;  \
  case 8: stem##8(variable, __VA_ARGS__);break;  \
  default:       \
   __bad_size_call_parameter();break;  \
  // __this_cpu_add_4 : *__this_cpu_ptr(&(vm_event_states.event[7]) += delta;

 }        \

} while (0)

migratetype = get_pageblock_migratetype(page);

mmzone.h

static inline int get_pageblock_migratetype(struct page *page)
{
 return get_pageblock_flags_group(page, PB_migrate, PB_migrate_end);
}

::page_alloc.c

unsigned long get_pageblock_flags_group(struct page *page,
 int start_bitidx, int end_bitidx)
{
 struct zone *zone;
 unsigned long *bitmap;
 unsigned long pfn, bitidx;
 unsigned long flags = 0;
 unsigned long value = 1;

 zone = page_zone(page);
 pfn = page_to_pfn(page);
 // pageblock_order :9 , NR_PAGEBLOCK_BITS: 4
 // bit : page 1024개당 1바이트 씩 사용
 bitmap = get_pageblock_bitmap(zone, pfn);

 // pfn : 0x20000
 bitidx = pfn_to_bitidx(zone, pfn);
 // bitidx: 0

 // start_bitidx : 0, end_bitidx : 2, value : 1, bitidx : 0
 for (; start_bitidx <= end_bitidx; start_bitidx++, value <<= 1)
  if (test_bit(bitidx + start_bitidx, bitmap))
   flags |= value;

 return flags;
}

:: pfn_to_bitidx

static inline int pfn_to_bitidx(struct zone *zone, unsigned long pfn)
{
#ifdef CONFIG_SPARSEMEM
 // PAGES_PER_SECTION : 0x10000
 // pfn : 0 (section의 몇 번째 프레임)
 // pfn : 0xF800
 pfn &= (PAGES_PER_SECTION-1);
 // pageblock_order: 9, NR_PAGEBLOCK_BITS : 4
 // bit : page 1024개당 1 바이트씩 사용
 return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS;
 // return 0x0
 // return 0x1F0
#else
 pfn = pfn - round_down(zone->zone_start_pfn, pageblock_nr_pages);
 return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS;
#endif /* CONFIG_SPARSEMEM */
}

메모리 단위

  • 1 section : 64 pageblock (256MB)
  • 1 pageblock : 1024 page (4MB)
  • 1 page : 4k

free_area_init_core에 대한 주석을 읽고 가자

  • Set up the zone data structures:
    • mark all pages reserved
    • mark all memory queues empty
    • clear the memory bitmaps *
  • NOTE: pgdat should get zeroed by caller.
    static void __paginginit free_area_init_core(struct pglist_data *pgdat, unsigned long node_start_pfn, unsigned long node_end_pfn, unsigned longzones_size, unsigned long zholes_size) { ... memmap_init(size, nid, j, zone_start_pfn);
    // struct page 내부 멤버를 설정 // flags : section, node, zone 번호, PG_reserved(10) 설정 // page->__count.counter : 1 // page->_mapcount.counter : -1 // page->lru 초기화 // page에 해당하는 &mem_section[0][2]->pageblock_flags의 // MIGRATE_MOVABLE(2)번 비트를 1로 설정(pageblock마다) // mem_section[0][2] ~ mem_section[0][9] 까지 설정
    // zone_start_pfn : 0x4F800 // zone_start_pfn : 0xA0000 ... }
    bitidx = pfn_to_bitidx(zone,pfn);
    0x200000 ~ 0x203FF : 0000 0010 0x200400 ~ 0x207FF : 0000 0010

for (; start_bitidx <= end_bitidx; start_bitidx++, value <<= 1)

  • 에서 0번 비트, 1번 비트 , 2번 비트를 돌면서 1번 비트(0x2)가 1인지 확인해서 flags 를 갱신하므로 최종 flags : 0x2가 리턴 된다.

free_one_page(page_zone(page), page, order, migratetype);

all_unreclaimable :  all pages pinned
pages_scanned : since last reclaim

__free_one_page(page, zone, order, migratetype);

unsigned long uninitialized_var(buddy_idx);

unsigned long buddy_idx = buddy_idx ;

초기화 되지 않은 지역 변수에 대한 경고 메시지를 없에기 위함

if (unlikely(PageCompound(page)))

PageCompound (const struct page *page)
{ retrun test_bit(PG_compound, & paga->flags);}
// PG_compound : enum 14

::page-flags.h

TESTPAGEFLAG(Compound, compound)
__SETPAGEFLAG(Head, compound)  __CLEARPAGEFLAG(Head, compound)

::page-flags.h

#define TESTPAGEFLAG(uname, lname)     \
static inline int Page##uname(const struct page *page)   \
   { return test_bit(PG_##lname, &page->flags); }

page_idx = page_to_pfn(page) & ((1 << MAX_ORDER) - 1);

  • MAX_ORDER : 11 ( 1<< MAX_ORDER) -1 : 0x7FF
  • page_to_pfn(page) : 0x20000
    11 : 4M + 4M 10 : 2M 2M 2M 2M 9 : 1M 1M 8 : 512K 7 : 256k 6 : 128l 5 : 64k 4 : 32k 3 : 16k 2 : 8k 1 : 4k
      VM_BUG_ON(bad_range(zone, page));
    
       while (order < MAX_ORDER-1) {
        buddy_idx = __find_buddy_index(page_idx, order);
        buddy = page + (buddy_idx - page_idx);
    

::page_alloc.c

static inline unsigned long
__find_buddy_index(unsigned long page_idx, unsigned int order)
{
 return page_idx ^ (1 << order);
}
  • order : 5
  • rerurn : 32

__find_buddy_index

  • 1 << order 만큼 떨어진 곳의 짝의 index를 찾아냄
  • idx ^ ( 1<< order)
      // page : 0x20000 (fpn), buddy_idx : 32, page_idx : 0
      buddy = page + (buddy_idx - page_idx);
      // page : 0x20000 (fpn), buddy : 0x20020
    
      if (!page_is_buddy(page, buddy, order))
    

page_is_buddy()

static inline int page_is_buddy(struct page *page, struct page *buddy,
        int order)
{
// page_to_pfn(byddy) : 0x20020
//

// pfn_valid_within () :1
 if (!pfn_valid_within(page_to_pfn(buddy)))
  return 0;

// NODES_PGOFF : 28
// ZONES_PGOFF : 26
// ZONEID_PGOFF : 26
// NODES_SHIFT : 0 , MAXX_NR_ZONES : 3, MAX_NR_SHIFT : 2
// ZONEID_SHIFT : 26

// page_zone_id(buddy) : 0
 if (page_zone_id(page) != page_zone_id(buddy))
  return 0;

// static inline bool page_is_guard(struct page *page) { return false; }
//
 if (page_is_guard(buddy) && page_order(buddy) == order) {
  VM_BUG_ON(page_count(buddy) != 0);
  return 1;
 }

 if (PageBuddy(buddy) && page_order(buddy) == order) {
  VM_BUG_ON(page_count(buddy) != 0);
  return 1;
 }
 return 0;
}

:: mm/internal.h

ostatic inline unsigned long page_order(struct page *page)
{
 /* PageBuddy() must be checked by the caller */
 return page_private(page);
}

set_page_order (page, order);
page-.private: 5
page->_mapcount : -128 로 설정

 list_add(&page->lru, &zone->free_area[order].free_list[migratetype]);
// contig_page_data.node_zone[ZONE_NORMAL].free_area[5].free_list[MIGRATE_MOVABLE]
에 0x2000(pfn) struct page를 연결

out:
 zone->free_area[order].nr_free++;
// zone->free_area[5].nr_free :1
// free 상태인 order 5 buddy 의 갯수를 증가

git log


# git log
2159499..d0bb9ad  master     -> origin/master
Updating 2159499..d0bb9ad
Fast-forward
 arch/arm/include/asm/percpu.h     |   1 +
 arch/arm/include/asm/spinlock.h   |   1 +
 include/asm-generic/percpu.h      |   2 ++
 include/linux/compiler-gcc.h      |   1 +
 include/linux/compiler.h          |   1 +
 include/linux/debug_locks.h       |   1 +
 include/linux/debugobjects.h      |   1 +
 include/linux/gfp.h               |   1 +
 include/linux/irqflags.h          |   1 +
 include/linux/lockdep.h           |   2 +-
 include/linux/memcontrol.h        |   1 +
 include/linux/mm.h                |  42 ++++++++++++++++++++++++++++++++++++++++--
 include/linux/mm_types.h          |   3 ++-
 include/linux/mmzone.h            |   9 ++++++++-
 include/linux/numa.h              |   1 +
 include/linux/page-flags-layout.h |   1 +
 include/linux/page-flags.h        |  54 ++++++++++++++++++++++++++++++++++++++++--------------
 include/linux/page-isolation.h    |   3 ++-
 include/linux/percpu.h            |   3 +++
 include/linux/spinlock.h          |   2 ++
 include/linux/spinlock_api_smp.h  |   6 +++++-
 include/linux/vm_event_item.h     |  35 ++++++++++++++++++++---------------
 include/linux/vmstat.h            |  32 +++++++++++++++++++++++++++++++-
 kernel/spinlock.c                 |   3 ++-
 lib/spinlock_debug.c              |   2 ++
 mm/internal.h                     |   1 +
 mm/page_alloc.c                   | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 27 files changed, 303 insertions(+), 43 deletions(-)2159499..d0bb9ad  master     -> origin/master

댓글 없음:

댓글 쓰기