3986 lines · 107.2 KB · C
RawDownload
/* *  linux/mm/memory.c * *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds */ /* * demand-loading started 01.12.91 - seems it is high on the list of * things wanted, and it should be easy to implement. - Linus */ /* * Ok, demand-loading was easy, shared pages a little bit tricker. Shared * pages started 02.12.91, seems to work. - Linus. * * Tested sharing by executing about 30 /bin/sh: under the old kernel it * would have taken more than the 6M I have free, but it worked well as * far as I could see. * * Also corrected some "invalidate()"s - I wasn't doing enough of them. */ /* * Real VM (paging to/from disk) started 18.12.91. Much more work and * thought has to go into this. Oh, well.. * 19.12.91  -  works, somewhat. Sometimes I get faults, don't know why. *		Found it. Everything seems to work now. * 20.12.91  -  Ok, making the swap-device changeable like the root. */ /* * 05.04.94  -  Multi-page memory management added for v1.1. * 		Idea by Alex Bligh (alex@cconcepts.co.uk) * * 16.07.99  -  Support of BIGMEM added by Gerhard Wichert, Siemens AG *		(Gerhard.Wichert@pdb.siemens.de) * * Aug/Sep 2004 Changed to four level page tables (Andi Kleen) */ #include <linux/kernel_stat.h>#include <linux/mm.h>#include <linux/hugetlb.h>#include <linux/mman.h>#include <linux/swap.h>#include <linux/highmem.h>#include <linux/pagemap.h>#include <linux/ksm.h>#include <linux/rmap.h>#include <linux/export.h>#include <linux/delayacct.h>#include <linux/init.h>#include <linux/writeback.h>#include <linux/memcontrol.h>#include <linux/mmu_notifier.h>#include <linux/kallsyms.h>#include <linux/swapops.h>#include <linux/elf.h>#include <linux/gfp.h> #include <asm/io.h>#include <asm/pgalloc.h>#include <asm/uaccess.h>#include <asm/tlb.h>#include <asm/tlbflush.h>#include <asm/pgtable.h> #include "internal.h" #ifndef CONFIG_NEED_MULTIPLE_NODES/* use the per-pgdat data instead for discontigmem - mbligh */unsigned long max_mapnr;struct page *mem_map; EXPORT_SYMBOL(max_mapnr);EXPORT_SYMBOL(mem_map);#endif unsigned long num_physpages;/* * A number of key systems in x86 including ioremap() rely on the assumption * that high_memory defines the upper bound on direct map memory, then end * of ZONE_NORMAL.  Under CONFIG_DISCONTIG this means that max_low_pfn and * highstart_pfn must be the same; there must be no gap between ZONE_NORMAL * and ZONE_HIGHMEM. */void * high_memory; EXPORT_SYMBOL(num_physpages);EXPORT_SYMBOL(high_memory); /* * Randomize the address space (stacks, mmaps, brk, etc.). * * ( When CONFIG_COMPAT_BRK=y we exclude brk from randomization, *   as ancient (libc5 based) binaries can segfault. ) */int randomize_va_space __read_mostly =#ifdef CONFIG_COMPAT_BRK					1;#else					2;#endif static int __init disable_randmaps(char *s){	randomize_va_space = 0;	return 1;}__setup("norandmaps", disable_randmaps); unsigned long zero_pfn __read_mostly;unsigned long highest_memmap_pfn __read_mostly; /* * CONFIG_MMU architectures set up ZERO_PAGE in their paging_init() */static int __init init_zero_pfn(void){	zero_pfn = page_to_pfn(ZERO_PAGE(0));	return 0;}core_initcall(init_zero_pfn);  #if defined(SPLIT_RSS_COUNTING) static void __sync_task_rss_stat(struct task_struct *task, struct mm_struct *mm){	int i; 	for (i = 0; i < NR_MM_COUNTERS; i++) {		if (task->rss_stat.count[i]) {			add_mm_counter(mm, i, task->rss_stat.count[i]);			task->rss_stat.count[i] = 0;		}	}	task->rss_stat.events = 0;} static void add_mm_counter_fast(struct mm_struct *mm, int member, int val){	struct task_struct *task = current; 	if (likely(task->mm == mm))		task->rss_stat.count[member] += val;	else		add_mm_counter(mm, member, val);}#define inc_mm_counter_fast(mm, member) add_mm_counter_fast(mm, member, 1)#define dec_mm_counter_fast(mm, member) add_mm_counter_fast(mm, member, -1) /* sync counter once per 64 page faults */#define TASK_RSS_EVENTS_THRESH	(64)static void check_sync_rss_stat(struct task_struct *task){	if (unlikely(task != current))		return;	if (unlikely(task->rss_stat.events++ > TASK_RSS_EVENTS_THRESH))		__sync_task_rss_stat(task, task->mm);} unsigned long get_mm_counter(struct mm_struct *mm, int member){	long val = 0; 	/*	 * Don't use task->mm here...for avoiding to use task_get_mm()..	 * The caller must guarantee task->mm is not invalid.	 */	val = atomic_long_read(&mm->rss_stat.count[member]);	/*	 * counter is updated in asynchronous manner and may go to minus.	 * But it's never be expected number for users.	 */	if (val < 0)		return 0;	return (unsigned long)val;} void sync_mm_rss(struct task_struct *task, struct mm_struct *mm){	__sync_task_rss_stat(task, mm);}#else /* SPLIT_RSS_COUNTING */ #define inc_mm_counter_fast(mm, member) inc_mm_counter(mm, member)#define dec_mm_counter_fast(mm, member) dec_mm_counter(mm, member) static void check_sync_rss_stat(struct task_struct *task){} #endif /* SPLIT_RSS_COUNTING */ #ifdef HAVE_GENERIC_MMU_GATHER static int tlb_next_batch(struct mmu_gather *tlb){	struct mmu_gather_batch *batch; 	batch = tlb->active;	if (batch->next) {		tlb->active = batch->next;		return 1;	} 	batch = (void *)__get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);	if (!batch)		return 0; 	batch->next = NULL;	batch->nr   = 0;	batch->max  = MAX_GATHER_BATCH; 	tlb->active->next = batch;	tlb->active = batch; 	return 1;} /* tlb_gather_mmu *	Called to initialize an (on-stack) mmu_gather structure for page-table *	tear-down from @mm. The @fullmm argument is used when @mm is without *	users and we're going to destroy the full address space (exit/execve). */void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm){	tlb->mm = mm; 	tlb->fullmm     = fullmm;	tlb->need_flush = 0;	tlb->fast_mode  = (num_possible_cpus() == 1);	tlb->local.next = NULL;	tlb->local.nr   = 0;	tlb->local.max  = ARRAY_SIZE(tlb->__pages);	tlb->active     = &tlb->local; #ifdef CONFIG_HAVE_RCU_TABLE_FREE	tlb->batch = NULL;#endif} void tlb_flush_mmu(struct mmu_gather *tlb){	struct mmu_gather_batch *batch; 	if (!tlb->need_flush)		return;	tlb->need_flush = 0;	tlb_flush(tlb);#ifdef CONFIG_HAVE_RCU_TABLE_FREE	tlb_table_flush(tlb);#endif 	if (tlb_fast_mode(tlb))		return; 	for (batch = &tlb->local; batch; batch = batch->next) {		free_pages_and_swap_cache(batch->pages, batch->nr);		batch->nr = 0;	}	tlb->active = &tlb->local;} /* tlb_finish_mmu *	Called at the end of the shootdown operation to free up any resources *	that were required. */void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end){	struct mmu_gather_batch *batch, *next; 	tlb_flush_mmu(tlb); 	/* keep the page table cache within bounds */	check_pgt_cache(); 	for (batch = tlb->local.next; batch; batch = next) {		next = batch->next;		free_pages((unsigned long)batch, 0);	}	tlb->local.next = NULL;} /* __tlb_remove_page *	Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while *	handling the additional races in SMP caused by other CPUs caching valid *	mappings in their TLBs. Returns the number of free page slots left. *	When out of page slots we must call tlb_flush_mmu(). */int __tlb_remove_page(struct mmu_gather *tlb, struct page *page){	struct mmu_gather_batch *batch; 	tlb->need_flush = 1; 	if (tlb_fast_mode(tlb)) {		free_page_and_swap_cache(page);		return 1; /* avoid calling tlb_flush_mmu() */	} 	batch = tlb->active;	batch->pages[batch->nr++] = page;	if (batch->nr == batch->max) {		if (!tlb_next_batch(tlb))			return 0;		batch = tlb->active;	}	VM_BUG_ON(batch->nr > batch->max); 	return batch->max - batch->nr;} #endif /* HAVE_GENERIC_MMU_GATHER */ #ifdef CONFIG_HAVE_RCU_TABLE_FREE /* * See the comment near struct mmu_table_batch. */ static void tlb_remove_table_smp_sync(void *arg){	/* Simply deliver the interrupt */} static void tlb_remove_table_one(void *table){	/*	 * This isn't an RCU grace period and hence the page-tables cannot be	 * assumed to be actually RCU-freed.	 *	 * It is however sufficient for software page-table walkers that rely on	 * IRQ disabling. See the comment near struct mmu_table_batch.	 */	smp_call_function(tlb_remove_table_smp_sync, NULL, 1);	__tlb_remove_table(table);} static void tlb_remove_table_rcu(struct rcu_head *head){	struct mmu_table_batch *batch;	int i; 	batch = container_of(head, struct mmu_table_batch, rcu); 	for (i = 0; i < batch->nr; i++)		__tlb_remove_table(batch->tables[i]); 	free_page((unsigned long)batch);} void tlb_table_flush(struct mmu_gather *tlb){	struct mmu_table_batch **batch = &tlb->batch; 	if (*batch) {		call_rcu_sched(&(*batch)->rcu, tlb_remove_table_rcu);		*batch = NULL;	}} void tlb_remove_table(struct mmu_gather *tlb, void *table){	struct mmu_table_batch **batch = &tlb->batch; 	tlb->need_flush = 1; 	/*	 * When there's less then two users of this mm there cannot be a	 * concurrent page-table walk.	 */	if (atomic_read(&tlb->mm->mm_users) < 2) {		__tlb_remove_table(table);		return;	} 	if (*batch == NULL) {		*batch = (struct mmu_table_batch *)__get_free_page(GFP_NOWAIT | __GFP_NOWARN);		if (*batch == NULL) {			tlb_remove_table_one(table);			return;		}		(*batch)->nr = 0;	}	(*batch)->tables[(*batch)->nr++] = table;	if ((*batch)->nr == MAX_TABLE_BATCH)		tlb_table_flush(tlb);} #endif /* CONFIG_HAVE_RCU_TABLE_FREE */ /* * If a p?d_bad entry is found while walking page tables, report * the error, before resetting entry to p?d_none.  Usually (but * very seldom) called out from the p?d_none_or_clear_bad macros. */ void pgd_clear_bad(pgd_t *pgd){	pgd_ERROR(*pgd);	pgd_clear(pgd);} void pud_clear_bad(pud_t *pud){	pud_ERROR(*pud);	pud_clear(pud);} void pmd_clear_bad(pmd_t *pmd){	pmd_ERROR(*pmd);	pmd_clear(pmd);} /* * Note: this doesn't free the actual pages themselves. That * has been handled earlier when unmapping all the memory regions. */static void free_pte_range(struct mmu_gather *tlb, pmd_t *pmd,			   unsigned long addr){	pgtable_t token = pmd_pgtable(*pmd);	pmd_clear(pmd);	pte_free_tlb(tlb, token, addr);	tlb->mm->nr_ptes--;} static inline void free_pmd_range(struct mmu_gather *tlb, pud_t *pud,				unsigned long addr, unsigned long end,				unsigned long floor, unsigned long ceiling){	pmd_t *pmd;	unsigned long next;	unsigned long start; 	start = addr;	pmd = pmd_offset(pud, addr);	do {		next = pmd_addr_end(addr, end);		if (pmd_none_or_clear_bad(pmd))			continue;		free_pte_range(tlb, pmd, addr);	} while (pmd++, addr = next, addr != end); 	start &= PUD_MASK;	if (start < floor)		return;	if (ceiling) {		ceiling &= PUD_MASK;		if (!ceiling)			return;	}	if (end - 1 > ceiling - 1)		return; 	pmd = pmd_offset(pud, start);	pud_clear(pud);	pmd_free_tlb(tlb, pmd, start);} static inline void free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,				unsigned long addr, unsigned long end,				unsigned long floor, unsigned long ceiling){	pud_t *pud;	unsigned long next;	unsigned long start; 	start = addr;	pud = pud_offset(pgd, addr);	do {		next = pud_addr_end(addr, end);		if (pud_none_or_clear_bad(pud))			continue;		free_pmd_range(tlb, pud, addr, next, floor, ceiling);	} while (pud++, addr = next, addr != end); 	start &= PGDIR_MASK;	if (start < floor)		return;	if (ceiling) {		ceiling &= PGDIR_MASK;		if (!ceiling)			return;	}	if (end - 1 > ceiling - 1)		return; 	pud = pud_offset(pgd, start);	pgd_clear(pgd);	pud_free_tlb(tlb, pud, start);} /* * This function frees user-level page tables of a process. * * Must be called with pagetable lock held.

Lines 1–500 of 3986.