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 将页面回收归还伙伴系统。
- /*
- * shrink_page_list() returns the number of reclaimed pages
- */
- static unsigned long shrink_page_list(struct list_head *page_list,
- struct scan_control *sc,
- enum pageout_io sync_writeback)
- {
- LIST_HEAD(ret_pages);
- struct pagevec freed_pvec;
- int pgactivate = 0;
- unsigned long nr_reclaimed = 0;
- cond_resched();
- pagevec_init(&freed_pvec, 1);
- while (!list_empty(page_list)) {
- struct address_space *mapping;
- struct page *page;
- int may_enter_fs;
- int referenced;
- cond_resched();
- page = lru_to_page(page_list);
- list_del(&page->lru);
- /*如果页面被锁住了,放入继续将页面保留在inactive list中,后就再扫描到底时候再试图回收这些page*/
- if (!trylock_page(page))
- goto keep;
- VM_BUG_ON(PageActive(page));
- sc->nr_scanned++;
- if (unlikely(!page_evictable(page, NULL)))
- goto cull_mlocked;
- /*如果回写控制结构体标记了不允许进行unmap操作,将那些在pte表项中有映射到页面保留在inactive list中*/
- if (!sc->may_swap && page_mapped(page))
- goto keep_locked;
- /* Double the slab pressure for mapped and swapcache pages */
- if (page_mapped(page) || PageSwapCache(page))
- sc->nr_scanned++;
- may_enter_fs = (sc->gfp_mask & __GFP_FS) ||
- (PageSwapCache(page) && (sc->gfp_mask & __GFP_IO));
- /*对于正在回写中的页面,如果是同步操作,等待页面回写完成。如果是异步操作,将page继续留在inactive list中,等待以后扫描再回收释放*/
- if (PageWriteback(page)) {
- /*
- * Synchronous reclaim is performed in two passes,
- * first an asynchronous pass over the list to
- * start parallel writeback, and a second synchronous
- * pass to wait for the IO to complete. Wait here
- * for any page for which writeback has already
- * started.
- */
- if (sync_writeback == PAGEOUT_IO_SYNC && may_enter_fs)
- wait_on_page_writeback(page);
- else
- goto keep_locked;
- }
- /*如果检查到page又被访问了,这个时候page有一定的机会回到active list链表中。必须满足一下条件
- a、page被访问,page_referenced检查
- b、order小于3,也就是系统趋向于回收较大的页面。对于较小的页面趋向于保留在active list中
- c、page_mapping_inuse检查,这个函数在上面的文章中已经分析
- */
- referenced = page_referenced(page, 1, sc->mem_cgroup);
- /* In active use or really unfreeable? Activate it. */
- if (sc->order <= PAGE_ALLOC_COSTLY_ORDER &&
- referenced && page_mapping_inuse(page))
- goto activate_locked;
- /*如果是匿名页面,并且不在swap缓冲区中,将page加入到swap的缓冲区中。*/
- /*
- * Anonymous process memory has backing store?
- * Try to allocate it some swap space here.
- */
- if (PageAnon(page) && !PageSwapCache(page)) {
- if (!(sc->gfp_mask & __GFP_IO))
- goto keep_locked;
- if (!add_to_swap(page))
- goto activate_locked;
- may_enter_fs = 1;
- }
- mapping = page_mapping(page);
-
- /*如果页面被映射了,调用unmap函数*/
- /*
- * The page is mapped into the page tables of one or more
- * processes. Try to unmap it here.
- */
- if (page_mapped(page) && mapping) {
- switch (try_to_unmap(page, 0)) {
- case SWAP_FAIL:
- goto activate_locked;
- case SWAP_AGAIN:
- goto keep_locked;
- case SWAP_MLOCK:
- goto cull_mlocked;
- case SWAP_SUCCESS:
- ; /* try to free the page below */
- }
- }
-
- /*如果页面是脏也,需要向将页面内容换出,调用pateout*/
- if (PageDirty(page)) {
- if (sc->order <= PAGE_ALLOC_COSTLY_ORDER && referenced)
- goto keep_locked;
- if (!may_enter_fs)
- goto keep_locked;
- if (!sc->may_writepage)
- goto keep_locked;
- /* Page is dirty, try to write it out here */
- switch (pageout(page, mapping, sync_writeback)) {
- case PAGE_KEEP:
- goto keep_locked;
- case PAGE_ACTIVATE:
- goto activate_locked;
- case PAGE_SUCCESS:
- if (PageWriteback(page) || PageDirty(page))
- goto keep;
- /*
- * A synchronous write - probably a ramdisk. Go
- * ahead and try to reclaim the page.
- */
- if (!trylock_page(page))
- goto keep;
- if (PageDirty(page) || PageWriteback(page))
- goto keep_locked;
- mapping = page_mapping(page);
- case PAGE_CLEAN:
- ; /* try to free the page below */
- }
- }
-
- /*如果页面和buffer相关联,将buffer释放掉,调用try_to_release_page函数*/
- /*
- * If the page has buffers, try to free the buffer mappings
- * associated with this page. If we succeed we try to free
- * the page as well.
- *
- * We do this even if the page is PageDirty().
- * try_to_release_page() does not perform I/O, but it is
- * possible for a page to have PageDirty set, but it is actually
- * clean (all its buffers are clean). This happens if the
- * buffers were written out directly, with submit_bh(). ext3
- * will do this, as well as the blockdev mapping.
- * try_to_release_page() will discover that cleanness and will
- * drop the buffers and mark the page clean - it can be freed.
- *
- * Rarely, pages can have buffers and no ->mapping. These are
- * the pages which were not successfully invalidated in
- * truncate_complete_page(). We try to drop those buffers here
- * and if that worked, and the page is no longer mapped into
- * process address space (page_count == 1) it can be freed.
- * Otherwise, leave the page on the LRU so it is swappable.
- */
- if (PagePrivate(page)) {
- if (!try_to_release_page(page, sc->gfp_mask))
- goto activate_locked;
- if (!mapping && page_count(page) == 1) {
- unlock_page(page);
- if (put_page_testzero(page))
- goto free_it;
- else {
- /*
- * rare race with speculative reference.
- * the speculative reference will free
- * this page shortly, so we may
- * increment nr_reclaimed here (and
- * leave it off the LRU).
- */
- nr_reclaimed++;
- continue;
- }
- }
- }
-
- /*调用__remove_mapping 将页面回收归还伙伴系统。*/
- if (!mapping || !__remove_mapping(mapping, page))
- goto keep_locked;
- /*
- * At this point, we have no other references and there is
- * no way to pick any more up (removed from LRU, removed
- * from pagecache). Can use non-atomic bitops now (and
- * we obviously don't have to worry about waking up a process
- * waiting on the page lock, because there are no references.
- */
- __clear_page_locked(page);
- free_it:
- nr_reclaimed++;
- if (!pagevec_add(&freed_pvec, page)) {
- __pagevec_free(&freed_pvec);
- pagevec_reinit(&freed_pvec);
- }
- continue;
- cull_mlocked:
- if (PageSwapCache(page))
- try_to_free_swap(page);
- unlock_page(page);
- putback_lru_page(page);
- continue;
- activate_locked:
- /* Not a candidate for swapping, so reclaim swap space. */
- if (PageSwapCache(page) && vm_swap_full())
- try_to_free_swap(page);
- VM_BUG_ON(PageActive(page));
- SetPageActive(page);
- pgactivate++;
- keep_locked:
- unlock_page(page);
- keep:
- list_add(&page->lru, &ret_pages);
- VM_BUG_ON(PageLRU(page) || PageUnevictable(page));
- }
- list_splice(&ret_pages, page_list);
- if (pagevec_count(&freed_pvec))
- __pagevec_free(&freed_pvec);
- count_vm_events(PGACTIVATE, pgactivate);
- return nr_reclaimed;
- }
阅读(4534) | 评论(0) | 转发(1) |