Merge branch 'akpm' (patches from Andrew)

Merge misc fixes from Andrew Morton:
 "Rather a lot of fixes, almost all affecting mm/"

* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (26 commits)
  scripts/gdb: fix debugging modules on s390
  kernel/events/uprobes.c: only do FOLL_SPLIT_PMD for uprobe register
  mm/thp: allow dropping THP from page cache
  mm/vmscan.c: support removing arbitrary sized pages from mapping
  mm/thp: fix node page state in split_huge_page_to_list()
  proc/meminfo: fix output alignment
  mm/init-mm.c: include <linux/mman.h> for vm_committed_as_batch
  mm/filemap.c: include <linux/ramfs.h> for generic_file_vm_ops definition
  mm: include <linux/huge_mm.h> for is_vma_temporary_stack
  zram: fix race between backing_dev_show and backing_dev_store
  mm/memcontrol: update lruvec counters in mem_cgroup_move_account
  ocfs2: fix panic due to ocfs2_wq is null
  hugetlbfs: don't access uninitialized memmaps in pfn_range_valid_gigantic()
  mm: memblock: do not enforce current limit for memblock_phys* family
  mm: memcg: get number of pages on the LRU list in memcgroup base on lru_zone_size
  mm/gup: fix a misnamed "write" argument, and a related bug
  mm/gup_benchmark: add a missing "w" to getopt string
  ocfs2: fix error handling in ocfs2_setattr()
  mm: memcg/slab: fix panic in __free_slab() caused by premature memcg pointer release
  mm/memunmap: don't access uninitialized memmap in memunmap_pages()
  ...
This commit is contained in:
Linus Torvalds 2019-10-19 06:53:59 -04:00
commit 998d75510e
27 changed files with 166 additions and 140 deletions

View File

@ -540,6 +540,9 @@ static ssize_t soft_offline_page_store(struct device *dev,
pfn >>= PAGE_SHIFT; pfn >>= PAGE_SHIFT;
if (!pfn_valid(pfn)) if (!pfn_valid(pfn))
return -ENXIO; return -ENXIO;
/* Only online pages can be soft-offlined (esp., not ZONE_DEVICE). */
if (!pfn_to_online_page(pfn))
return -EIO;
ret = soft_offline_page(pfn_to_page(pfn), 0); ret = soft_offline_page(pfn_to_page(pfn), 0);
return ret == 0 ? count : ret; return ret == 0 ? count : ret;
} }

View File

@ -413,13 +413,14 @@ static void reset_bdev(struct zram *zram)
static ssize_t backing_dev_show(struct device *dev, static ssize_t backing_dev_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct file *file;
struct zram *zram = dev_to_zram(dev); struct zram *zram = dev_to_zram(dev);
struct file *file = zram->backing_dev;
char *p; char *p;
ssize_t ret; ssize_t ret;
down_read(&zram->init_lock); down_read(&zram->init_lock);
if (!zram->backing_dev) { file = zram->backing_dev;
if (!file) {
memcpy(buf, "none\n", 5); memcpy(buf, "none\n", 5);
up_read(&zram->init_lock); up_read(&zram->init_lock);
return 5; return 5;

View File

@ -1230,6 +1230,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(attr->ia_uid)); transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(attr->ia_uid));
if (IS_ERR(transfer_to[USRQUOTA])) { if (IS_ERR(transfer_to[USRQUOTA])) {
status = PTR_ERR(transfer_to[USRQUOTA]); status = PTR_ERR(transfer_to[USRQUOTA]);
transfer_to[USRQUOTA] = NULL;
goto bail_unlock; goto bail_unlock;
} }
} }
@ -1239,6 +1240,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(attr->ia_gid)); transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(attr->ia_gid));
if (IS_ERR(transfer_to[GRPQUOTA])) { if (IS_ERR(transfer_to[GRPQUOTA])) {
status = PTR_ERR(transfer_to[GRPQUOTA]); status = PTR_ERR(transfer_to[GRPQUOTA]);
transfer_to[GRPQUOTA] = NULL;
goto bail_unlock; goto bail_unlock;
} }
} }

View File

@ -217,7 +217,8 @@ void ocfs2_recovery_exit(struct ocfs2_super *osb)
/* At this point, we know that no more recovery threads can be /* At this point, we know that no more recovery threads can be
* launched, so wait for any recovery completion work to * launched, so wait for any recovery completion work to
* complete. */ * complete. */
flush_workqueue(osb->ocfs2_wq); if (osb->ocfs2_wq)
flush_workqueue(osb->ocfs2_wq);
/* /*
* Now that recovery is shut down, and the osb is about to be * Now that recovery is shut down, and the osb is about to be

View File

@ -377,7 +377,8 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
struct ocfs2_dinode *alloc = NULL; struct ocfs2_dinode *alloc = NULL;
cancel_delayed_work(&osb->la_enable_wq); cancel_delayed_work(&osb->la_enable_wq);
flush_workqueue(osb->ocfs2_wq); if (osb->ocfs2_wq)
flush_workqueue(osb->ocfs2_wq);
if (osb->local_alloc_state == OCFS2_LA_UNUSED) if (osb->local_alloc_state == OCFS2_LA_UNUSED)
goto out; goto out;

View File

@ -132,9 +132,9 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
global_node_page_state(NR_SHMEM_THPS) * HPAGE_PMD_NR); global_node_page_state(NR_SHMEM_THPS) * HPAGE_PMD_NR);
show_val_kb(m, "ShmemPmdMapped: ", show_val_kb(m, "ShmemPmdMapped: ",
global_node_page_state(NR_SHMEM_PMDMAPPED) * HPAGE_PMD_NR); global_node_page_state(NR_SHMEM_PMDMAPPED) * HPAGE_PMD_NR);
show_val_kb(m, "FileHugePages: ", show_val_kb(m, "FileHugePages: ",
global_node_page_state(NR_FILE_THPS) * HPAGE_PMD_NR); global_node_page_state(NR_FILE_THPS) * HPAGE_PMD_NR);
show_val_kb(m, "FilePmdMapped: ", show_val_kb(m, "FilePmdMapped: ",
global_node_page_state(NR_FILE_PMDMAPPED) * HPAGE_PMD_NR); global_node_page_state(NR_FILE_PMDMAPPED) * HPAGE_PMD_NR);
#endif #endif

View File

@ -42,10 +42,12 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf,
return -EINVAL; return -EINVAL;
while (count > 0) { while (count > 0) {
if (pfn_valid(pfn)) /*
ppage = pfn_to_page(pfn); * TODO: ZONE_DEVICE support requires to identify
else * memmaps that were actually initialized.
ppage = NULL; */
ppage = pfn_to_online_page(pfn);
if (!ppage || PageSlab(ppage) || page_has_type(ppage)) if (!ppage || PageSlab(ppage) || page_has_type(ppage))
pcount = 0; pcount = 0;
else else
@ -216,10 +218,11 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf,
return -EINVAL; return -EINVAL;
while (count > 0) { while (count > 0) {
if (pfn_valid(pfn)) /*
ppage = pfn_to_page(pfn); * TODO: ZONE_DEVICE support requires to identify
else * memmaps that were actually initialized.
ppage = NULL; */
ppage = pfn_to_online_page(pfn);
if (put_user(stable_page_flags(ppage), out)) { if (put_user(stable_page_flags(ppage), out)) {
ret = -EFAULT; ret = -EFAULT;
@ -261,10 +264,11 @@ static ssize_t kpagecgroup_read(struct file *file, char __user *buf,
return -EINVAL; return -EINVAL;
while (count > 0) { while (count > 0) {
if (pfn_valid(pfn)) /*
ppage = pfn_to_page(pfn); * TODO: ZONE_DEVICE support requires to identify
else * memmaps that were actually initialized.
ppage = NULL; */
ppage = pfn_to_online_page(pfn);
if (ppage) if (ppage)
ino = page_cgroup_ino(ppage); ino = page_cgroup_ino(ppage);

View File

@ -474,14 +474,17 @@ int uprobe_write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
struct vm_area_struct *vma; struct vm_area_struct *vma;
int ret, is_register, ref_ctr_updated = 0; int ret, is_register, ref_ctr_updated = 0;
bool orig_page_huge = false; bool orig_page_huge = false;
unsigned int gup_flags = FOLL_FORCE;
is_register = is_swbp_insn(&opcode); is_register = is_swbp_insn(&opcode);
uprobe = container_of(auprobe, struct uprobe, arch); uprobe = container_of(auprobe, struct uprobe, arch);
retry: retry:
if (is_register)
gup_flags |= FOLL_SPLIT_PMD;
/* Read the page with vaddr into memory */ /* Read the page with vaddr into memory */
ret = get_user_pages_remote(NULL, mm, vaddr, 1, ret = get_user_pages_remote(NULL, mm, vaddr, 1, gup_flags,
FOLL_FORCE | FOLL_SPLIT_PMD, &old_page, &vma, NULL); &old_page, &vma, NULL);
if (ret <= 0) if (ret <= 0)
return ret; return ret;
@ -489,6 +492,12 @@ retry:
if (ret <= 0) if (ret <= 0)
goto put_old; goto put_old;
if (WARN(!is_register && PageCompound(old_page),
"uprobe unregister should never work on compound page\n")) {
ret = -EINVAL;
goto put_old;
}
/* We are going to replace instruction, update ref_ctr. */ /* We are going to replace instruction, update ref_ctr. */
if (!ref_ctr_updated && uprobe->ref_ctr_offset) { if (!ref_ctr_updated && uprobe->ref_ctr_offset) {
ret = update_ref_ctr(uprobe, mm, is_register ? 1 : -1); ret = update_ref_ctr(uprobe, mm, is_register ? 1 : -1);

View File

@ -40,6 +40,7 @@
#include <linux/rmap.h> #include <linux/rmap.h>
#include <linux/delayacct.h> #include <linux/delayacct.h>
#include <linux/psi.h> #include <linux/psi.h>
#include <linux/ramfs.h>
#include "internal.h" #include "internal.h"
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS

View File

@ -1973,7 +1973,8 @@ static unsigned long hugepte_addr_end(unsigned long addr, unsigned long end,
} }
static int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr, static int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
unsigned long end, int write, struct page **pages, int *nr) unsigned long end, unsigned int flags,
struct page **pages, int *nr)
{ {
unsigned long pte_end; unsigned long pte_end;
struct page *head, *page; struct page *head, *page;
@ -1986,7 +1987,7 @@ static int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
pte = READ_ONCE(*ptep); pte = READ_ONCE(*ptep);
if (!pte_access_permitted(pte, write)) if (!pte_access_permitted(pte, flags & FOLL_WRITE))
return 0; return 0;
/* hugepages are never "special" */ /* hugepages are never "special" */
@ -2023,7 +2024,7 @@ static int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
} }
static int gup_huge_pd(hugepd_t hugepd, unsigned long addr, static int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
unsigned int pdshift, unsigned long end, int write, unsigned int pdshift, unsigned long end, unsigned int flags,
struct page **pages, int *nr) struct page **pages, int *nr)
{ {
pte_t *ptep; pte_t *ptep;
@ -2033,7 +2034,7 @@ static int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
ptep = hugepte_offset(hugepd, addr, pdshift); ptep = hugepte_offset(hugepd, addr, pdshift);
do { do {
next = hugepte_addr_end(addr, end, sz); next = hugepte_addr_end(addr, end, sz);
if (!gup_hugepte(ptep, sz, addr, end, write, pages, nr)) if (!gup_hugepte(ptep, sz, addr, end, flags, pages, nr))
return 0; return 0;
} while (ptep++, addr = next, addr != end); } while (ptep++, addr = next, addr != end);
@ -2041,7 +2042,7 @@ static int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
} }
#else #else
static inline int gup_huge_pd(hugepd_t hugepd, unsigned long addr, static inline int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
unsigned pdshift, unsigned long end, int write, unsigned int pdshift, unsigned long end, unsigned int flags,
struct page **pages, int *nr) struct page **pages, int *nr)
{ {
return 0; return 0;
@ -2049,7 +2050,8 @@ static inline int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
#endif /* CONFIG_ARCH_HAS_HUGEPD */ #endif /* CONFIG_ARCH_HAS_HUGEPD */
static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr, static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr,
unsigned long end, unsigned int flags, struct page **pages, int *nr) unsigned long end, unsigned int flags,
struct page **pages, int *nr)
{ {
struct page *head, *page; struct page *head, *page;
int refs; int refs;

View File

@ -2789,8 +2789,13 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
ds_queue->split_queue_len--; ds_queue->split_queue_len--;
list_del(page_deferred_list(head)); list_del(page_deferred_list(head));
} }
if (mapping) if (mapping) {
__dec_node_page_state(page, NR_SHMEM_THPS); if (PageSwapBacked(page))
__dec_node_page_state(page, NR_SHMEM_THPS);
else
__dec_node_page_state(page, NR_FILE_THPS);
}
spin_unlock(&ds_queue->split_queue_lock); spin_unlock(&ds_queue->split_queue_lock);
__split_huge_page(page, list, end, flags); __split_huge_page(page, list, end, flags);
if (PageSwapCache(head)) { if (PageSwapCache(head)) {

View File

@ -1084,11 +1084,10 @@ static bool pfn_range_valid_gigantic(struct zone *z,
struct page *page; struct page *page;
for (i = start_pfn; i < end_pfn; i++) { for (i = start_pfn; i < end_pfn; i++) {
if (!pfn_valid(i)) page = pfn_to_online_page(i);
if (!page)
return false; return false;
page = pfn_to_page(i);
if (page_zone(page) != z) if (page_zone(page) != z)
return false; return false;

View File

@ -5,6 +5,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/mman.h>
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/user_namespace.h> #include <linux/user_namespace.h>

View File

@ -1356,9 +1356,6 @@ static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size,
align = SMP_CACHE_BYTES; align = SMP_CACHE_BYTES;
} }
if (end > memblock.current_limit)
end = memblock.current_limit;
again: again:
found = memblock_find_in_range_node(size, align, start, end, nid, found = memblock_find_in_range_node(size, align, start, end, nid,
flags); flags);
@ -1469,6 +1466,9 @@ static void * __init memblock_alloc_internal(
if (WARN_ON_ONCE(slab_is_available())) if (WARN_ON_ONCE(slab_is_available()))
return kzalloc_node(size, GFP_NOWAIT, nid); return kzalloc_node(size, GFP_NOWAIT, nid);
if (max_addr > memblock.current_limit)
max_addr = memblock.current_limit;
alloc = memblock_alloc_range_nid(size, align, min_addr, max_addr, nid); alloc = memblock_alloc_range_nid(size, align, min_addr, max_addr, nid);
/* retry allocation without lower limit */ /* retry allocation without lower limit */

View File

@ -5420,6 +5420,8 @@ static int mem_cgroup_move_account(struct page *page,
struct mem_cgroup *from, struct mem_cgroup *from,
struct mem_cgroup *to) struct mem_cgroup *to)
{ {
struct lruvec *from_vec, *to_vec;
struct pglist_data *pgdat;
unsigned long flags; unsigned long flags;
unsigned int nr_pages = compound ? hpage_nr_pages(page) : 1; unsigned int nr_pages = compound ? hpage_nr_pages(page) : 1;
int ret; int ret;
@ -5443,11 +5445,15 @@ static int mem_cgroup_move_account(struct page *page,
anon = PageAnon(page); anon = PageAnon(page);
pgdat = page_pgdat(page);
from_vec = mem_cgroup_lruvec(pgdat, from);
to_vec = mem_cgroup_lruvec(pgdat, to);
spin_lock_irqsave(&from->move_lock, flags); spin_lock_irqsave(&from->move_lock, flags);
if (!anon && page_mapped(page)) { if (!anon && page_mapped(page)) {
__mod_memcg_state(from, NR_FILE_MAPPED, -nr_pages); __mod_lruvec_state(from_vec, NR_FILE_MAPPED, -nr_pages);
__mod_memcg_state(to, NR_FILE_MAPPED, nr_pages); __mod_lruvec_state(to_vec, NR_FILE_MAPPED, nr_pages);
} }
/* /*
@ -5459,14 +5465,14 @@ static int mem_cgroup_move_account(struct page *page,
struct address_space *mapping = page_mapping(page); struct address_space *mapping = page_mapping(page);
if (mapping_cap_account_dirty(mapping)) { if (mapping_cap_account_dirty(mapping)) {
__mod_memcg_state(from, NR_FILE_DIRTY, -nr_pages); __mod_lruvec_state(from_vec, NR_FILE_DIRTY, -nr_pages);
__mod_memcg_state(to, NR_FILE_DIRTY, nr_pages); __mod_lruvec_state(to_vec, NR_FILE_DIRTY, nr_pages);
} }
} }
if (PageWriteback(page)) { if (PageWriteback(page)) {
__mod_memcg_state(from, NR_WRITEBACK, -nr_pages); __mod_lruvec_state(from_vec, NR_WRITEBACK, -nr_pages);
__mod_memcg_state(to, NR_WRITEBACK, nr_pages); __mod_lruvec_state(to_vec, NR_WRITEBACK, nr_pages);
} }
#ifdef CONFIG_TRANSPARENT_HUGEPAGE #ifdef CONFIG_TRANSPARENT_HUGEPAGE

View File

@ -1257,17 +1257,19 @@ int memory_failure(unsigned long pfn, int flags)
if (!sysctl_memory_failure_recovery) if (!sysctl_memory_failure_recovery)
panic("Memory failure on page %lx", pfn); panic("Memory failure on page %lx", pfn);
if (!pfn_valid(pfn)) { p = pfn_to_online_page(pfn);
if (!p) {
if (pfn_valid(pfn)) {
pgmap = get_dev_pagemap(pfn, NULL);
if (pgmap)
return memory_failure_dev_pagemap(pfn, flags,
pgmap);
}
pr_err("Memory failure: %#lx: memory outside kernel control\n", pr_err("Memory failure: %#lx: memory outside kernel control\n",
pfn); pfn);
return -ENXIO; return -ENXIO;
} }
pgmap = get_dev_pagemap(pfn, NULL);
if (pgmap)
return memory_failure_dev_pagemap(pfn, flags, pgmap);
p = pfn_to_page(pfn);
if (PageHuge(p)) if (PageHuge(p))
return memory_failure_hugetlb(pfn, flags); return memory_failure_hugetlb(pfn, flags);
if (TestSetPageHWPoison(p)) { if (TestSetPageHWPoison(p)) {

View File

@ -436,67 +436,25 @@ static void shrink_zone_span(struct zone *zone, unsigned long start_pfn,
zone_span_writeunlock(zone); zone_span_writeunlock(zone);
} }
static void shrink_pgdat_span(struct pglist_data *pgdat, static void update_pgdat_span(struct pglist_data *pgdat)
unsigned long start_pfn, unsigned long end_pfn)
{ {
unsigned long pgdat_start_pfn = pgdat->node_start_pfn; unsigned long node_start_pfn = 0, node_end_pfn = 0;
unsigned long p = pgdat_end_pfn(pgdat); /* pgdat_end_pfn namespace clash */ struct zone *zone;
unsigned long pgdat_end_pfn = p;
unsigned long pfn;
int nid = pgdat->node_id;
if (pgdat_start_pfn == start_pfn) { for (zone = pgdat->node_zones;
/* zone < pgdat->node_zones + MAX_NR_ZONES; zone++) {
* If the section is smallest section in the pgdat, it need unsigned long zone_end_pfn = zone->zone_start_pfn +
* shrink pgdat->node_start_pfn and pgdat->node_spanned_pages. zone->spanned_pages;
* In this case, we find second smallest valid mem_section
* for shrinking zone. /* No need to lock the zones, they can't change. */
*/ if (zone_end_pfn > node_end_pfn)
pfn = find_smallest_section_pfn(nid, NULL, end_pfn, node_end_pfn = zone_end_pfn;
pgdat_end_pfn); if (zone->zone_start_pfn < node_start_pfn)
if (pfn) { node_start_pfn = zone->zone_start_pfn;
pgdat->node_start_pfn = pfn;
pgdat->node_spanned_pages = pgdat_end_pfn - pfn;
}
} else if (pgdat_end_pfn == end_pfn) {
/*
* If the section is biggest section in the pgdat, it need
* shrink pgdat->node_spanned_pages.
* In this case, we find second biggest valid mem_section for
* shrinking zone.
*/
pfn = find_biggest_section_pfn(nid, NULL, pgdat_start_pfn,
start_pfn);
if (pfn)
pgdat->node_spanned_pages = pfn - pgdat_start_pfn + 1;
} }
/* pgdat->node_start_pfn = node_start_pfn;
* If the section is not biggest or smallest mem_section in the pgdat, pgdat->node_spanned_pages = node_end_pfn - node_start_pfn;
* it only creates a hole in the pgdat. So in this case, we need not
* change the pgdat.
* But perhaps, the pgdat has only hole data. Thus it check the pgdat
* has only hole or not.
*/
pfn = pgdat_start_pfn;
for (; pfn < pgdat_end_pfn; pfn += PAGES_PER_SUBSECTION) {
if (unlikely(!pfn_valid(pfn)))
continue;
if (pfn_to_nid(pfn) != nid)
continue;
/* Skip range to be removed */
if (pfn >= start_pfn && pfn < end_pfn)
continue;
/* If we find valid section, we have nothing to do */
return;
}
/* The pgdat has no valid section */
pgdat->node_start_pfn = 0;
pgdat->node_spanned_pages = 0;
} }
static void __remove_zone(struct zone *zone, unsigned long start_pfn, static void __remove_zone(struct zone *zone, unsigned long start_pfn,
@ -507,7 +465,7 @@ static void __remove_zone(struct zone *zone, unsigned long start_pfn,
pgdat_resize_lock(zone->zone_pgdat, &flags); pgdat_resize_lock(zone->zone_pgdat, &flags);
shrink_zone_span(zone, start_pfn, start_pfn + nr_pages); shrink_zone_span(zone, start_pfn, start_pfn + nr_pages);
shrink_pgdat_span(pgdat, start_pfn, start_pfn + nr_pages); update_pgdat_span(pgdat);
pgdat_resize_unlock(zone->zone_pgdat, &flags); pgdat_resize_unlock(zone->zone_pgdat, &flags);
} }

View File

@ -103,6 +103,7 @@ static void dev_pagemap_cleanup(struct dev_pagemap *pgmap)
void memunmap_pages(struct dev_pagemap *pgmap) void memunmap_pages(struct dev_pagemap *pgmap)
{ {
struct resource *res = &pgmap->res; struct resource *res = &pgmap->res;
struct page *first_page;
unsigned long pfn; unsigned long pfn;
int nid; int nid;
@ -111,14 +112,16 @@ void memunmap_pages(struct dev_pagemap *pgmap)
put_page(pfn_to_page(pfn)); put_page(pfn_to_page(pfn));
dev_pagemap_cleanup(pgmap); dev_pagemap_cleanup(pgmap);
/* make sure to access a memmap that was actually initialized */
first_page = pfn_to_page(pfn_first(pgmap));
/* pages are dead and unused, undo the arch mapping */ /* pages are dead and unused, undo the arch mapping */
nid = page_to_nid(pfn_to_page(PHYS_PFN(res->start))); nid = page_to_nid(first_page);
mem_hotplug_begin(); mem_hotplug_begin();
if (pgmap->type == MEMORY_DEVICE_PRIVATE) { if (pgmap->type == MEMORY_DEVICE_PRIVATE) {
pfn = PHYS_PFN(res->start); __remove_pages(page_zone(first_page), PHYS_PFN(res->start),
__remove_pages(page_zone(pfn_to_page(pfn)), pfn, PHYS_PFN(resource_size(res)), NULL);
PHYS_PFN(resource_size(res)), NULL);
} else { } else {
arch_remove_memory(nid, res->start, resource_size(res), arch_remove_memory(nid, res->start, resource_size(res),
pgmap_altmap(pgmap)); pgmap_altmap(pgmap));

View File

@ -271,7 +271,8 @@ void pagetypeinfo_showmixedcount_print(struct seq_file *m,
* not matter as the mixed block count will still be correct * not matter as the mixed block count will still be correct
*/ */
for (; pfn < end_pfn; ) { for (; pfn < end_pfn; ) {
if (!pfn_valid(pfn)) { page = pfn_to_online_page(pfn);
if (!page) {
pfn = ALIGN(pfn + 1, MAX_ORDER_NR_PAGES); pfn = ALIGN(pfn + 1, MAX_ORDER_NR_PAGES);
continue; continue;
} }
@ -279,13 +280,13 @@ void pagetypeinfo_showmixedcount_print(struct seq_file *m,
block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages); block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
block_end_pfn = min(block_end_pfn, end_pfn); block_end_pfn = min(block_end_pfn, end_pfn);
page = pfn_to_page(pfn);
pageblock_mt = get_pageblock_migratetype(page); pageblock_mt = get_pageblock_migratetype(page);
for (; pfn < block_end_pfn; pfn++) { for (; pfn < block_end_pfn; pfn++) {
if (!pfn_valid_within(pfn)) if (!pfn_valid_within(pfn))
continue; continue;
/* The pageblock is online, no need to recheck. */
page = pfn_to_page(pfn); page = pfn_to_page(pfn);
if (page_zone(page) != zone) if (page_zone(page) != zone)

View File

@ -61,6 +61,7 @@
#include <linux/mmu_notifier.h> #include <linux/mmu_notifier.h>
#include <linux/migrate.h> #include <linux/migrate.h>
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/huge_mm.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/page_idle.h> #include <linux/page_idle.h>
#include <linux/memremap.h> #include <linux/memremap.h>

View File

@ -178,10 +178,13 @@ static int init_memcg_params(struct kmem_cache *s,
static void destroy_memcg_params(struct kmem_cache *s) static void destroy_memcg_params(struct kmem_cache *s)
{ {
if (is_root_cache(s)) if (is_root_cache(s)) {
kvfree(rcu_access_pointer(s->memcg_params.memcg_caches)); kvfree(rcu_access_pointer(s->memcg_params.memcg_caches));
else } else {
mem_cgroup_put(s->memcg_params.memcg);
WRITE_ONCE(s->memcg_params.memcg, NULL);
percpu_ref_exit(&s->memcg_params.refcnt); percpu_ref_exit(&s->memcg_params.refcnt);
}
} }
static void free_memcg_params(struct rcu_head *rcu) static void free_memcg_params(struct rcu_head *rcu)
@ -253,8 +256,6 @@ static void memcg_unlink_cache(struct kmem_cache *s)
} else { } else {
list_del(&s->memcg_params.children_node); list_del(&s->memcg_params.children_node);
list_del(&s->memcg_params.kmem_caches_node); list_del(&s->memcg_params.kmem_caches_node);
mem_cgroup_put(s->memcg_params.memcg);
WRITE_ONCE(s->memcg_params.memcg, NULL);
} }
} }
#else #else

View File

@ -592,6 +592,16 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
unlock_page(page); unlock_page(page);
continue; continue;
} }
/* Take a pin outside pagevec */
get_page(page);
/*
* Drop extra pins before trying to invalidate
* the huge page.
*/
pagevec_remove_exceptionals(&pvec);
pagevec_release(&pvec);
} }
ret = invalidate_inode_page(page); ret = invalidate_inode_page(page);
@ -602,6 +612,8 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
*/ */
if (!ret) if (!ret)
deactivate_file_page(page); deactivate_file_page(page);
if (PageTransHuge(page))
put_page(page);
count += ret; count += ret;
} }
pagevec_remove_exceptionals(&pvec); pagevec_remove_exceptionals(&pvec);

View File

@ -351,12 +351,13 @@ unsigned long zone_reclaimable_pages(struct zone *zone)
*/ */
unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru, int zone_idx) unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru, int zone_idx)
{ {
unsigned long lru_size; unsigned long lru_size = 0;
int zid; int zid;
if (!mem_cgroup_disabled()) if (!mem_cgroup_disabled()) {
lru_size = lruvec_page_state_local(lruvec, NR_LRU_BASE + lru); for (zid = 0; zid < MAX_NR_ZONES; zid++)
else lru_size += mem_cgroup_get_zone_lru_size(lruvec, lru, zid);
} else
lru_size = node_page_state(lruvec_pgdat(lruvec), NR_LRU_BASE + lru); lru_size = node_page_state(lruvec_pgdat(lruvec), NR_LRU_BASE + lru);
for (zid = zone_idx + 1; zid < MAX_NR_ZONES; zid++) { for (zid = zone_idx + 1; zid < MAX_NR_ZONES; zid++) {
@ -932,10 +933,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page,
* Note that if SetPageDirty is always performed via set_page_dirty, * Note that if SetPageDirty is always performed via set_page_dirty,
* and thus under the i_pages lock, then this ordering is not required. * and thus under the i_pages lock, then this ordering is not required.
*/ */
if (unlikely(PageTransHuge(page)) && PageSwapCache(page)) refcount = 1 + compound_nr(page);
refcount = 1 + HPAGE_PMD_NR;
else
refcount = 2;
if (!page_ref_freeze(page, refcount)) if (!page_ref_freeze(page, refcount))
goto cannot_free; goto cannot_free;
/* note: atomic_cmpxchg in page_ref_freeze provides the smp_rmb */ /* note: atomic_cmpxchg in page_ref_freeze provides the smp_rmb */

View File

@ -16,6 +16,8 @@ import sys
from linux import utils from linux import utils
printk_log_type = utils.CachedType("struct printk_log")
class LxDmesg(gdb.Command): class LxDmesg(gdb.Command):
"""Print Linux kernel log buffer.""" """Print Linux kernel log buffer."""
@ -42,9 +44,14 @@ class LxDmesg(gdb.Command):
b = utils.read_memoryview(inf, log_buf_addr, log_next_idx) b = utils.read_memoryview(inf, log_buf_addr, log_next_idx)
log_buf = a.tobytes() + b.tobytes() log_buf = a.tobytes() + b.tobytes()
length_offset = printk_log_type.get_type()['len'].bitpos // 8
text_len_offset = printk_log_type.get_type()['text_len'].bitpos // 8
time_stamp_offset = printk_log_type.get_type()['ts_nsec'].bitpos // 8
text_offset = printk_log_type.get_type().sizeof
pos = 0 pos = 0
while pos < log_buf.__len__(): while pos < log_buf.__len__():
length = utils.read_u16(log_buf[pos + 8:pos + 10]) length = utils.read_u16(log_buf, pos + length_offset)
if length == 0: if length == 0:
if log_buf_2nd_half == -1: if log_buf_2nd_half == -1:
gdb.write("Corrupted log buffer!\n") gdb.write("Corrupted log buffer!\n")
@ -52,10 +59,11 @@ class LxDmesg(gdb.Command):
pos = log_buf_2nd_half pos = log_buf_2nd_half
continue continue
text_len = utils.read_u16(log_buf[pos + 10:pos + 12]) text_len = utils.read_u16(log_buf, pos + text_len_offset)
text = log_buf[pos + 16:pos + 16 + text_len].decode( text_start = pos + text_offset
text = log_buf[text_start:text_start + text_len].decode(
encoding='utf8', errors='replace') encoding='utf8', errors='replace')
time_stamp = utils.read_u64(log_buf[pos:pos + 8]) time_stamp = utils.read_u64(log_buf, pos + time_stamp_offset)
for line in text.splitlines(): for line in text.splitlines():
msg = u"[{time:12.6f}] {line}\n".format( msg = u"[{time:12.6f}] {line}\n".format(

View File

@ -15,7 +15,7 @@ import gdb
import os import os
import re import re
from linux import modules from linux import modules, utils
if hasattr(gdb, 'Breakpoint'): if hasattr(gdb, 'Breakpoint'):
@ -116,6 +116,12 @@ lx-symbols command."""
module_file = self._get_module_file(module_name) module_file = self._get_module_file(module_name)
if module_file: if module_file:
if utils.is_target_arch('s390'):
# Module text is preceded by PLT stubs on s390.
module_arch = module['arch']
plt_offset = int(module_arch['plt_offset'])
plt_size = int(module_arch['plt_size'])
module_addr = hex(int(module_addr, 0) + plt_offset + plt_size)
gdb.write("loading @{addr}: {filename}\n".format( gdb.write("loading @{addr}: {filename}\n".format(
addr=module_addr, filename=module_file)) addr=module_addr, filename=module_file))
cmdline = "add-symbol-file {filename} {addr}{sections}".format( cmdline = "add-symbol-file {filename} {addr}{sections}".format(

View File

@ -92,15 +92,16 @@ def read_memoryview(inf, start, length):
return memoryview(inf.read_memory(start, length)) return memoryview(inf.read_memory(start, length))
def read_u16(buffer): def read_u16(buffer, offset):
buffer_val = buffer[offset:offset + 2]
value = [0, 0] value = [0, 0]
if type(buffer[0]) is str: if type(buffer_val[0]) is str:
value[0] = ord(buffer[0]) value[0] = ord(buffer_val[0])
value[1] = ord(buffer[1]) value[1] = ord(buffer_val[1])
else: else:
value[0] = buffer[0] value[0] = buffer_val[0]
value[1] = buffer[1] value[1] = buffer_val[1]
if get_target_endianness() == LITTLE_ENDIAN: if get_target_endianness() == LITTLE_ENDIAN:
return value[0] + (value[1] << 8) return value[0] + (value[1] << 8)
@ -108,18 +109,18 @@ def read_u16(buffer):
return value[1] + (value[0] << 8) return value[1] + (value[0] << 8)
def read_u32(buffer): def read_u32(buffer, offset):
if get_target_endianness() == LITTLE_ENDIAN: if get_target_endianness() == LITTLE_ENDIAN:
return read_u16(buffer[0:2]) + (read_u16(buffer[2:4]) << 16) return read_u16(buffer, offset) + (read_u16(buffer, offset + 2) << 16)
else: else:
return read_u16(buffer[2:4]) + (read_u16(buffer[0:2]) << 16) return read_u16(buffer, offset + 2) + (read_u16(buffer, offset) << 16)
def read_u64(buffer): def read_u64(buffer, offset):
if get_target_endianness() == LITTLE_ENDIAN: if get_target_endianness() == LITTLE_ENDIAN:
return read_u32(buffer[0:4]) + (read_u32(buffer[4:8]) << 32) return read_u32(buffer, offset) + (read_u32(buffer, offset + 4) << 32)
else: else:
return read_u32(buffer[4:8]) + (read_u32(buffer[0:4]) << 32) return read_u32(buffer, offset + 4) + (read_u32(buffer, offset) << 32)
target_arch = None target_arch = None

View File

@ -37,7 +37,7 @@ int main(int argc, char **argv)
char *file = "/dev/zero"; char *file = "/dev/zero";
char *p; char *p;
while ((opt = getopt(argc, argv, "m:r:n:f:tTLUSH")) != -1) { while ((opt = getopt(argc, argv, "m:r:n:f:tTLUwSH")) != -1) {
switch (opt) { switch (opt) {
case 'm': case 'm':
size = atoi(optarg) * MB; size = atoi(optarg) * MB;