Commit 2b0a9f01 authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by Linus Torvalds

pagemap: introduce pagemap_entry_t without pmshift bits

These bits are always constant (== PAGE_SHIFT) and just occupy space in
the entry.  Moreover, in next patch we will need to report one more bit
in the pagemap, but all bits are already busy on it.

That said, describe the pagemap entry that has 6 more free zero bits.
Signed-off-by: default avatarPavel Emelyanov <xemul@parallels.com>
Cc: Matt Mackall <mpm@selenic.com>
Cc: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com>
Cc: Glauber Costa <glommer@parallels.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent af9de7eb
...@@ -807,6 +807,7 @@ typedef struct { ...@@ -807,6 +807,7 @@ typedef struct {
struct pagemapread { struct pagemapread {
int pos, len; int pos, len;
pagemap_entry_t *buffer; pagemap_entry_t *buffer;
bool v2;
}; };
#define PAGEMAP_WALK_SIZE (PMD_SIZE) #define PAGEMAP_WALK_SIZE (PMD_SIZE)
...@@ -820,14 +821,16 @@ struct pagemapread { ...@@ -820,14 +821,16 @@ struct pagemapread {
#define PM_PSHIFT_BITS 6 #define PM_PSHIFT_BITS 6
#define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS) #define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS)
#define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET) #define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET)
#define PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK) #define __PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK)
#define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1) #define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1)
#define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) #define PM_PFRAME(x) ((x) & PM_PFRAME_MASK)
/* in "new" pagemap pshift bits are occupied with more status bits */
#define PM_STATUS2(v2, x) (__PM_PSHIFT(v2 ? x : PAGE_SHIFT))
#define PM_PRESENT PM_STATUS(4LL) #define PM_PRESENT PM_STATUS(4LL)
#define PM_SWAP PM_STATUS(2LL) #define PM_SWAP PM_STATUS(2LL)
#define PM_FILE PM_STATUS(1LL) #define PM_FILE PM_STATUS(1LL)
#define PM_NOT_PRESENT PM_PSHIFT(PAGE_SHIFT) #define PM_NOT_PRESENT(v2) PM_STATUS2(v2, 0)
#define PM_END_OF_BUFFER 1 #define PM_END_OF_BUFFER 1
static inline pagemap_entry_t make_pme(u64 val) static inline pagemap_entry_t make_pme(u64 val)
...@@ -850,7 +853,7 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end, ...@@ -850,7 +853,7 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end,
struct pagemapread *pm = walk->private; struct pagemapread *pm = walk->private;
unsigned long addr; unsigned long addr;
int err = 0; int err = 0;
pagemap_entry_t pme = make_pme(PM_NOT_PRESENT); pagemap_entry_t pme = make_pme(PM_NOT_PRESENT(pm->v2));
for (addr = start; addr < end; addr += PAGE_SIZE) { for (addr = start; addr < end; addr += PAGE_SIZE) {
err = add_to_pagemap(addr, &pme, pm); err = add_to_pagemap(addr, &pme, pm);
...@@ -860,7 +863,7 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end, ...@@ -860,7 +863,7 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end,
return err; return err;
} }
static void pte_to_pagemap_entry(pagemap_entry_t *pme, static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
struct vm_area_struct *vma, unsigned long addr, pte_t pte) struct vm_area_struct *vma, unsigned long addr, pte_t pte)
{ {
u64 frame, flags; u64 frame, flags;
...@@ -879,18 +882,18 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, ...@@ -879,18 +882,18 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme,
if (is_migration_entry(entry)) if (is_migration_entry(entry))
page = migration_entry_to_page(entry); page = migration_entry_to_page(entry);
} else { } else {
*pme = make_pme(PM_NOT_PRESENT); *pme = make_pme(PM_NOT_PRESENT(pm->v2));
return; return;
} }
if (page && !PageAnon(page)) if (page && !PageAnon(page))
flags |= PM_FILE; flags |= PM_FILE;
*pme = make_pme(PM_PFRAME(frame) | PM_PSHIFT(PAGE_SHIFT) | flags); *pme = make_pme(PM_PFRAME(frame) | PM_STATUS2(pm->v2, 0) | flags);
} }
#ifdef CONFIG_TRANSPARENT_HUGEPAGE #ifdef CONFIG_TRANSPARENT_HUGEPAGE
static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
pmd_t pmd, int offset) pmd_t pmd, int offset)
{ {
/* /*
...@@ -900,12 +903,12 @@ static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, ...@@ -900,12 +903,12 @@ static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme,
*/ */
if (pmd_present(pmd)) if (pmd_present(pmd))
*pme = make_pme(PM_PFRAME(pmd_pfn(pmd) + offset) *pme = make_pme(PM_PFRAME(pmd_pfn(pmd) + offset)
| PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT); | PM_STATUS2(pm->v2, 0) | PM_PRESENT);
else else
*pme = make_pme(PM_NOT_PRESENT); *pme = make_pme(PM_NOT_PRESENT(pm->v2));
} }
#else #else
static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
pmd_t pmd, int offset) pmd_t pmd, int offset)
{ {
} }
...@@ -918,7 +921,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, ...@@ -918,7 +921,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
struct pagemapread *pm = walk->private; struct pagemapread *pm = walk->private;
pte_t *pte; pte_t *pte;
int err = 0; int err = 0;
pagemap_entry_t pme = make_pme(PM_NOT_PRESENT); pagemap_entry_t pme = make_pme(PM_NOT_PRESENT(pm->v2));
/* find the first VMA at or above 'addr' */ /* find the first VMA at or above 'addr' */
vma = find_vma(walk->mm, addr); vma = find_vma(walk->mm, addr);
...@@ -928,7 +931,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, ...@@ -928,7 +931,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
offset = (addr & ~PAGEMAP_WALK_MASK) >> offset = (addr & ~PAGEMAP_WALK_MASK) >>
PAGE_SHIFT; PAGE_SHIFT;
thp_pmd_to_pagemap_entry(&pme, *pmd, offset); thp_pmd_to_pagemap_entry(&pme, pm, *pmd, offset);
err = add_to_pagemap(addr, &pme, pm); err = add_to_pagemap(addr, &pme, pm);
if (err) if (err)
break; break;
...@@ -945,7 +948,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, ...@@ -945,7 +948,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
* and need a new, higher one */ * and need a new, higher one */
if (vma && (addr >= vma->vm_end)) { if (vma && (addr >= vma->vm_end)) {
vma = find_vma(walk->mm, addr); vma = find_vma(walk->mm, addr);
pme = make_pme(PM_NOT_PRESENT); pme = make_pme(PM_NOT_PRESENT(pm->v2));
} }
/* check that 'vma' actually covers this address, /* check that 'vma' actually covers this address,
...@@ -953,7 +956,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, ...@@ -953,7 +956,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
if (vma && (vma->vm_start <= addr) && if (vma && (vma->vm_start <= addr) &&
!is_vm_hugetlb_page(vma)) { !is_vm_hugetlb_page(vma)) {
pte = pte_offset_map(pmd, addr); pte = pte_offset_map(pmd, addr);
pte_to_pagemap_entry(&pme, vma, addr, *pte); pte_to_pagemap_entry(&pme, pm, vma, addr, *pte);
/* unmap before userspace copy */ /* unmap before userspace copy */
pte_unmap(pte); pte_unmap(pte);
} }
...@@ -968,14 +971,14 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, ...@@ -968,14 +971,14 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
} }
#ifdef CONFIG_HUGETLB_PAGE #ifdef CONFIG_HUGETLB_PAGE
static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme, static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
pte_t pte, int offset) pte_t pte, int offset)
{ {
if (pte_present(pte)) if (pte_present(pte))
*pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset) *pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset)
| PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT); | PM_STATUS2(pm->v2, 0) | PM_PRESENT);
else else
*pme = make_pme(PM_NOT_PRESENT); *pme = make_pme(PM_NOT_PRESENT(pm->v2));
} }
/* This function walks within one hugetlb entry in the single call */ /* This function walks within one hugetlb entry in the single call */
...@@ -989,7 +992,7 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask, ...@@ -989,7 +992,7 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask,
for (; addr != end; addr += PAGE_SIZE) { for (; addr != end; addr += PAGE_SIZE) {
int offset = (addr & ~hmask) >> PAGE_SHIFT; int offset = (addr & ~hmask) >> PAGE_SHIFT;
huge_pte_to_pagemap_entry(&pme, *pte, offset); huge_pte_to_pagemap_entry(&pme, pm, *pte, offset);
err = add_to_pagemap(addr, &pme, pm); err = add_to_pagemap(addr, &pme, pm);
if (err) if (err)
return err; return err;
...@@ -1051,6 +1054,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, ...@@ -1051,6 +1054,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
if (!count) if (!count)
goto out_task; goto out_task;
pm.v2 = false;
pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT);
pm.buffer = kmalloc(pm.len, GFP_TEMPORARY); pm.buffer = kmalloc(pm.len, GFP_TEMPORARY);
ret = -ENOMEM; ret = -ENOMEM;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment