⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vmscan.c

📁 最新最稳定的Linux内存管理模块源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				nr_taken++;				scan++;				break;			case -EBUSY:				/* else it is being freed elsewhere */				list_move(&cursor_page->lru, src);			default:				break;	/* ! on LRU or wrong list */			}		}	}	*scanned = scan;	return nr_taken;}static unsigned long isolate_pages_global(unsigned long nr,					struct list_head *dst,					unsigned long *scanned, int order,					int mode, struct zone *z,					struct mem_cgroup *mem_cont,					int active, int file){	int lru = LRU_BASE;	if (active)		lru += LRU_ACTIVE;	if (file)		lru += LRU_FILE;	return isolate_lru_pages(nr, &z->lru[lru].list, dst, scanned, order,								mode, !!file);}/* * clear_active_flags() is a helper for shrink_active_list(), clearing * any active bits from the pages in the list. */static unsigned long clear_active_flags(struct list_head *page_list,					unsigned int *count){	int nr_active = 0;	int lru;	struct page *page;	list_for_each_entry(page, page_list, lru) {		lru = page_is_file_cache(page);		if (PageActive(page)) {			lru += LRU_ACTIVE;			ClearPageActive(page);			nr_active++;		}		count[lru]++;	}	return nr_active;}/** * isolate_lru_page - tries to isolate a page from its LRU list * @page: page to isolate from its LRU list * * Isolates a @page from an LRU list, clears PageLRU and adjusts the * vmstat statistic corresponding to whatever LRU list the page was on. * * Returns 0 if the page was removed from an LRU list. * Returns -EBUSY if the page was not on an LRU list. * * The returned page will have PageLRU() cleared.  If it was found on * the active list, it will have PageActive set.  If it was found on * the unevictable list, it will have the PageUnevictable bit set. That flag * may need to be cleared by the caller before letting the page go. * * The vmstat statistic corresponding to the list on which the page was * found will be decremented. * * Restrictions: * (1) Must be called with an elevated refcount on the page. This is a *     fundamentnal difference from isolate_lru_pages (which is called *     without a stable reference). * (2) the lru_lock must not be held. * (3) interrupts must be enabled. */int isolate_lru_page(struct page *page){	int ret = -EBUSY;	if (PageLRU(page)) {		struct zone *zone = page_zone(page);		spin_lock_irq(&zone->lru_lock);		if (PageLRU(page) && get_page_unless_zero(page)) {			int lru = page_lru(page);			ret = 0;			ClearPageLRU(page);			del_page_from_lru_list(zone, page, lru);		}		spin_unlock_irq(&zone->lru_lock);	}	return ret;}/* * shrink_inactive_list() is a helper for shrink_zone().  It returns the number * of reclaimed pages */static unsigned long shrink_inactive_list(unsigned long max_scan,			struct zone *zone, struct scan_control *sc,			int priority, int file){	LIST_HEAD(page_list);	struct pagevec pvec;	unsigned long nr_scanned = 0;	unsigned long nr_reclaimed = 0;	struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);	pagevec_init(&pvec, 1);	lru_add_drain();	spin_lock_irq(&zone->lru_lock);	do {		struct page *page;		unsigned long nr_taken;		unsigned long nr_scan;		unsigned long nr_freed;		unsigned long nr_active;		unsigned int count[NR_LRU_LISTS] = { 0, };		int mode = ISOLATE_INACTIVE;		/*		 * If we need a large contiguous chunk of memory, or have		 * trouble getting a small set of contiguous pages, we		 * will reclaim both active and inactive pages.		 *		 * We use the same threshold as pageout congestion_wait below.		 */		if (sc->order > PAGE_ALLOC_COSTLY_ORDER)			mode = ISOLATE_BOTH;		else if (sc->order && priority < DEF_PRIORITY - 2)			mode = ISOLATE_BOTH;		nr_taken = sc->isolate_pages(sc->swap_cluster_max,			     &page_list, &nr_scan, sc->order, mode,				zone, sc->mem_cgroup, 0, file);		nr_active = clear_active_flags(&page_list, count);		__count_vm_events(PGDEACTIVATE, nr_active);		__mod_zone_page_state(zone, NR_ACTIVE_FILE,						-count[LRU_ACTIVE_FILE]);		__mod_zone_page_state(zone, NR_INACTIVE_FILE,						-count[LRU_INACTIVE_FILE]);		__mod_zone_page_state(zone, NR_ACTIVE_ANON,						-count[LRU_ACTIVE_ANON]);		__mod_zone_page_state(zone, NR_INACTIVE_ANON,						-count[LRU_INACTIVE_ANON]);		if (scanning_global_lru(sc))			zone->pages_scanned += nr_scan;		reclaim_stat->recent_scanned[0] += count[LRU_INACTIVE_ANON];		reclaim_stat->recent_scanned[0] += count[LRU_ACTIVE_ANON];		reclaim_stat->recent_scanned[1] += count[LRU_INACTIVE_FILE];		reclaim_stat->recent_scanned[1] += count[LRU_ACTIVE_FILE];		spin_unlock_irq(&zone->lru_lock);		nr_scanned += nr_scan;		nr_freed = shrink_page_list(&page_list, sc, PAGEOUT_IO_ASYNC);		/*		 * If we are direct reclaiming for contiguous pages and we do		 * not reclaim everything in the list, try again and wait		 * for IO to complete. This will stall high-order allocations		 * but that should be acceptable to the caller		 */		if (nr_freed < nr_taken && !current_is_kswapd() &&					sc->order > PAGE_ALLOC_COSTLY_ORDER) {			congestion_wait(WRITE, HZ/10);			/*			 * The attempt at page out may have made some			 * of the pages active, mark them inactive again.			 */			nr_active = clear_active_flags(&page_list, count);			count_vm_events(PGDEACTIVATE, nr_active);			nr_freed += shrink_page_list(&page_list, sc,							PAGEOUT_IO_SYNC);		}		nr_reclaimed += nr_freed;		local_irq_disable();		if (current_is_kswapd()) {			__count_zone_vm_events(PGSCAN_KSWAPD, zone, nr_scan);			__count_vm_events(KSWAPD_STEAL, nr_freed);		} else if (scanning_global_lru(sc))			__count_zone_vm_events(PGSCAN_DIRECT, zone, nr_scan);		__count_zone_vm_events(PGSTEAL, zone, nr_freed);		if (nr_taken == 0)			goto done;		spin_lock(&zone->lru_lock);		/*		 * Put back any unfreeable pages.		 */		while (!list_empty(&page_list)) {			int lru;			page = lru_to_page(&page_list);			VM_BUG_ON(PageLRU(page));			list_del(&page->lru);			if (unlikely(!page_evictable(page, NULL))) {				spin_unlock_irq(&zone->lru_lock);				putback_lru_page(page);				spin_lock_irq(&zone->lru_lock);				continue;			}			SetPageLRU(page);			lru = page_lru(page);			add_page_to_lru_list(zone, page, lru);			if (PageActive(page)) {				int file = !!page_is_file_cache(page);				reclaim_stat->recent_rotated[file]++;			}			if (!pagevec_add(&pvec, page)) {				spin_unlock_irq(&zone->lru_lock);				__pagevec_release(&pvec);				spin_lock_irq(&zone->lru_lock);			}		}  	} while (nr_scanned < max_scan);	spin_unlock(&zone->lru_lock);done:	local_irq_enable();	pagevec_release(&pvec);	return nr_reclaimed;}/* * We are about to scan this zone at a certain priority level.  If that priority * level is smaller (ie: more urgent) than the previous priority, then note * that priority level within the zone.  This is done so that when the next * process comes in to scan this zone, it will immediately start out at this * priority level rather than having to build up its own scanning priority. * Here, this priority affects only the reclaim-mapped threshold. */static inline void note_zone_scanning_priority(struct zone *zone, int priority){	if (priority < zone->prev_priority)		zone->prev_priority = priority;}/* * This moves pages from the active list to the inactive list. * * We move them the other way if the page is referenced by one or more * processes, from rmap. * * If the pages are mostly unmapped, the processing is fast and it is * appropriate to hold zone->lru_lock across the whole operation.  But if * the pages are mapped, the processing is slow (page_referenced()) so we * should drop zone->lru_lock around each page.  It's impossible to balance * this, so instead we remove the pages from the LRU while processing them. * It is safe to rely on PG_active against the non-LRU pages in here because * nobody will play with that bit on a non-LRU page. * * The downside is that we have to touch page->_count against each page. * But we had to alter page->flags anyway. */static void shrink_active_list(unsigned long nr_pages, struct zone *zone,			struct scan_control *sc, int priority, int file){	unsigned long pgmoved;	int pgdeactivate = 0;	unsigned long pgscanned;	LIST_HEAD(l_hold);	/* The pages which were snipped off */	LIST_HEAD(l_inactive);	struct page *page;	struct pagevec pvec;	enum lru_list lru;	struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);	lru_add_drain();	spin_lock_irq(&zone->lru_lock);	pgmoved = sc->isolate_pages(nr_pages, &l_hold, &pgscanned, sc->order,					ISOLATE_ACTIVE, zone,					sc->mem_cgroup, 1, file);	/*	 * zone->pages_scanned is used for detect zone's oom	 * mem_cgroup remembers nr_scan by itself.	 */	if (scanning_global_lru(sc)) {		zone->pages_scanned += pgscanned;	}	reclaim_stat->recent_scanned[!!file] += pgmoved;	if (file)		__mod_zone_page_state(zone, NR_ACTIVE_FILE, -pgmoved);	else		__mod_zone_page_state(zone, NR_ACTIVE_ANON, -pgmoved);	spin_unlock_irq(&zone->lru_lock);	pgmoved = 0;	while (!list_empty(&l_hold)) {		cond_resched();		page = lru_to_page(&l_hold);		list_del(&page->lru);		if (unlikely(!page_evictable(page, NULL))) {			putback_lru_page(page);			continue;		}		/* page_referenced clears PageReferenced */		if (page_mapping_inuse(page) &&		    page_referenced(page, 0, sc->mem_cgroup))			pgmoved++;		list_add(&page->lru, &l_inactive);	}	/*	 * Move the pages to the [file or anon] inactive list.	 */	pagevec_init(&pvec, 1);	lru = LRU_BASE + file * LRU_FILE;	spin_lock_irq(&zone->lru_lock);	/*	 * Count referenced pages from currently used mappings as	 * rotated, even though they are moved to the inactive list.	 * This helps balance scan pressure between file and anonymous	 * pages in get_scan_ratio.	 */	reclaim_stat->recent_rotated[!!file] += pgmoved;	pgmoved = 0;	while (!list_empty(&l_inactive)) {		page = lru_to_page(&l_inactive);		prefetchw_prev_lru_page(page, &l_inactive, flags);		VM_BUG_ON(PageLRU(page));		SetPageLRU(page);		VM_BUG_ON(!PageActive(page));		ClearPageActive(page);		list_move(&page->lru, &zone->lru[lru].list);		mem_cgroup_add_lru_list(page, lru);		pgmoved++;		if (!pagevec_add(&pvec, page)) {			__mod_zone_page_state(zone, NR_LRU_BASE + lru, pgmoved);			spin_unlock_irq(&zone->lru_lock);			pgdeactivate += pgmoved;			pgmoved = 0;			if (buffer_heads_over_limit)				pagevec_strip(&pvec);			__pagevec_release(&pvec);			spin_lock_irq(&zone->lru_lock);		}	}	__mod_zone_page_state(zone, NR_LRU_BASE + lru, pgmoved);	pgdeactivate += pgmoved;	if (buffer_heads_over_limit) {		spin_unlock_irq(&zone->lru_lock);		pagevec_strip(&pvec);		spin_lock_irq(&zone->lru_lock);	}	__count_zone_vm_events(PGREFILL, zone, pgscanned);	__count_vm_events(PGDEACTIVATE, pgdeactivate);	spin_unlock_irq(&zone->lru_lock);	if (vm_swap_full())		pagevec_swap_free(&pvec);	pagevec_release(&pvec);}static int inactive_anon_is_low_global(struct zone *zone){	unsigned long active, inactive;	active = zone_page_state(zone, NR_ACTIVE_ANON);	inactive = zone_page_state(zone, NR_INACTIVE_ANON);	if (inactive * zone->inactive_ratio < active)		return 1;	return 0;}/** * inactive_anon_is_low - check if anonymous pages need to be deactivated * @zone: zone to check * @sc:   scan control of this context * * Returns true if the zone does not have enough inactive anon pages, * meaning some active anon pages need to be deactivated. */static int inactive_anon_is_low(struct zone *zone, struct scan_control *sc){	int low;	if (scanning_global_lru(sc))		low = inactive_anon_is_low_global(zone);	else		low = mem_cgroup_inactive_anon_is_low(sc->mem_cgroup);	return low;}static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan,	struct zone *zone, struct scan_control *sc, int priority){	int file = is_file_lru(lru);	if (lru == LRU_ACTIVE_FILE) {		shrink_active_list(nr_to_scan, zone, sc, priority, file);		return 0;	}	if (lru == LRU_ACTIVE_ANON && inactive_anon_is_low(zone, sc)) {		shrink_active_list(nr_to_scan, zone, sc, priority, file);		return 0;	}	return shrink_inactive_list(nr_to_scan, zone, sc, priority, file);}/* * Determine how aggressively the anon and file LRU lists should be * scanned.  The relative value of each set of LRU lists is determined * by looking at the fraction of the pages scanned we did rotate back * onto the active list instead of evict. * * percent[0] specifies how much pressure to put on ram/swap backed * memory, while percent[1] determines pressure on the file LRUs. */static void get_scan_ratio(struct zone *zone, struct scan_control *sc,					unsigned long *percent){	unsigned long anon, file, free;	unsigned long anon_prio, file_prio;	unsigned long ap, fp;	struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);	/* If we have no swap space, do not bother scanning anon pages. */	if (nr_swap_pages <= 0) {		percent[0] = 0;		percent[1] = 100;		return;	}	anon  = zone_nr_pages(zone, sc, LRU_ACTIVE_ANON) +		zone_nr_pages(zone, sc, LRU_INACTIVE_ANON);	file  = zone_nr_pages(zone, sc, LRU_ACTIVE_FILE) +		zone_nr_pages(zone, sc, LRU_INACTIVE_FILE);	if (scanning_global_lru(sc)) {		free  = zone_page_state(zone, NR_FREE_PAGES);		/* If we have very few page cache pages,		   force-scan anon pages. */		if (unlikely(file + free <= zone->pages_high)) {			percent[0] = 100;			percent[1] = 0;			return;		}	}	/*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -