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:
commit
998d75510e
|
@ -540,6 +540,9 @@ static ssize_t soft_offline_page_store(struct device *dev,
|
|||
pfn >>= PAGE_SHIFT;
|
||||
if (!pfn_valid(pfn))
|
||||
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);
|
||||
return ret == 0 ? count : ret;
|
||||
}
|
||||
|
|
|
@ -413,13 +413,14 @@ static void reset_bdev(struct zram *zram)
|
|||
static ssize_t backing_dev_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct file *file;
|
||||
struct zram *zram = dev_to_zram(dev);
|
||||
struct file *file = zram->backing_dev;
|
||||
char *p;
|
||||
ssize_t ret;
|
||||
|
||||
down_read(&zram->init_lock);
|
||||
if (!zram->backing_dev) {
|
||||
file = zram->backing_dev;
|
||||
if (!file) {
|
||||
memcpy(buf, "none\n", 5);
|
||||
up_read(&zram->init_lock);
|
||||
return 5;
|
||||
|
|
|
@ -1230,6 +1230,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(attr->ia_uid));
|
||||
if (IS_ERR(transfer_to[USRQUOTA])) {
|
||||
status = PTR_ERR(transfer_to[USRQUOTA]);
|
||||
transfer_to[USRQUOTA] = NULL;
|
||||
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));
|
||||
if (IS_ERR(transfer_to[GRPQUOTA])) {
|
||||
status = PTR_ERR(transfer_to[GRPQUOTA]);
|
||||
transfer_to[GRPQUOTA] = NULL;
|
||||
goto bail_unlock;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -217,7 +217,8 @@ void ocfs2_recovery_exit(struct ocfs2_super *osb)
|
|||
/* At this point, we know that no more recovery threads can be
|
||||
* launched, so wait for any recovery completion work to
|
||||
* 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
|
||||
|
|
|
@ -377,7 +377,8 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
|
|||
struct ocfs2_dinode *alloc = NULL;
|
||||
|
||||
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)
|
||||
goto out;
|
||||
|
|
|
@ -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);
|
||||
show_val_kb(m, "ShmemPmdMapped: ",
|
||||
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);
|
||||
show_val_kb(m, "FilePmdMapped: ",
|
||||
show_val_kb(m, "FilePmdMapped: ",
|
||||
global_node_page_state(NR_FILE_PMDMAPPED) * HPAGE_PMD_NR);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -42,10 +42,12 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf,
|
|||
return -EINVAL;
|
||||
|
||||
while (count > 0) {
|
||||
if (pfn_valid(pfn))
|
||||
ppage = pfn_to_page(pfn);
|
||||
else
|
||||
ppage = NULL;
|
||||
/*
|
||||
* TODO: ZONE_DEVICE support requires to identify
|
||||
* memmaps that were actually initialized.
|
||||
*/
|
||||
ppage = pfn_to_online_page(pfn);
|
||||
|
||||
if (!ppage || PageSlab(ppage) || page_has_type(ppage))
|
||||
pcount = 0;
|
||||
else
|
||||
|
@ -216,10 +218,11 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf,
|
|||
return -EINVAL;
|
||||
|
||||
while (count > 0) {
|
||||
if (pfn_valid(pfn))
|
||||
ppage = pfn_to_page(pfn);
|
||||
else
|
||||
ppage = NULL;
|
||||
/*
|
||||
* TODO: ZONE_DEVICE support requires to identify
|
||||
* memmaps that were actually initialized.
|
||||
*/
|
||||
ppage = pfn_to_online_page(pfn);
|
||||
|
||||
if (put_user(stable_page_flags(ppage), out)) {
|
||||
ret = -EFAULT;
|
||||
|
@ -261,10 +264,11 @@ static ssize_t kpagecgroup_read(struct file *file, char __user *buf,
|
|||
return -EINVAL;
|
||||
|
||||
while (count > 0) {
|
||||
if (pfn_valid(pfn))
|
||||
ppage = pfn_to_page(pfn);
|
||||
else
|
||||
ppage = NULL;
|
||||
/*
|
||||
* TODO: ZONE_DEVICE support requires to identify
|
||||
* memmaps that were actually initialized.
|
||||
*/
|
||||
ppage = pfn_to_online_page(pfn);
|
||||
|
||||
if (ppage)
|
||||
ino = page_cgroup_ino(ppage);
|
||||
|
|
|
@ -474,14 +474,17 @@ int uprobe_write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
|
|||
struct vm_area_struct *vma;
|
||||
int ret, is_register, ref_ctr_updated = 0;
|
||||
bool orig_page_huge = false;
|
||||
unsigned int gup_flags = FOLL_FORCE;
|
||||
|
||||
is_register = is_swbp_insn(&opcode);
|
||||
uprobe = container_of(auprobe, struct uprobe, arch);
|
||||
|
||||
retry:
|
||||
if (is_register)
|
||||
gup_flags |= FOLL_SPLIT_PMD;
|
||||
/* Read the page with vaddr into memory */
|
||||
ret = get_user_pages_remote(NULL, mm, vaddr, 1,
|
||||
FOLL_FORCE | FOLL_SPLIT_PMD, &old_page, &vma, NULL);
|
||||
ret = get_user_pages_remote(NULL, mm, vaddr, 1, gup_flags,
|
||||
&old_page, &vma, NULL);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
|
@ -489,6 +492,12 @@ retry:
|
|||
if (ret <= 0)
|
||||
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. */
|
||||
if (!ref_ctr_updated && uprobe->ref_ctr_offset) {
|
||||
ret = update_ref_ctr(uprobe, mm, is_register ? 1 : -1);
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <linux/rmap.h>
|
||||
#include <linux/delayacct.h>
|
||||
#include <linux/psi.h>
|
||||
#include <linux/ramfs.h>
|
||||
#include "internal.h"
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
|
|
14
mm/gup.c
14
mm/gup.c
|
@ -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,
|
||||
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;
|
||||
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);
|
||||
|
||||
if (!pte_access_permitted(pte, write))
|
||||
if (!pte_access_permitted(pte, flags & FOLL_WRITE))
|
||||
return 0;
|
||||
|
||||
/* 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,
|
||||
unsigned int pdshift, unsigned long end, int write,
|
||||
unsigned int pdshift, unsigned long end, unsigned int flags,
|
||||
struct page **pages, int *nr)
|
||||
{
|
||||
pte_t *ptep;
|
||||
|
@ -2033,7 +2034,7 @@ static int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
|
|||
ptep = hugepte_offset(hugepd, addr, pdshift);
|
||||
do {
|
||||
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;
|
||||
} while (ptep++, addr = next, addr != end);
|
||||
|
||||
|
@ -2041,7 +2042,7 @@ static int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
|
|||
}
|
||||
#else
|
||||
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)
|
||||
{
|
||||
return 0;
|
||||
|
@ -2049,7 +2050,8 @@ static inline int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
|
|||
#endif /* CONFIG_ARCH_HAS_HUGEPD */
|
||||
|
||||
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;
|
||||
int refs;
|
||||
|
|
|
@ -2789,8 +2789,13 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
|
|||
ds_queue->split_queue_len--;
|
||||
list_del(page_deferred_list(head));
|
||||
}
|
||||
if (mapping)
|
||||
__dec_node_page_state(page, NR_SHMEM_THPS);
|
||||
if (mapping) {
|
||||
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);
|
||||
__split_huge_page(page, list, end, flags);
|
||||
if (PageSwapCache(head)) {
|
||||
|
|
|
@ -1084,11 +1084,10 @@ static bool pfn_range_valid_gigantic(struct zone *z,
|
|||
struct page *page;
|
||||
|
||||
for (i = start_pfn; i < end_pfn; i++) {
|
||||
if (!pfn_valid(i))
|
||||
page = pfn_to_online_page(i);
|
||||
if (!page)
|
||||
return false;
|
||||
|
||||
page = pfn_to_page(i);
|
||||
|
||||
if (page_zone(page) != z)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/mman.h>
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/user_namespace.h>
|
||||
|
|
|
@ -1356,9 +1356,6 @@ static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size,
|
|||
align = SMP_CACHE_BYTES;
|
||||
}
|
||||
|
||||
if (end > memblock.current_limit)
|
||||
end = memblock.current_limit;
|
||||
|
||||
again:
|
||||
found = memblock_find_in_range_node(size, align, start, end, nid,
|
||||
flags);
|
||||
|
@ -1469,6 +1466,9 @@ static void * __init memblock_alloc_internal(
|
|||
if (WARN_ON_ONCE(slab_is_available()))
|
||||
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);
|
||||
|
||||
/* retry allocation without lower limit */
|
||||
|
|
|
@ -5420,6 +5420,8 @@ static int mem_cgroup_move_account(struct page *page,
|
|||
struct mem_cgroup *from,
|
||||
struct mem_cgroup *to)
|
||||
{
|
||||
struct lruvec *from_vec, *to_vec;
|
||||
struct pglist_data *pgdat;
|
||||
unsigned long flags;
|
||||
unsigned int nr_pages = compound ? hpage_nr_pages(page) : 1;
|
||||
int ret;
|
||||
|
@ -5443,11 +5445,15 @@ static int mem_cgroup_move_account(struct page *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);
|
||||
|
||||
if (!anon && page_mapped(page)) {
|
||||
__mod_memcg_state(from, NR_FILE_MAPPED, -nr_pages);
|
||||
__mod_memcg_state(to, NR_FILE_MAPPED, nr_pages);
|
||||
__mod_lruvec_state(from_vec, 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);
|
||||
|
||||
if (mapping_cap_account_dirty(mapping)) {
|
||||
__mod_memcg_state(from, NR_FILE_DIRTY, -nr_pages);
|
||||
__mod_memcg_state(to, NR_FILE_DIRTY, nr_pages);
|
||||
__mod_lruvec_state(from_vec, NR_FILE_DIRTY, -nr_pages);
|
||||
__mod_lruvec_state(to_vec, NR_FILE_DIRTY, nr_pages);
|
||||
}
|
||||
}
|
||||
|
||||
if (PageWriteback(page)) {
|
||||
__mod_memcg_state(from, NR_WRITEBACK, -nr_pages);
|
||||
__mod_memcg_state(to, NR_WRITEBACK, nr_pages);
|
||||
__mod_lruvec_state(from_vec, NR_WRITEBACK, -nr_pages);
|
||||
__mod_lruvec_state(to_vec, NR_WRITEBACK, nr_pages);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
|
|
|
@ -1257,17 +1257,19 @@ int memory_failure(unsigned long pfn, int flags)
|
|||
if (!sysctl_memory_failure_recovery)
|
||||
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",
|
||||
pfn);
|
||||
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))
|
||||
return memory_failure_hugetlb(pfn, flags);
|
||||
if (TestSetPageHWPoison(p)) {
|
||||
|
|
|
@ -436,67 +436,25 @@ static void shrink_zone_span(struct zone *zone, unsigned long start_pfn,
|
|||
zone_span_writeunlock(zone);
|
||||
}
|
||||
|
||||
static void shrink_pgdat_span(struct pglist_data *pgdat,
|
||||
unsigned long start_pfn, unsigned long end_pfn)
|
||||
static void update_pgdat_span(struct pglist_data *pgdat)
|
||||
{
|
||||
unsigned long pgdat_start_pfn = pgdat->node_start_pfn;
|
||||
unsigned long p = pgdat_end_pfn(pgdat); /* pgdat_end_pfn namespace clash */
|
||||
unsigned long pgdat_end_pfn = p;
|
||||
unsigned long pfn;
|
||||
int nid = pgdat->node_id;
|
||||
unsigned long node_start_pfn = 0, node_end_pfn = 0;
|
||||
struct zone *zone;
|
||||
|
||||
if (pgdat_start_pfn == start_pfn) {
|
||||
/*
|
||||
* If the section is smallest section in the pgdat, it need
|
||||
* shrink pgdat->node_start_pfn and pgdat->node_spanned_pages.
|
||||
* In this case, we find second smallest valid mem_section
|
||||
* for shrinking zone.
|
||||
*/
|
||||
pfn = find_smallest_section_pfn(nid, NULL, end_pfn,
|
||||
pgdat_end_pfn);
|
||||
if (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;
|
||||
for (zone = pgdat->node_zones;
|
||||
zone < pgdat->node_zones + MAX_NR_ZONES; zone++) {
|
||||
unsigned long zone_end_pfn = zone->zone_start_pfn +
|
||||
zone->spanned_pages;
|
||||
|
||||
/* No need to lock the zones, they can't change. */
|
||||
if (zone_end_pfn > node_end_pfn)
|
||||
node_end_pfn = zone_end_pfn;
|
||||
if (zone->zone_start_pfn < node_start_pfn)
|
||||
node_start_pfn = zone->zone_start_pfn;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the section is not biggest or smallest mem_section in the pgdat,
|
||||
* 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;
|
||||
pgdat->node_start_pfn = node_start_pfn;
|
||||
pgdat->node_spanned_pages = node_end_pfn - node_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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ static void dev_pagemap_cleanup(struct dev_pagemap *pgmap)
|
|||
void memunmap_pages(struct dev_pagemap *pgmap)
|
||||
{
|
||||
struct resource *res = &pgmap->res;
|
||||
struct page *first_page;
|
||||
unsigned long pfn;
|
||||
int nid;
|
||||
|
||||
|
@ -111,14 +112,16 @@ void memunmap_pages(struct dev_pagemap *pgmap)
|
|||
put_page(pfn_to_page(pfn));
|
||||
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 */
|
||||
nid = page_to_nid(pfn_to_page(PHYS_PFN(res->start)));
|
||||
nid = page_to_nid(first_page);
|
||||
|
||||
mem_hotplug_begin();
|
||||
if (pgmap->type == MEMORY_DEVICE_PRIVATE) {
|
||||
pfn = PHYS_PFN(res->start);
|
||||
__remove_pages(page_zone(pfn_to_page(pfn)), pfn,
|
||||
PHYS_PFN(resource_size(res)), NULL);
|
||||
__remove_pages(page_zone(first_page), PHYS_PFN(res->start),
|
||||
PHYS_PFN(resource_size(res)), NULL);
|
||||
} else {
|
||||
arch_remove_memory(nid, res->start, resource_size(res),
|
||||
pgmap_altmap(pgmap));
|
||||
|
|
|
@ -271,7 +271,8 @@ void pagetypeinfo_showmixedcount_print(struct seq_file *m,
|
|||
* not matter as the mixed block count will still be correct
|
||||
*/
|
||||
for (; pfn < end_pfn; ) {
|
||||
if (!pfn_valid(pfn)) {
|
||||
page = pfn_to_online_page(pfn);
|
||||
if (!page) {
|
||||
pfn = ALIGN(pfn + 1, MAX_ORDER_NR_PAGES);
|
||||
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 = min(block_end_pfn, end_pfn);
|
||||
|
||||
page = pfn_to_page(pfn);
|
||||
pageblock_mt = get_pageblock_migratetype(page);
|
||||
|
||||
for (; pfn < block_end_pfn; pfn++) {
|
||||
if (!pfn_valid_within(pfn))
|
||||
continue;
|
||||
|
||||
/* The pageblock is online, no need to recheck. */
|
||||
page = pfn_to_page(pfn);
|
||||
|
||||
if (page_zone(page) != zone)
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include <linux/mmu_notifier.h>
|
||||
#include <linux/migrate.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/huge_mm.h>
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/page_idle.h>
|
||||
#include <linux/memremap.h>
|
||||
|
|
|
@ -178,10 +178,13 @@ static int init_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));
|
||||
else
|
||||
} else {
|
||||
mem_cgroup_put(s->memcg_params.memcg);
|
||||
WRITE_ONCE(s->memcg_params.memcg, NULL);
|
||||
percpu_ref_exit(&s->memcg_params.refcnt);
|
||||
}
|
||||
}
|
||||
|
||||
static void free_memcg_params(struct rcu_head *rcu)
|
||||
|
@ -253,8 +256,6 @@ static void memcg_unlink_cache(struct kmem_cache *s)
|
|||
} else {
|
||||
list_del(&s->memcg_params.children_node);
|
||||
list_del(&s->memcg_params.kmem_caches_node);
|
||||
mem_cgroup_put(s->memcg_params.memcg);
|
||||
WRITE_ONCE(s->memcg_params.memcg, NULL);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
|
|
@ -592,6 +592,16 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
|
|||
unlock_page(page);
|
||||
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);
|
||||
|
@ -602,6 +612,8 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
|
|||
*/
|
||||
if (!ret)
|
||||
deactivate_file_page(page);
|
||||
if (PageTransHuge(page))
|
||||
put_page(page);
|
||||
count += ret;
|
||||
}
|
||||
pagevec_remove_exceptionals(&pvec);
|
||||
|
|
14
mm/vmscan.c
14
mm/vmscan.c
|
@ -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 lru_size;
|
||||
unsigned long lru_size = 0;
|
||||
int zid;
|
||||
|
||||
if (!mem_cgroup_disabled())
|
||||
lru_size = lruvec_page_state_local(lruvec, NR_LRU_BASE + lru);
|
||||
else
|
||||
if (!mem_cgroup_disabled()) {
|
||||
for (zid = 0; zid < MAX_NR_ZONES; zid++)
|
||||
lru_size += mem_cgroup_get_zone_lru_size(lruvec, lru, zid);
|
||||
} else
|
||||
lru_size = node_page_state(lruvec_pgdat(lruvec), NR_LRU_BASE + lru);
|
||||
|
||||
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,
|
||||
* and thus under the i_pages lock, then this ordering is not required.
|
||||
*/
|
||||
if (unlikely(PageTransHuge(page)) && PageSwapCache(page))
|
||||
refcount = 1 + HPAGE_PMD_NR;
|
||||
else
|
||||
refcount = 2;
|
||||
refcount = 1 + compound_nr(page);
|
||||
if (!page_ref_freeze(page, refcount))
|
||||
goto cannot_free;
|
||||
/* note: atomic_cmpxchg in page_ref_freeze provides the smp_rmb */
|
||||
|
|
|
@ -16,6 +16,8 @@ import sys
|
|||
|
||||
from linux import utils
|
||||
|
||||
printk_log_type = utils.CachedType("struct printk_log")
|
||||
|
||||
|
||||
class LxDmesg(gdb.Command):
|
||||
"""Print Linux kernel log buffer."""
|
||||
|
@ -42,9 +44,14 @@ class LxDmesg(gdb.Command):
|
|||
b = utils.read_memoryview(inf, log_buf_addr, log_next_idx)
|
||||
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
|
||||
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 log_buf_2nd_half == -1:
|
||||
gdb.write("Corrupted log buffer!\n")
|
||||
|
@ -52,10 +59,11 @@ class LxDmesg(gdb.Command):
|
|||
pos = log_buf_2nd_half
|
||||
continue
|
||||
|
||||
text_len = utils.read_u16(log_buf[pos + 10:pos + 12])
|
||||
text = log_buf[pos + 16:pos + 16 + text_len].decode(
|
||||
text_len = utils.read_u16(log_buf, pos + text_len_offset)
|
||||
text_start = pos + text_offset
|
||||
text = log_buf[text_start:text_start + text_len].decode(
|
||||
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():
|
||||
msg = u"[{time:12.6f}] {line}\n".format(
|
||||
|
|
|
@ -15,7 +15,7 @@ import gdb
|
|||
import os
|
||||
import re
|
||||
|
||||
from linux import modules
|
||||
from linux import modules, utils
|
||||
|
||||
|
||||
if hasattr(gdb, 'Breakpoint'):
|
||||
|
@ -116,6 +116,12 @@ lx-symbols command."""
|
|||
module_file = self._get_module_file(module_name)
|
||||
|
||||
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(
|
||||
addr=module_addr, filename=module_file))
|
||||
cmdline = "add-symbol-file {filename} {addr}{sections}".format(
|
||||
|
|
|
@ -92,15 +92,16 @@ def read_memoryview(inf, 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]
|
||||
|
||||
if type(buffer[0]) is str:
|
||||
value[0] = ord(buffer[0])
|
||||
value[1] = ord(buffer[1])
|
||||
if type(buffer_val[0]) is str:
|
||||
value[0] = ord(buffer_val[0])
|
||||
value[1] = ord(buffer_val[1])
|
||||
else:
|
||||
value[0] = buffer[0]
|
||||
value[1] = buffer[1]
|
||||
value[0] = buffer_val[0]
|
||||
value[1] = buffer_val[1]
|
||||
|
||||
if get_target_endianness() == LITTLE_ENDIAN:
|
||||
return value[0] + (value[1] << 8)
|
||||
|
@ -108,18 +109,18 @@ def read_u16(buffer):
|
|||
return value[1] + (value[0] << 8)
|
||||
|
||||
|
||||
def read_u32(buffer):
|
||||
def read_u32(buffer, offset):
|
||||
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:
|
||||
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:
|
||||
return read_u32(buffer[0:4]) + (read_u32(buffer[4:8]) << 32)
|
||||
return read_u32(buffer, offset) + (read_u32(buffer, offset + 4) << 32)
|
||||
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
|
||||
|
|
|
@ -37,7 +37,7 @@ int main(int argc, char **argv)
|
|||
char *file = "/dev/zero";
|
||||
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) {
|
||||
case 'm':
|
||||
size = atoi(optarg) * MB;
|
||||
|
|
Loading…
Reference in New Issue