diff options
Diffstat (limited to 'mm')
| -rw-r--r-- | mm/memblock.c | 24 | ||||
| -rw-r--r-- | mm/mmu_notifier.c | 26 | ||||
| -rw-r--r-- | mm/page_alloc.c | 6 | ||||
| -rw-r--r-- | mm/rmap.c | 20 | 
4 files changed, 55 insertions, 21 deletions
diff --git a/mm/memblock.c b/mm/memblock.c index 931eef145af..625905523c2 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -930,6 +930,30 @@ int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t si  	return memblock_overlaps_region(&memblock.reserved, base, size) >= 0;  } +void __init_memblock memblock_trim_memory(phys_addr_t align) +{ +	int i; +	phys_addr_t start, end, orig_start, orig_end; +	struct memblock_type *mem = &memblock.memory; + +	for (i = 0; i < mem->cnt; i++) { +		orig_start = mem->regions[i].base; +		orig_end = mem->regions[i].base + mem->regions[i].size; +		start = round_up(orig_start, align); +		end = round_down(orig_end, align); + +		if (start == orig_start && end == orig_end) +			continue; + +		if (start < end) { +			mem->regions[i].base = start; +			mem->regions[i].size = end - start; +		} else { +			memblock_remove_region(mem, i); +			i--; +		} +	} +}  void __init_memblock memblock_set_current_limit(phys_addr_t limit)  { diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c index 479a1e751a7..8a5ac8c686b 100644 --- a/mm/mmu_notifier.c +++ b/mm/mmu_notifier.c @@ -196,28 +196,28 @@ static int do_mmu_notifier_register(struct mmu_notifier *mn,  	BUG_ON(atomic_read(&mm->mm_users) <= 0);  	/* -	* Verify that mmu_notifier_init() already run and the global srcu is -	* initialized. -	*/ +	 * Verify that mmu_notifier_init() already run and the global srcu is +	 * initialized. +	 */  	BUG_ON(!srcu.per_cpu_ref); +	ret = -ENOMEM; +	mmu_notifier_mm = kmalloc(sizeof(struct mmu_notifier_mm), GFP_KERNEL); +	if (unlikely(!mmu_notifier_mm)) +		goto out; +  	if (take_mmap_sem)  		down_write(&mm->mmap_sem);  	ret = mm_take_all_locks(mm);  	if (unlikely(ret)) -		goto out; +		goto out_clean;  	if (!mm_has_notifiers(mm)) { -		mmu_notifier_mm = kmalloc(sizeof(struct mmu_notifier_mm), -					GFP_KERNEL); -		if (unlikely(!mmu_notifier_mm)) { -			ret = -ENOMEM; -			goto out_of_mem; -		}  		INIT_HLIST_HEAD(&mmu_notifier_mm->list);  		spin_lock_init(&mmu_notifier_mm->lock);  		mm->mmu_notifier_mm = mmu_notifier_mm; +		mmu_notifier_mm = NULL;  	}  	atomic_inc(&mm->mm_count); @@ -233,12 +233,12 @@ static int do_mmu_notifier_register(struct mmu_notifier *mn,  	hlist_add_head(&mn->hlist, &mm->mmu_notifier_mm->list);  	spin_unlock(&mm->mmu_notifier_mm->lock); -out_of_mem:  	mm_drop_all_locks(mm); -out: +out_clean:  	if (take_mmap_sem)  		up_write(&mm->mmap_sem); - +	kfree(mmu_notifier_mm); +out:  	BUG_ON(atomic_read(&mm->mm_users) <= 0);  	return ret;  } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index bb90971182b..5b74de6702e 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1809,10 +1809,10 @@ static void __paginginit init_zone_allows_reclaim(int nid)  	int i;  	for_each_online_node(i) -		if (node_distance(nid, i) <= RECLAIM_DISTANCE) { +		if (node_distance(nid, i) <= RECLAIM_DISTANCE)  			node_set(i, NODE_DATA(nid)->reclaim_nodes); +		else  			zone_reclaim_mode = 1; -		}  }  #else	/* CONFIG_NUMA */ @@ -5825,7 +5825,7 @@ int alloc_contig_range(unsigned long start, unsigned long end,  	ret = start_isolate_page_range(pfn_max_align_down(start),  				       pfn_max_align_up(end), migratetype);  	if (ret) -		goto done; +		return ret;  	ret = __alloc_contig_migrate_range(&cc, start, end);  	if (ret) diff --git a/mm/rmap.c b/mm/rmap.c index 7df7984d476..2ee1ef0f317 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -56,6 +56,7 @@  #include <linux/mmu_notifier.h>  #include <linux/migrate.h>  #include <linux/hugetlb.h> +#include <linux/backing-dev.h>  #include <asm/tlbflush.h> @@ -926,11 +927,8 @@ int page_mkclean(struct page *page)  	if (page_mapped(page)) {  		struct address_space *mapping = page_mapping(page); -		if (mapping) { +		if (mapping)  			ret = page_mkclean_file(mapping, page); -			if (page_test_and_clear_dirty(page_to_pfn(page), 1)) -				ret = 1; -		}  	}  	return ret; @@ -1116,6 +1114,7 @@ void page_add_file_rmap(struct page *page)   */  void page_remove_rmap(struct page *page)  { +	struct address_space *mapping = page_mapping(page);  	bool anon = PageAnon(page);  	bool locked;  	unsigned long flags; @@ -1138,8 +1137,19 @@ void page_remove_rmap(struct page *page)  	 * this if the page is anon, so about to be freed; but perhaps  	 * not if it's in swapcache - there might be another pte slot  	 * containing the swap entry, but page not yet written to swap. +	 * +	 * And we can skip it on file pages, so long as the filesystem +	 * participates in dirty tracking; but need to catch shm and tmpfs +	 * and ramfs pages which have been modified since creation by read +	 * fault. +	 * +	 * Note that mapping must be decided above, before decrementing +	 * mapcount (which luckily provides a barrier): once page is unmapped, +	 * it could be truncated and page->mapping reset to NULL at any moment. +	 * Note also that we are relying on page_mapping(page) to set mapping +	 * to &swapper_space when PageSwapCache(page).  	 */ -	if ((!anon || PageSwapCache(page)) && +	if (mapping && !mapping_cap_account_dirty(mapping) &&  	    page_test_and_clear_dirty(page_to_pfn(page), 1))  		set_page_dirty(page);  	/*  |