static int shrink_list(struct list_head *page_list, struct scan_control *sc) { LIST_HEAD(ret_pages); struct pagevec freed_pvec; int pgactivate = 0; int reclaimed = 0; //有进程需要调度,先进行调度 cond_resched();
pagevec_init(&freed_pvec, 1); //对于page_list 链表上的每一个页面试图进行回收 while (!list_empty(page_list)) { struct address_space *mapping; struct page *page; int may_enter_fs; int referenced;
//获取一个页面 page = lru_to_page(page_list); //从lru上摘除 list_del(&page->lru); //page被锁定,不能回收 if (TestSetPageLocked(page))//page is locked? goto keep;
BUG_ON(PageActive(page)); //page正在被writeback,不能回收 if (PageWriteback(page))//page is writeback? goto keep_locked;
sc->nr_scanned++; /* Double the slab pressure for mapped and swapcache pages */
if (page_mapped(page) || PageSwapCache(page)) sc->nr_scanned++; //查看最近该页面有无被访问过 referenced = page_referenced(page, 1, sc->priority <= 0); /* In active use or really unfreeable? Activate it. */ //1页面被访问过,2页面在用户态空间,页面是文件映射页面, //页面在交换高速缓存中,同时满足这两个条件的话,页面不被回收 if (referenced && page_mapping_inuse(page)) goto activate_locked;
#ifdef CONFIG_SWAP
//page is anon and page has not been add to swapcache //该页面是匿名映射的页面,且该页面不在swapcache中 if (PageAnon(page) && !PageSwapCache(page)) { //将页面加入到swap cache中 if (!add_to_swap(page)) goto activate_locked; } #endif /* CONFIG_SWAP */ //得到对应的address_space,有可能是对应文件的address_space,或者是 //swap cache的address_space mapping = page_mapping(page); may_enter_fs = (sc->gfp_mask & __GFP_FS) || (PageSwapCache(page) && (sc->gfp_mask & __GFP_IO));
//该页面被映射到某个用户页表中 if (page_mapped(page) && mapping) { //将该页面在用户页表中的页表项通通清除 switch (try_to_unmap(page)) { case SWAP_FAIL: goto activate_locked; case SWAP_AGAIN: goto keep_locked; case SWAP_SUCCESS: ; /* try to free the page below */ } } //页面是脏的,哈哈,准备往文件或swapcache里面写硬盘吧 if (PageDirty(page)) { if (referenced) goto keep_locked; if (!may_enter_fs) goto keep_locked; if (laptop_mode && !sc->may_writepage) goto keep_locked;
/* Page is dirty, try to write it out here */ //往磁盘上写页面 switch(pageout(page, mapping)) { case PAGE_KEEP: goto keep_locked; case PAGE_ACTIVATE: goto activate_locked; case PAGE_SUCCESS: if (PageWriteback(page) || PageDirty(page)) goto keep;
if (TestSetPageLocked(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_head给释放掉 if (PagePrivate(page)) { if (!try_to_release_page(page, sc->gfp_mask)) goto activate_locked; if (!mapping && page_count(page) == 1) goto free_it; }
if (!mapping) goto keep_locked;/* truncate got there first */