Chinaunix首页 | 论坛 | 博客
  • 博客访问: 345470
  • 博文数量: 96
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 152
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-02 09:27
文章分类

全部博文(96)

文章存档

2017年(2)

2016年(30)

2015年(38)

2014年(25)

2013年(1)

我的朋友

分类: LINUX

2015-09-24 14:36:38

原文地址:shrink_page_list 函数分析 作者:alloysystem

shrink_page_list 是页面回收体系中最至关重要的一个函数,它决定在zone->inactive_list中的页面最后是否能被回收释放掉。这个函数的处理流程总结如下
1、如果页面被锁住了,放入继续将页面保留在inactive list中,后就再扫描到底时候再试图回收这些page
2、如果回写控制结构体标记了不允许进行unmap操作,将那些在pte表项中有映射到页面保留在inactive list中。
3、对于正在回写中的页面,如果是同步操作,等待页面回写完成。如果是异步操作,将page继续留在inactive list中,等待以后扫描再回收释放。
4、如果检查到page又被访问了,这个时候page有一定的机会回到active list链表中。必须满足一下条件
a、page被访问,page_referenced检查
b、order小于3,也就是系统趋向于回收较大的页面。对于较小的页面趋向于保留在active list中
c、page_mapping_inuse检查,这个函数在上面的文章中已经分析

5、如果是匿名页面,并且不在swap缓冲区中,将page加入到swap的缓冲区中。
6、如果页面被映射了,调用unmap函数
7、如果页面是脏也,需要向将页面内容换出,调用pateout
8、如果页面和buffer相关联,将buffer释放掉,调用try_to_release_page函数
9、调用__remove_mapping 将页面回收归还伙伴系统。



