2014년 5월 17일 토요일

[Linux Kernel] 54주차(2014.05.17) 후기

일시 : 2014.05.17 (54주차)

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

장소 : 토즈 타워점

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

참여인원 : 4명

스터디 진도 :

  • 지난 스터디에 이어서 mem_init()을 계속 분석합니다.
  • start_kernel()-> mm_init()->kmem_cache_init()->create_boot_cache() 분석중
  • kmem_cache_init()이 분석 중이어서 이번 후기는 내용이 짧습니다.
  • 자세한 후기도 그때 다시 정리하려고 합니다.

스터디 주요 내용

  • buddy할당자에 이어서 kmem 할당자 (Slub)을 분석중입니다.
  • mem_init()->kmem_cache_init()->create_boot_cache()->kmem_cache_create()
    ->kmem_cache_open()->init_kmem_cache_nodes->early_kmem_cache_node_alloc()
    ->new_slab()->allocate_slab()->alloc_slab_page()->alloc_pages_exact_node()
    ->
    alloc_pages()->__alloc_pages_nodemask();

vm_stat[?]

  • vm_stat[0] : number of free pags 수
  • vm_stat[1] : batch : chunk size for buddy add/remove

create_boot_cache()

  • mem_init()->kmem_cache_init()->create_boot_cache()
    err = __kmem_cache_create(s, flags);
    
  • __kmem_cache_create()
    // s: &boot_kmem_cache_node, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
    err = kmem_cache_open(s, flags);
    
  • kmem_cache_open()
    // s: &boot_kmem_cache_node
    if (!init_kmem_cache_nodes(s))
  • init_kmem_cache_nodes
        // slab_state: DOWN: 1
       if (slab_state == DOWN) {
           // node: 0
           early_kmem_cache_node_alloc(node);
           continue;
       }
    
  • early_kmem_cache_node_alloc()
    // kmem_cache_node: &boot_kmem_cache_node, GFP_NOWAIT: 0, node: 0
    
    page = new_slab(kmem_cache_node, GFP_NOWAIT, node);
  • new_slab()
    // s: &boot_kmem_cache_node, flags: GFP_NOWAIT: 0, node: 0
    // GFP_RECLAIM_MASK: 0x13ef0, GFP_CONSTRAINT_MASK: 0x60000
    page = allocate_slab(s,
       flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
    
  • allocate_slab()
    // alloc_gfp: 0x1200, node: 0, oo: boot_kmem_cache_node.oo
    page = alloc_slab_page(alloc_gfp, node, oo);
  • alloc_slab_page()
    // node: 0, NUMA_NO_NODE: -1
    
    if (node == NUMA_NO_NODE)
       return alloc_pages(flags, order);
    
    else
       // node: 0, flags: 0x201200, order: 0
       return alloc_pages_exact_node(node, flags, order);
    
  • alloc_pages_exact_node()
    // gfp_mask: 0x201200, order: 0, nid: 0,
    // node_zonelist(0, 0x201200): contig_page_data->node_zonelists
    return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask));
  • __alloc_pages()
    // gfp_mask: 0x201200, order: 0
    // zonelist: contig_page_data->node_zonelists, NULL
    return __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL);
  • __alloc_pages_nodemask();
    // gfp_mask: 0x201200, GFP_HARDWALL: 0x20000, nodemask: NULL, order: 0
    // zonelist: contig_page_data->node_zonelists, high_zoneidx: ZONE_NORMAL: 0
    // alloc_flags: 0x41, preferred_zone: (&contig_page_data)->node_zones[0]
    // migratetype: MIGRATE_UNMOVABLE: 0
    page = get_page_from_freelist(gfp_mask|
    GFP_HARDWALL, nodemask, order,
           zonelist, high_zoneidx, alloc_flags,
           preferred_zone, migratetype);
    
  • get_page_from_freelist()
       // zone: contig_page_data->node_zones[0], order: 0, mark: 0
       // classzone_idx: 0 alloc_flags: 0x41
       // zone_watermark_ok(contig_page_data->node_zones[0], 0, 0, 0, 0x41): 1
       if (!zone_watermark_ok(zone, order, mark,
                      classzone_idx, alloc_flags)) {
    
  • zone_watermark_ok()
    // z: contig_page_data->node_zones[0], order: 0, mark: 0
    // classzone_idx: 0 alloc_flags: 0x41
    // zone_page_state(contig_page_data->node_zones[0], NR_FREE_PAGES): ????
    return __zone_watermark_ok(z, order, mark, classzone_idx, alloc_flags,
                   zone_page_state(z, NR_FREE_PAGES));
    
    // return 1
  • get_page_from_freelist()
       // preferred_zone: (&contig_page_data)->node_zones[0]
       // zone: contig_page_data->node_zones[0], order: 0, gfp_mask: 0x221200
       // migratetype: MIGRATE_UNMOVABLE: 0
       page = buffered_rmqueue(preferred_zone, zone, order,
                       gfp_mask, migratetype);
    
  • buffered_rmqueue()
        if (list_empty(list)) {
           pcp->count += rmqueue_bulk(zone, 0,
                   pcp->batch, list,
                   migratetype, cold);
           if (unlikely(list_empty(list)))
               goto failed;
       }
    
  • rmqueue_bulk()
    for (i = 0; i < count; ++i) {
       struct page *page = __rmqueue(zone, order, migratetype);
       if (unlikely(page == NULL))
           break;
    
  • __rmqueue()
    retry_reserve:
    page = __rmqueue_smallest(zone, order, migratetype);
  • __rmqueue_smallest()
    // order : 0, MAX_ORDER : 11
    for (current_order = order; current_order < MAX_ORDER; ++current_order) {
      // zone->free_area[0] : contig_page_data_node_zones[0].free_area[0]>
       area = &(zone->free_area[current_order]);
      // area: &(contig_page_data_node_zones[0].free_area[0])
    
      // migratetype : 0,
      // area->free_list[0] : &&(contig_page_data_node_zones[0].free_area[0])->free_list[0] :1
       if (list_empty(&area->free_list[migratetype]))
           continue;
    
    • if (list_empty(&area->free_list[migratetype]))
      • 여기서 free_list[0]이 의미하는 바를 알아보자.
      • free_list가 현재 오더에서 빈것이 있는지 찾는다.
      • 빈것이 없으면 continue로 오더가 증가한다.
      • 빈것이 있으면 다음주로 실행된다.
      • 그런데 migratetype : 0은 UNMOVEABLE이므로,
      • if가 NULL이되어
      • free_list[]는 __free_one_page에서 넣었다.
    • if (unlikely(!page) && migratetype != MIGRATE_RESERVE) {
      page : NULL, migragetype : 0, MIGRATE_RESERVE : 3
      // if문 실행
      page = __rmqueue_fallback(zone, order, migratetype);
  • __rmqueue_fallback()
      // MAX_ORDER : 11, order : 0
       for (current_order = MAX_ORDER-1; current_order >= order;
                          --current_order) {
          for (i = 0;; i++) {
          // i:0, start_migratetype:0, fallback[0][0]: MIGRATE_RECLAIMABLE: 1
          // i:1, start_migratetype:0, fallback[0][1]: MIGRATE_MOVABLE : 2
              migratetype = fallbacks[start_migratetype][i];
              // fallbacks[0][0] : MIGRATE_RECLAIMABLE : 1
              // migratetype : MIGRATE_RECLAIMABLE : 1
              // fallbacks[0][1] : MIGRATE_MOVABLE : 2
              // migratetype : MIGRATE_MOVABLE : 2
    
              /* MIGRATE_RESERVE handled later if necessary */
              if (migratetype == MIGRATE_RESERVE)
                  break;
    
              // current_order : 10
              area = &(zone->free_area[current_order]);
              // area : &(zone->free_area[10]:
              //      : contig_page_data->node_zones[0].free_area[10]
    
              // i:0, migratetype : MIGRATE_RECLIMABLE : 1
              // i:0, area->free_list[1] : contig_page_data->node_zones[0].free_area[10]->free_list[1]
              // i:1, migratetype : MIGRATE_MOVABLE : 2
              // i:1, area->free_list[2] : contig_page_data->node_zones[0].free_area[10]->free_list[2]
              if (list_empty(&area->free_list[migratetype]))
                  continue;
    
              //  current_order:5, migratetype : MIGRATE_MOVABLE: 2 아래 코드 수행할것으로 보고 분석
              // i:1, curren_order:5
              // i:1 ,are->free_list[2]: contig_page_data->node_zones[0].free_area[5]->free_list[2].next
              page = list_entry(area->free_list[migratetype].next,
                      struct page, lru);
              // i:1 area->nr_free : (&contig_page_data->node_zones[0].free_area[5]->nr_free 1감소
              area->nr_free--;
    
              // i:1 zone : contig_page_data->node_zone[0]
              // i
              new_type = try_to_steal_freepages(zone, page,
                                start_migratetype,
                                migratetype);
    
              /* Remove the page from the freelists */
              list_del(&page->lru);
              rmv_page_order(page);
    
              expand(zone, page, order, current_order, area,
                     new_type);
    
              trace_mm_page_alloc_extfrag(page, order, current_order,
                  start_migratetype, migratetype, new_type);
    
              return page;
          }
      }
    
    • new_type
             new_type = try_to_steal_freepages(zone, page,
                               start_migratetype,
                               migratetype);
      
  • try_to_steal_freepages()
    static int try_to_steal_freepages(struct zone *zone, struct page *page,
                    int start_type, int fallback_type)
    {
      int current_order = page_order(page);
    
      /*
       * When borrowing from MIGRATE_CMA, we need to release the excess
       * buddy pages to CMA itself.
       */
      if (is_migrate_cma(fallback_type))
          return fallback_type;
    
      /* Take ownership for orders >= pageblock_order */
      // current_order : 5 >= pageblock_order : 10
      if (current_order >= pageblock_order) {
          change_pageblock_range(page, current_order, start_type);
          return start_type;
      }
    
      // current_order : 5
      // page_group_by_mobility_disabled : 0
      if (current_order >= pageblock_order / 2 ||
          start_type == MIGRATE_RECLAIMABLE ||
          page_group_by_mobility_disabled) {
          int pages;
    
          pages = move_freepages_block(zone, page, start_type);
    
          /* Claim the whole block if over half of it is free */
          if (pages >= (1 << (pageblock_order-1)) ||
                  page_group_by_mobility_disabled) {
    
              set_pageblock_migratetype(page, start_type);
              return start_type;
          }
    
      }
    
      return fallback_type;
    }
    
    • pages
          pages = move_freepages_block(zone, page, start_type);
      
    • move_freepages_block()
      zone : contig_page_data->node_zones[0],
  • move_freepages_block()
    int move_freepages_block(struct zone *zone, struct page *page,
                  int migratetype)
    {
      unsigned long start_pfn, end_pfn;
      struct page *start_page, *end_page;
    
      // 가정 : order 5의 migratetype MIGRARE_MOVALE 인 lru page
      //        의 pfn값을 0x200000 으로 가정하고 분석
    
      start_pfn = page_to_pfn(page);
      // start_pfn : 0x20000
    
      // pageblock_nr_pages : 0x400 (1024)
      start_pfn = start_pfn & ~(pageblock_nr_pages-1);
      // start_pfn = 0x20000 
    
      start_page = pfn_to_page(start_pfn);
      // start_page : page 0x20000 (pfn)
    
      end_page = start_page + pageblock_nr_pages - 1;
      // end_page : page 0x20CFF (pfn)
      end_pfn = start_pfn + pageblock_nr_pages - 1;
      // end_pfn : 0x20000 + ( 0x400 -1)
      // end_pfn : 0x20CFF
    
      /* Do not cross zone boundaries */
      // zone : contig_page_data->node_zones[0], start_pfn: 0x20000
      // zone_spans_pfn : 1
      if (!zone_spans_pfn(zone, start_pfn))
          start_page = page;
    
      // zone : contig_page_data->node_zones[0], end_pfn: 0x20cff
      // zone_spans_pfn : 1
      if (!zone_spans_pfn(zone, end_pfn))
          return 0;
    
      return move_freepages(zone, start_page, end_page, migratetype);
    }
    
    • return
      return move_freepages(zone, start_page, end_page, migratetype);
      
  • move_freepages()

// Move the free pages in a range to the free lists of the requested type.
// Note that start_page and end_pages are not aligned on a pageblock
// boundary. If alignment is required, use move_freepages_block()

int move_freepages(struct zone *zone,
              struct page *start_page, struct page *end_page,
              int migratetype)
{
    struct page *page;
    unsigned long order;
    int pages_moved = 0;

#ifndef CONFIG_HOLES_IN_ZONE
    /*
     * page_zone is not safe to call in this context when
     * CONFIG_HOLES_IN_ZONE is set. This bug check is probably redundant
     * anyway as we check zone boundaries in move_freepages_block().
     * Remove at a later date when no bug reports exist related to
     * grouping pages by mobility
     */
     BUG_ON(page_zone(start_page) != page_zone(end_page));
     // 시작과 끝이 같은 존에 있는지 확인하여 아니면 버그.
#endif

    // start: page : 0x20000 (pfn), end_page : page 0x20CFF (pfn)
    for (page = start_page; page <= end_page;) {
        /* Make sure we are not inadvertently changing nodes */

        // page_to_nid(page)
        VM_BUG_ON(page_to_nid(page) != zone_to_nid(zone));
        // 같은 존에 있는지 확인.

        if (!pfn_valid_within(page_to_pfn(page))) {
            page++;
            continue;
        }

        if (!PageBuddy(page)) {
            page++;
            continue;
        }

        order = page_order(page);
        // order : 5

        // zone->free_area[5[.free_list[0]: cotig_page_data->node_zones[0].free_area[5].free_area[0]
        list_move(&page->lru,
              &zone->free_area[order].free_list[migratetype]);

        // 에 page : 0x20000 (pfn)
        // page->lru를 자기 자신으로 초기화하고, free_list에 불인다.
        // migratetype 을 2에 있는 page를 0으로 바꾸고, 
        // zone->free_area[5[.free_list[0]: cotig_page_data->node_zones[0].free_area[5].free_area[2]
        // contig_page_data->node_zones[0].free_list[2] 에서
        // contig_page_data->node_zone[0.free_area[5].free_list[0]로 옮김
        set_freepage_migratetype(page, migratetype);
        // migrage type 이 2에서 0으로 바뀜.

        page += 1 << order;
        pages_moved += 1 << order;
    }

    return pages_moved;
    // pages_moved : 1024 (옴겨진 page 수)
}
  • VM_BUG_ON() : page의 nid와 zone의 nid가 일치하는지 ?
        VM_BUG_ON(page_to_nid(page) != zone_to_nid(zone));
    
  • page_to_nid()
    static inline int page_to_nid(const struct page *page)
    {
      return (page->flags >> NODES_PGSHIFT) & NODES_MASK;
      // NODES_PGSHIFT : 0,
      // NODES_MASK : 0,
      // return (page->flags >> 0) & 3; 하위 2비트만 리턴.
    }
    
    • zone_to_nid()
      return 0;
    • pfn_valid_within(page_to_pfn(page))
      if (!pfn_valid_within(page_to_pfn(page))) {
      page++;
      continue;
    • pfn_valid_within()
      return 1;
    • PageBuddy(page)
          if (!PageBuddy(page)) {
             page++;
             continue;
         }
      
    • PageBuddy
      return 1;
  • try_to_steal_freepages()
       if (pages >= (1 << (pageblock_order-1)) ||
               page_group_by_mobility_disabled) {
    
          // pages: ???
          // >
            set_pageblock_migratetype(page, start_type);
           return start_type;
    
    • set_pageblock_migratetype()
      page 블록의 migratetype을 바꿔줌 (2->0)
  • try_to_steal_freepages()
    return start_type : 0
  • __rmqueue_fallback()
    new_type = try_to_steal_freepages() : 0
    o list_del(&page->lru);
    rmv_page_order(page);
  • rmv_page_order()
    page->_mapcount : -1
    page->private : 0
    // page의 _mapcount 를 -1, private값을 0으로 초기화
  • __rmqueue_fallback()
    expand(zone, page, order, current_order, area,
                  new_type);
    
    // i: 1, order ; 0, current_order : 5, start_migratetype:
    // new_type : 0
    return page;
    // page : migratetype이 MIGRATE_UNMOVEABLE인 page

expand ():

  • 페이지가 0이 필요한데. MIGRATE_UNMOVABLE이 없어서.
  • MIGRATE_MOVEABLE을 order 5부터 4, 3, 2, 1으로 해서
  • order 1의 slub을 MIGRAT_UNMOVEABLE로 설정하고
  • 나머지 5부터 반쪽씩 free로 설정한다.
  • smallest에서 MIGRATE_UNMOVEABLE이 있었으면 프리페이지 확장을 하지만,
  • 우리는 smallest가 없었기 때문에 unlikely를 들어와서 fallback에서
  • 가장 큰 영역부터 (오더 5)에서 부터 순차적으로 내려오면서.
  • 남은 영역을 free로 확장해서 설정하고,
  • 오더 1에서 MIGRATE_MOVEABLE에서 할당 받아 MiGRATE_UNMOVEABLE로 설정하고
  • 역시 남은 영역을 free로 확장해서 할당한다.
  • (&contig_page_data->node_zones[0].free_area[4])->free_list[0] 에
  • order 5의 migratetype MIGRATE_MOVEABLE인 lru page + 16 인 page추가
  • free page 수 증가
  • page의 _mapcount 값을 -128, private를 4로 변경.
static inline void expand(struct zone *zone, struct page *page,
    int low, int high, struct free_area *area,
    int migratetype)
{
    // high : current_order : 5
    unsigned long size = 1 << high;

    // high : 5, low : 0
    while (high > low) {
         // area: &contig_page_data->node_zones[0].free_area[5]
        area--;
         // area: &contig_page_data->node_zones[0].free_area[4]

        // high : 5
        high--;
        // high : 4

        // size : 32
        size >>= 1;
        // size : 16

        // zone : contig_page_data->node_zones[0]
        // page : order 5의 migratetype MIGRATE_MOVEABLE인 lru page
        VM_BUG_ON(bad_range(zone, &page[size]));

#ifdef CONFIG_DEBUG_PAGEALLOC  // not set
        if (high < debug_guardpage_minorder()) {
            /*
             * Mark as guard pages (or page), that will allow to
             * merge back to allocator when buddy will be freed.
             * Corresponding page table entries will not be touched,
             * pages will stay not present in virtual address space
             */
            INIT_LIST_HEAD(&page[size].lru);
            set_page_guard_flag(&page[size]);
            set_page_private(&page[size], high);
            /* Guard pages are not available for any usage */
            __mod_zone_freepage_state(zone, -(1 << high),
                          migratetype);
            continue;
        }
#endif
        // size : 16
        // page : order 5의 migratetype MIGRATE_MOVEABLE인 lru page + 16).lru
        // migratetype : 0 ,
        // area->free_list[0] : &contig_page_data->node_zones[0].free_area[4])->free_list[0]
        list_add(&page[size].lru, &area->free_list[migratetype]);
        // &contig_page_data->node_zones[0].free_area[4])->free_list[0]에
        // order K의 migratetype MIGRATE_MOVEABLE lru page + 16 인 page 추가

        // (&contig_page_data->node_zones[0].free_area[4]->free_list[0]
        area->nr_free++;
        // free page 수 증가

        // size : 16,
        // page[16] : order 5의 migratetype 이 MIGRATE_MOVEABLE인 lru page
        set_page_order(&page[size], high);
        // page의 _mapcount 값을 -128, private를 4로 변경.

    }
}
  • expand(zone, page, order, current_order, area, new_type)
    • order는 필요한 크기
    • current_order : 버디에서 가져온 크기
    • 큰 버디 오더에서 사용하려는 오더를 제외한 나머지 버디영역을
    • 미사용영역으로 정리함.
    • (필요한 크기보다 가져온 크기가 클때 )실행함.

__rmqueue()

  • 해당 zone에서 order(크기)에 맞고 migratetype이 같은 page를 구해옴
  • migratetype이 일치 하지 않으면.
  • fallbacks의 enum의 메모리정책에 따라서 할당 받는다.
    1. __rmque_samllest () UNMOVERABLE
    2. __rmqure_fallback () MOVEABLE
    3. RESERVE에서 찾는다.
         if (!page) {
          migratetype = MIGRATE_RESERVE;
          goto retry_reserve;
      
trace_mm_page_alloc_zone_locked(page, order, migratetype);
// page : migratetype MIGRATE_
  • fallback에서 메모리 정책이 결정된다.

requeue_bulk()

    struct page *page = __rmqueue(zone, order, migratetype);
위의 분석이었다.
  // cold :0>
   if (likely(cold == 0))
       list_add(&page->lru, list);
        // page->lru : (migtratetype이 MIGRATE_UNMOVEABLE인 page)->lru
        // list : (&boot_pageset + (__per_cpu_offset[0]))->pcp.lists[0]

   else
       list_add_tail(&page->lru, list);
   // page의 lru가 cold가 1일때 tail로 cold가 0일때 head로 등록됨

  // IS_ENABLED(CONFIG_CMA)  // n/A
   if (IS_ENABLED(CONFIG_CMA)) {
       mt = get_pageblock_migratetype(page);
       if (!is_migrate_cma(mt) && !is_migrate_isolate(mt))
           mt = migratetype;
   }

  // page->index = migratetype
   set_freepage_migratetype(page, mt);
  // page의 index필드를 migratetype 0으로 변경

  // list : (&boot_pageset + (__per_cpu_offset[0]))->pcp.lists[0]
  // page->lru : (migratetype 이 MIGRATE_UNMOVEABLE인 page)->lru
  list = &page->lru;
  // lru는 색인이고, 자료는 pcp.list[0]에 값이 업데이트 됨

  // mt : 0
  if (is_migrate_cma(mt)) // false
       __mod_zone_page_state(zone, NR_FREE_CMA_PAGES,
                     -(1 << order));
 }
 // zone: contig_page_data->node_zones[0], NR_FREE_PAGES : 0, i:1
 __mod_zone_page_state(zone, NR_FREE_PAGES, -(i << order));
// vm_stat[enum]에서 NR_FREE_PAGES인 2번째 인자를 가지고 update하는 함수
 // x = delta + __this_cpu_read(*p)
// (&contig_pgate_data)->node_zones[ZONE_NORMAL].vm_stat[0]의 값을 update함
// t : 32???6 -1 5
 return i;
 // order : 0, return i : 1

buffered_rmqueue()

   if (list_empty(list)) {
       pcp->count += rmqueue_bulk(zone, 0,
               pcp->batch, list,
               migratetype, cold);
        // pcp->count : (&boot_pageset + (__per_cpu_offset[0]))->pcp.list[0]
       if (unlikely(list_empty(list))) // fault
           goto failed;
   }
  • // cold : 0
     if (cold)
         page = list_entry(list->prev, struct page, lru);
     else
        // list-next :((&boot_pageset + (__per_cpu_offset[0]))->pcp.list[0])->next
         page = list_entry(list->next, struct page, lru);
        // page : migratetype이 MIGRATE_UNMOVEABEL인 page
      list_del(&page->lru);
    // list-next :((&boot_pageset + (__per_cpu_offset[0]))->pcp.list[0]에서 현제 page->lru삭제
     pcp->count--;
    //  list-next :((&boot_pageset + (__per_cpu_offset[0]))->pcp.list[0]).count : 0
    
    // gfp_flags : 0x221200
    if (!gfp_thisnode_allocation(gfp_flags)) // true : !false 
        // zone: contig_page_data->noce_zones[0], NR_ALLOC_BATCH :1, order: 0
         __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
        // (&contig_page_data->node_zones[0]->vm_stat[1] update
        // 
    

스터디 log

4824920..d9a9639 master -> origin/master
Merge made by the ‘recursive’ strategy.
arch/arm/include/asm/spinlock.h | 2 +
include/asm-generic/memory_model.h | 1 +
include/linux/list.h | 3 +
include/linux/lockdep.h | 2 +
include/linux/mm.h | 16 -
include/linux/mmzone.h | 6 +
include/linux/page-flags-layout.h | 1 +
include/linux/pageblock-flags.h | 4 +-
include/linux/preempt.h | 1 +
include/linux/spinlock.h | 5 +
include/linux/spinlock_api_smp.h | 3 +
include/linux/vmstat.h | 1 +
include/trace/events/kmem.h | 2 +
kernel/locking/spinlock.c | 2 +
kernel/locking/spinlock_debug.c | 5 +
mm/internal.h | 1 +
mm/page_alloc.c | 281 ++
-
mm/vmstat.c | 10 +-
18 files changed, 335 insertions(+), 11 deletions(-)

댓글 없음:

댓글 쓰기