- 论坛徽章:
- 0
|
本帖最后由 blake326 于 2012-05-21 10:57 编辑
2.6.38 kernel
shrink_inactive_list()主要三个步骤:
1. 获取一组待回收page到page_list。
isolate_pages_global(nr_to_scan, &page_list, &nr_scanned, sc->order, sc->reclaim_mode & RECLAIM_MODE_LUMPYRECLAIM ? ISOLATE_BOTH : ISOLATE_INACTIVE,
zone, 0, file);
2. 调用shrink_page_list回收这组page。无法回收的保存在page_list里面。
nr_reclaimed = shrink_page_list(&page_list, zone, sc);
3. 将不能回收的page根据active标志放回相应的lru中。
putback_lru_pages(zone, sc, nr_anon, nr_file, &page_list);
问题再shrink_page_list里面:
while (!list_empty(page_list)) {
循环对每个page分别处理。
检查page是否应该回收。
references = page_check_references(page, sc);
switch (references) {
case PAGEREF_ACTIVATE:
goto activate_locked;
case PAGEREF_KEEP:
goto keep_locked;
case PAGEREF_RECLAIM:
case PAGEREF_RECLAIM_CLEAN:
; /* try to reclaim the page below */
}
反向映射,释放pte和page的映射。
if (page_mapped(page) && mapping) {
switch (try_to_unmap(page, TTU_UNMAP)) {
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 */
}
}
脏页处理。
if (PageDirty(page)) {
nr_dirty++;
}
看page_check_references的代码,如果是用户的匿名page或者映射文件的page,referenced_ptes肯定大于1,导致page_check_references必定返回PAGEREF_KEEP或者PAGEREF_ACTIVATE。
从而无法释放该page,放回到相应的lru中。那么shrink_page_list后面的反向映射什么时候才有机会执行呢?匿名page,映射page怎样才能释放呢?
static enum page_references page_check_references(struct page *page,
struct scan_control *sc)
{
int referenced_ptes, referenced_page;
unsigned long vm_flags;
referenced_ptes = page_referenced(page, 1, sc->mem_cgroup, &vm_flags);
referenced_page = TestClearPageReferenced(page);
/* Lumpy reclaim - ignore references */
if (sc->reclaim_mode & RECLAIM_MODE_LUMPYRECLAIM)
return PAGEREF_RECLAIM;
if (vm_flags & VM_LOCKED)
return PAGEREF_RECLAIM;
if (referenced_ptes) {
if (PageAnon(page))
return PAGEREF_ACTIVATE;
SetPageReferenced(page);
if (referenced_page)
return PAGEREF_ACTIVATE;
return PAGEREF_KEEP;
}
/* Reclaim if clean, defer dirty pages to writeback */
if (referenced_page && !PageSwapBacked(page))
return PAGEREF_RECLAIM_CLEAN;
return PAGEREF_RECLAIM;
}
|
|