点击(此处)折叠或打开

  1. /*
  2.  * shrink_page_list() returns the number of reclaimed pages
  3.  */
  4. static unsigned long shrink_page_list(struct list_head *page_list,
  5.                     struct scan_control *sc,
  6.                     enum pageout_io sync_writeback)
  7. {
  8.     LIST_HEAD(ret_pages);
  9.     struct pagevec freed_pvec;
  10.     int pgactivate = 0;
  11.     unsigned long nr_reclaimed = 0;

  12.     cond_resched();

  13.     pagevec_init(&freed_pvec, 1);
  14.     while (!list_empty(page_list)) {
  15.         struct address_space *mapping;
  16.         struct page *page;
  17.         int may_enter_fs;
  18.         int referenced;

  19.         cond_resched();

  20.         page = lru_to_page(page_list);
  21.         list_del(&page->lru);

  22.         /*如果页面被锁住了,放入继续将页面保留在inactive list中,后就再扫描到底时候再试图回收这些page*/
  23.         if (!trylock_page(page))
  24.             goto keep;

  25.         VM_BUG_ON(PageActive(page));

  26.         sc->nr_scanned++;

  27.         if (unlikely(!page_evictable(page, NULL)))
  28.             goto cull_mlocked;
  29.         /*如果回写控制结构体标记了不允许进行unmap操作,将那些在pte表项中有映射到页面保留在inactive list中*/
  30.         if (!sc->may_swap && page_mapped(page))
  31.             goto keep_locked;

  32.         /* Double the slab pressure for mapped and swapcache pages */
  33.         if (page_mapped(page) || PageSwapCache(page))
  34.             sc->nr_scanned++;

  35.         may_enter_fs = (sc->gfp_mask & __GFP_FS) ||
  36.             (PageSwapCache(page) && (sc->gfp_mask & __GFP_IO));
  37.         /*对于正在回写中的页面,如果是同步操作,等待页面回写完成。如果是异步操作,将page继续留在inactive list中,等待以后扫描再回收释放*/
  38.         if (PageWriteback(page)) {
  39.             /*
  40.              * Synchronous reclaim is performed in two passes,
  41.              * first an asynchronous pass over the list to
  42.              * start parallel writeback, and a second synchronous
  43.              * pass to wait for the IO to complete. Wait here
  44.              * for any page for which writeback has already
  45.              * started.
  46.              */
  47.             if (sync_writeback == PAGEOUT_IO_SYNC && may_enter_fs)
  48.                 wait_on_page_writeback(page);
  49.             else
  50.                 goto keep_locked;
  51.         }

  52.         /*如果检查到page又被访问了,这个时候page有一定的机会回到active list链表中。必须满足一下条件
  53.         a、page被访问,page_referenced检查
  54.         b、order小于3,也就是系统趋向于回收较大的页面。对于较小的页面趋向于保留在active list中
  55.         c、page_mapping_inuse检查,这个函数在上面的文章中已经分析
  56.         */
  57.         referenced = page_referenced(page, 1, sc->mem_cgroup);
  58.         /* In active use or really unfreeable? Activate it. */
  59.         if (sc->order <= PAGE_ALLOC_COSTLY_ORDER &&
  60.                     referenced && page_mapping_inuse(page))
  61.             goto activate_locked;

  62.         /*如果是匿名页面,并且不在swap缓冲区中,将page加入到swap的缓冲区中。*/
  63.         /*
  64.          * Anonymous process memory has backing store?
  65.          * Try to allocate it some swap space here.
  66.          */
  67.         if (PageAnon(page) && !PageSwapCache(page)) {
  68.             if (!(sc->gfp_mask & __GFP_IO))
  69.                 goto keep_locked;
  70.             if (!add_to_swap(page))
  71.                 goto activate_locked;
  72.             may_enter_fs = 1;
  73.         }

  74.         mapping = page_mapping(page);
  75.         
  76.         /*如果页面被映射了,调用unmap函数*/
  77.         /*
  78.          * The page is mapped into the page tables of one or more
  79.          * processes. Try to unmap it here.
  80.          */
  81.         if (page_mapped(page) && mapping) {
  82.             switch (try_to_unmap(page, 0)) {
  83.             case SWAP_FAIL:
  84.                 goto activate_locked;
  85.             case SWAP_AGAIN:
  86.                 goto keep_locked;
  87.             case SWAP_MLOCK:
  88.                 goto cull_mlocked;
  89.             case SWAP_SUCCESS:
  90.                 ; /* try to free the page below */
  91.             }
  92.         }
  93.         
  94.         /*如果页面是脏也,需要向将页面内容换出,调用pateout*/
  95.         if (PageDirty(page)) {
  96.             if (sc->order <= PAGE_ALLOC_COSTLY_ORDER && referenced)
  97.                 goto keep_locked;
  98.             if (!may_enter_fs)
  99.                 goto keep_locked;
  100.             if (!sc->may_writepage)
  101.                 goto keep_locked;

  102.             /* Page is dirty, try to write it out here */
  103.             switch (pageout(page, mapping, sync_writeback)) {
  104.             case PAGE_KEEP:
  105.                 goto keep_locked;
  106.             case PAGE_ACTIVATE:
  107.                 goto activate_locked;
  108.             case PAGE_SUCCESS:
  109.                 if (PageWriteback(page) || PageDirty(page))
  110.                     goto keep;
  111.                 /*
  112.                  * A synchronous write - probably a ramdisk. Go
  113.                  * ahead and try to reclaim the page.
  114.                  */
  115.                 if (!trylock_page(page))
  116.                     goto keep;
  117.                 if (PageDirty(page) || PageWriteback(page))
  118.                     goto keep_locked;
  119.                 mapping = page_mapping(page);
  120.             case PAGE_CLEAN:
  121.                 ; /* try to free the page below */
  122.             }
  123.         }
  124.         
  125.         /*如果页面和buffer相关联,将buffer释放掉,调用try_to_release_page函数*/
  126.         /*
  127.          * If the page has buffers, try to free the buffer mappings
  128.          * associated with this page. If we succeed we try to free
  129.          * the page as well.
  130.          *
  131.          * We do this even if the page is PageDirty().
  132.          * try_to_release_page() does not perform I/O, but it is
  133.          * possible for a page to have PageDirty set, but it is actually
  134.          * clean (all its buffers are clean). This happens if the
  135.          * buffers were written out directly, with submit_bh(). ext3
  136.          * will do this, as well as the blockdev mapping.
  137.          * try_to_release_page() will discover that cleanness and will
  138.          * drop the buffers and mark the page clean - it can be freed.
  139.          *
  140.          * Rarely, pages can have buffers and no ->mapping. These are
  141.          * the pages which were not successfully invalidated in
  142.          * truncate_complete_page(). We try to drop those buffers here
  143.          * and if that worked, and the page is no longer mapped into
  144.          * process address space (page_count == 1) it can be freed.
  145.          * Otherwise, leave the page on the LRU so it is swappable.
  146.          */
  147.         if (PagePrivate(page)) {
  148.             if (!try_to_release_page(page, sc->gfp_mask))
  149.                 goto activate_locked;
  150.             if (!mapping && page_count(page) == 1) {
  151.                 unlock_page(page);
  152.                 if (put_page_testzero(page))
  153.                     goto free_it;
  154.                 else {
  155.                     /*
  156.                      * rare race with speculative reference.
  157.                      * the speculative reference will free
  158.                      * this page shortly, so we may
  159.                      * increment nr_reclaimed here (and
  160.                      * leave it off the LRU).
  161.                      */
  162.                     nr_reclaimed++;
  163.                     continue;
  164.                 }
  165.             }
  166.         }
  167.         
  168.         /*调用__remove_mapping 将页面回收归还伙伴系统。*/
  169.         if (!mapping || !__remove_mapping(mapping, page))
  170.             goto keep_locked;

  171.         /*
  172.          * At this point, we have no other references and there is
  173.          * no way to pick any more up (removed from LRU, removed
  174.          * from pagecache). Can use non-atomic bitops now (and
  175.          * we obviously don't have to worry about waking up a process
  176.          * waiting on the page lock, because there are no references.
  177.          */
  178.         __clear_page_locked(page);
  179. free_it:
  180.         nr_reclaimed++;
  181.         if (!pagevec_add(&freed_pvec, page)) {
  182.             __pagevec_free(&freed_pvec);
  183.             pagevec_reinit(&freed_pvec);
  184.         }
  185.         continue;

  186. cull_mlocked:
  187.         if (PageSwapCache(page))
  188.             try_to_free_swap(page);
  189.         unlock_page(page);
  190.         putback_lru_page(page);
  191.         continue;

  192. activate_locked:
  193.         /* Not a candidate for swapping, so reclaim swap space. */
  194.         if (PageSwapCache(page) && vm_swap_full())
  195.             try_to_free_swap(page);
  196.         VM_BUG_ON(PageActive(page));
  197.         SetPageActive(page);
  198.         pgactivate++;
  199. keep_locked:
  200.         unlock_page(page);
  201. keep:
  202.         list_add(&page->lru, &ret_pages);
  203.         VM_BUG_ON(PageLRU(page) || PageUnevictable(page));
  204.     }
  205.     list_splice(&ret_pages, page_list);
  206.     if (pagevec_count(&freed_pvec))
  207.         __pagevec_free(&freed_pvec);
  208.     count_vm_events(PGACTIVATE, pgactivate);
  209.     return nr_reclaimed;
  210. }


阅读(2714) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~