Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6aab341e authored by Linus Torvalds's avatar Linus Torvalds
Browse files

mm: re-architect the VM_UNPAGED logic



This replaces the (in my opinion horrible) VM_UNMAPPED logic with very
explicit support for a "remapped page range" aka VM_PFNMAP.  It allows a
VM area to contain an arbitrary range of page table entries that the VM
never touches, and never considers to be normal pages.

Any user of "remap_pfn_range()" automatically gets this new
functionality, and doesn't even have to mark the pages reserved or
indeed mark them any other way.  It just works.  As a side effect, doing
mmap() on /dev/mem works for arbitrary ranges.

Sparc update from David in the next commit.

Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 458af543
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -145,8 +145,7 @@ static void dump_vdso_pages(struct vm_area_struct * vma)
			struct page *pg = virt_to_page(vdso32_kbase +
						       i*PAGE_SIZE);
			struct page *upg = (vma && vma->vm_mm) ?
				follow_page(vma->vm_mm, vma->vm_start +
					    i*PAGE_SIZE, 0)
				follow_page(vma, vma->vm_start + i*PAGE_SIZE, 0)
				: NULL;
			dump_one_vdso_page(pg, upg);
		}
@@ -157,8 +156,7 @@ static void dump_vdso_pages(struct vm_area_struct * vma)
			struct page *pg = virt_to_page(vdso64_kbase +
						       i*PAGE_SIZE);
			struct page *upg = (vma && vma->vm_mm) ?
				follow_page(vma->vm_mm, vma->vm_start +
					    i*PAGE_SIZE, 0)
				follow_page(vma, vma->vm_start + i*PAGE_SIZE, 0)
				: NULL;
			dump_one_vdso_page(pg, upg);
		}
+1 −1
Original line number Diff line number Diff line
@@ -591,7 +591,7 @@ static inline size_t read_zero_pagealigned(char __user * buf, size_t size)

		if (vma->vm_start > addr || (vma->vm_flags & VM_WRITE) == 0)
			goto out_up;
		if (vma->vm_flags & (VM_SHARED | VM_HUGETLB | VM_UNPAGED))
		if (vma->vm_flags & (VM_SHARED | VM_HUGETLB))
			break;
		count = vma->vm_end - addr;
		if (count > size)
+3 −4
Original line number Diff line number Diff line
@@ -402,12 +402,11 @@ struct numa_maps {
/*
 * Calculate numa node maps for a vma
 */
static struct numa_maps *get_numa_maps(const struct vm_area_struct *vma)
static struct numa_maps *get_numa_maps(struct vm_area_struct *vma)
{
	int i;
	struct page *page;
	unsigned long vaddr;
	struct mm_struct *mm = vma->vm_mm;
	int i;
	struct numa_maps *md = kmalloc(sizeof(struct numa_maps), GFP_KERNEL);

	if (!md)
@@ -420,7 +419,7 @@ static struct numa_maps *get_numa_maps(const struct vm_area_struct *vma)
		md->node[i] =0;

 	for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr += PAGE_SIZE) {
		page = follow_page(mm, vaddr, 0);
		page = follow_page(vma, vaddr, 0);
		if (page) {
			int count = page_mapcount(page);

+3 −2
Original line number Diff line number Diff line
@@ -145,7 +145,7 @@ extern unsigned int kobjsize(const void *objp);
#define VM_GROWSDOWN	0x00000100	/* general info on the segment */
#define VM_GROWSUP	0x00000200
#define VM_SHM		0x00000000	/* Means nothing: delete it later */
#define VM_UNPAGED	0x00000400	/* Pages managed without map count */
#define VM_PFNMAP	0x00000400	/* Page-ranges managed without "struct page", just pure PFN */
#define VM_DENYWRITE	0x00000800	/* ETXTBSY on write attempts.. */

#define VM_EXECUTABLE	0x00001000
@@ -664,6 +664,7 @@ struct zap_details {
	unsigned long truncate_count;		/* Compare vm_truncate_count */
};

struct page *vm_normal_page(struct vm_area_struct *, unsigned long, pte_t);
unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
		unsigned long size, struct zap_details *);
unsigned long unmap_vmas(struct mmu_gather **tlb,
@@ -953,7 +954,7 @@ unsigned long vmalloc_to_pfn(void *addr);
int remap_pfn_range(struct vm_area_struct *, unsigned long addr,
			unsigned long pfn, unsigned long size, pgprot_t);

struct page *follow_page(struct mm_struct *, unsigned long address,
struct page *follow_page(struct vm_area_struct *, unsigned long address,
			unsigned int foll_flags);
#define FOLL_WRITE	0x01	/* check pte is writable */
#define FOLL_TOUCH	0x02	/* mark page accessed */
+7 −15
Original line number Diff line number Diff line
@@ -27,24 +27,20 @@ static int zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
	struct page *page = NULL;

	if (pte_present(pte)) {
		unsigned long pfn = pte_pfn(pte);
		flush_cache_page(vma, addr, pfn);
		flush_cache_page(vma, addr, pte_pfn(pte));
		pte = ptep_clear_flush(vma, addr, ptep);
		if (unlikely(!pfn_valid(pfn))) {
			print_bad_pte(vma, pte, addr);
			goto out;
		}
		page = pfn_to_page(pfn);
		page = vm_normal_page(vma, addr, pte);
		if (page) {
			if (pte_dirty(pte))
				set_page_dirty(page);
			page_remove_rmap(page);
			page_cache_release(page);
		}
	} else {
		if (!pte_file(pte))
			free_swap_and_cache(pte_to_swp_entry(pte));
		pte_clear(mm, addr, ptep);
	}
out:
	return !!page;
}

@@ -65,8 +61,6 @@ int install_page(struct mm_struct *mm, struct vm_area_struct *vma,
	pte_t pte_val;
	spinlock_t *ptl;

	BUG_ON(vma->vm_flags & VM_UNPAGED);

	pgd = pgd_offset(mm, addr);
	pud = pud_alloc(mm, pgd, addr);
	if (!pud)
@@ -122,8 +116,6 @@ int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma,
	pte_t pte_val;
	spinlock_t *ptl;

	BUG_ON(vma->vm_flags & VM_UNPAGED);

	pgd = pgd_offset(mm, addr);
	pud = pud_alloc(mm, pgd, addr);
	if (!pud)
Loading