Merge branch 'akpm' (patches from Andrew)
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 6 Mar 2019 18:31:36 +0000 (10:31 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 6 Mar 2019 18:31:36 +0000 (10:31 -0800)
Merge misc updates from Andrew Morton:

 - a few misc things

 - ocfs2 updates

 - most of MM

* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (159 commits)
  tools/testing/selftests/proc/proc-self-syscall.c: remove duplicate include
  proc: more robust bulk read test
  proc: test /proc/*/maps, smaps, smaps_rollup, statm
  proc: use seq_puts() everywhere
  proc: read kernel cpu stat pointer once
  proc: remove unused argument in proc_pid_lookup()
  fs/proc/thread_self.c: code cleanup for proc_setup_thread_self()
  fs/proc/self.c: code cleanup for proc_setup_self()
  proc: return exit code 4 for skipped tests
  mm,mremap: bail out earlier in mremap_to under map pressure
  mm/sparse: fix a bad comparison
  mm/memory.c: do_fault: avoid usage of stale vm_area_struct
  writeback: fix inode cgroup switching comment
  mm/huge_memory.c: fix "orig_pud" set but not used
  mm/hotplug: fix an imbalance with DEBUG_PAGEALLOC
  mm/memcontrol.c: fix bad line in comment
  mm/cma.c: cma_declare_contiguous: correct err handling
  mm/page_ext.c: fix an imbalance with kmemleak
  mm/compaction: pass pgdat to too_many_isolated() instead of zone
  mm: remove zone_lru_lock() function, access ->lru_lock directly
  ...

213 files changed:
Documentation/admin-guide/cgroup-v2.rst
Documentation/admin-guide/mm/pagemap.rst
Documentation/cgroup-v1/memcg_test.txt
Documentation/cgroup-v1/memory.txt
MAINTAINERS
arch/alpha/include/asm/topology.h
arch/arm64/Kconfig
arch/arm64/include/asm/hugetlb.h
arch/arm64/include/asm/memory.h
arch/arm64/kernel/machine_kexec.c
arch/arm64/mm/hugetlbpage.c
arch/arm64/mm/init.c
arch/arm64/mm/numa.c
arch/ia64/kernel/numa.c
arch/ia64/kernel/perfmon.c
arch/ia64/mm/discontig.c
arch/m68k/mm/memory.c
arch/powerpc/include/asm/book3s/64/hugetlb.h
arch/powerpc/include/asm/book3s/64/pgtable.h
arch/powerpc/include/asm/book3s/64/radix.h
arch/powerpc/include/asm/pci-bridge.h
arch/powerpc/kernel/paca.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/vdso.c
arch/powerpc/mm/hugetlbpage-hash64.c
arch/powerpc/mm/hugetlbpage-radix.c
arch/powerpc/mm/mmu_context_iommu.c
arch/powerpc/mm/numa.c
arch/powerpc/mm/pgtable-book3s64.c
arch/powerpc/mm/pgtable-radix.c
arch/powerpc/platforms/powernv/memtrace.c
arch/riscv/kernel/vdso.c
arch/s390/include/asm/pgtable.h
arch/s390/kernel/vdso.c
arch/s390/mm/pgtable.c
arch/sh/kernel/syscalls/syscalltbl.sh
arch/sh/kernel/syscalls_32.S
arch/sparc/kernel/pci_fire.c
arch/sparc/kernel/pci_schizo.c
arch/sparc/kernel/psycho_common.c
arch/sparc/kernel/sbus.c
arch/sparc/mm/init_64.c
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/pci.h
arch/x86/include/asm/uaccess.h
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/setup_percpu.c
arch/x86/kernel/smpboot.c
arch/x86/lib/usercopy_32.c
arch/x86/mm/numa.c
arch/x86/xen/mmu.h
arch/x86/xen/mmu_pv.c
drivers/block/mtip32xx/mtip32xx.c
drivers/char/agp/efficeon-agp.c
drivers/dma/dmaengine.c
drivers/gpu/drm/i915/i915_utils.h
drivers/hv/hv_balloon.c
drivers/infiniband/hw/hfi1/affinity.c
drivers/infiniband/hw/hfi1/init.c
drivers/iommu/dmar.c
drivers/iommu/intel-iommu.c
drivers/misc/sgi-xp/xpc_uv.c
drivers/misc/vmw_balloon.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/xen/balloon.c
fs/file.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/kernfs/file.c
fs/ocfs2/alloc.c
fs/ocfs2/cluster/nodemanager.c
fs/ocfs2/dlmglue.c
fs/ocfs2/ocfs2.h
fs/ocfs2/ocfs2_trace.h
fs/ocfs2/slot_map.c
fs/ocfs2/super.c
fs/pipe.c
fs/proc/array.c
fs/proc/base.c
fs/proc/internal.h
fs/proc/page.c
fs/proc/root.c
fs/proc/self.c
fs/proc/stat.c
fs/proc/task_mmu.c
fs/proc/task_nommu.c
fs/proc/thread_self.c
include/asm-generic/pgtable.h
include/linux/backing-dev.h
include/linux/balloon_compaction.h
include/linux/cgroup-defs.h
include/linux/compaction.h
include/linux/device.h
include/linux/frontswap.h
include/linux/fs.h
include/linux/gfp.h
include/linux/hugetlb.h
include/linux/kasan-checks.h
include/linux/kernfs.h
include/linux/ksm.h
include/linux/list.h
include/linux/memcontrol.h
include/linux/memory_hotplug.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmzone.h
include/linux/nodemask.h
include/linux/page-flags.h
include/linux/pagemap.h
include/linux/poison.h
include/linux/sched.h
include/linux/sched/mm.h
include/linux/shmem_fs.h
include/linux/slub_def.h
include/linux/swap.h
include/uapi/linux/fcntl.h
include/uapi/linux/kernel-page-flags.h
init/init_task.c
kernel/cgroup/cgroup.c
kernel/crash_core.c
kernel/kthread.c
kernel/power/snapshot.c
kernel/sched/core.c
kernel/sched/fair.c
kernel/sysctl.c
lib/Kconfig.debug
lib/Kconfig.kasan
lib/Makefile
lib/cpumask.c
lib/test_kasan.c
lib/test_vmalloc.c [new file with mode: 0644]
mm/Kconfig.debug
mm/cma.c
mm/cma_debug.c
mm/compaction.c
mm/dmapool.c
mm/failslab.c
mm/filemap.c
mm/gup.c
mm/gup_benchmark.c
mm/huge_memory.c
mm/hugetlb.c
mm/internal.h
mm/kasan/common.c
mm/kasan/generic.c
mm/kasan/generic_report.c
mm/kasan/init.c
mm/kasan/kasan.h
mm/khugepaged.c
mm/ksm.c
mm/list_lru.c
mm/memblock.c
mm/memcontrol.c
mm/memfd.c
mm/memory-failure.c
mm/memory.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/mempool.c
mm/migrate.c
mm/mlock.c
mm/mmap.c
mm/mprotect.c
mm/mremap.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_ext.c
mm/page_idle.c
mm/page_owner.c
mm/page_poison.c
mm/readahead.c
mm/rmap.c
mm/shmem.c
mm/slab.c
mm/slab.h
mm/slab_common.c
mm/slub.c
mm/sparse.c
mm/swap.c
mm/swap_state.c
mm/swapfile.c
mm/truncate.c
mm/util.c
mm/vmalloc.c
mm/vmscan.c
mm/vmstat.c
mm/workingset.c
net/core/pktgen.c
net/qrtr/qrtr.c
scripts/Makefile.kasan
scripts/decode_stacktrace.sh
scripts/gcc-plugins/Kconfig
tools/include/linux/numa.h [new file with mode: 0644]
tools/perf/bench/numa.c
tools/testing/selftests/Makefile
tools/testing/selftests/memfd/memfd_test.c
tools/testing/selftests/proc/.gitignore
tools/testing/selftests/proc/Makefile
tools/testing/selftests/proc/proc-loadavg-001.c
tools/testing/selftests/proc/proc-pid-vm.c [new file with mode: 0644]
tools/testing/selftests/proc/proc-self-map-files-002.c
tools/testing/selftests/proc/proc-self-syscall.c
tools/testing/selftests/proc/proc-self-wchan.c
tools/testing/selftests/proc/read.c
tools/testing/selftests/tmpfs/.gitignore [new file with mode: 0644]
tools/testing/selftests/tmpfs/Makefile [new file with mode: 0644]
tools/testing/selftests/tmpfs/bug-link-o-tmpfile.c [new file with mode: 0644]
tools/testing/selftests/vm/run_vmtests
tools/testing/selftests/vm/test_vmalloc.sh [new file with mode: 0644]
tools/vm/page-types.c
tools/vm/slabinfo.c

index 7bf3f129c68bdc75943c58764b78aba097671e25..53d3288c328bcfb15723669759776f2bfbacc4e9 100644 (file)
@@ -1189,6 +1189,10 @@ PAGE_SIZE multiple when read back.
                Amount of cached filesystem data that was modified and
                is currently being written back to disk
 
+         anon_thp
+               Amount of memory used in anonymous mappings backed by
+               transparent hugepages
+
          inactive_anon, active_anon, inactive_file, active_file, unevictable
                Amount of memory, swap-backed and filesystem-backed,
                on the internal memory management lists used by the
@@ -1248,6 +1252,18 @@ PAGE_SIZE multiple when read back.
 
                Amount of reclaimed lazyfree pages
 
+         thp_fault_alloc
+
+               Number of transparent hugepages which were allocated to satisfy
+               a page fault, including COW faults. This counter is not present
+               when CONFIG_TRANSPARENT_HUGEPAGE is not set.
+
+         thp_collapse_alloc
+
+               Number of transparent hugepages which were allocated to allow
+               collapsing an existing range of pages. This counter is not
+               present when CONFIG_TRANSPARENT_HUGEPAGE is not set.
+
   memory.swap.current
        A read-only single value file which exists on non-root
        cgroups.
index 3f7bade2c231e0eb402dcc4be4be4d0560ccf46f..340a5aee9b80268cf5c3c0e05962a5df97f77bcd 100644 (file)
@@ -75,9 +75,10 @@ number of times a page is mapped.
     20. NOPAGE
     21. KSM
     22. THP
-    23. BALLOON
+    23. OFFLINE
     24. ZERO_PAGE
     25. IDLE
+    26. PGTABLE
 
  * ``/proc/kpagecgroup``.  This file contains a 64-bit inode number of the
    memory cgroup each page is charged to, indexed by PFN. Only available when
@@ -118,8 +119,8 @@ Short descriptions to the page flags
     identical memory pages dynamically shared between one or more processes
 22 - THP
     contiguous pages which construct transparent hugepages
-23 - BALLOON
-    balloon compaction page
+23 - OFFLINE
+    page is logically offline
 24 - ZERO_PAGE
     zero page for pfn_zero or huge_zero page
 25 - IDLE
@@ -128,6 +129,8 @@ Short descriptions to the page flags
     Note that this flag may be stale in case the page was accessed via
     a PTE. To make sure the flag is up-to-date one has to read
     ``/sys/kernel/mm/page_idle/bitmap`` first.
+26 - PGTABLE
+    page is in use as a page table
 
 IO related page flags
 ---------------------
index 5c7f310f32bb9f4d3b92fda7f2b916e4a5339f4f..621e29ffb358e82f11a25f55e8179487bcae389a 100644 (file)
@@ -107,9 +107,9 @@ Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y.
 
 8. LRU
         Each memcg has its own private LRU. Now, its handling is under global
-       VM's control (means that it's handled under global zone_lru_lock).
+       VM's control (means that it's handled under global pgdat->lru_lock).
        Almost all routines around memcg's LRU is called by global LRU's
-       list management functions under zone_lru_lock().
+       list management functions under pgdat->lru_lock.
 
        A special function is mem_cgroup_isolate_pages(). This scans
        memcg's private LRU and call __isolate_lru_page() to extract a page
index 3682e99234c2c6652ac4990504dfb14bd3873618..a347fc9293e56b04a998b0c38316175da590c3d8 100644 (file)
@@ -267,11 +267,11 @@ When oom event notifier is registered, event will be delivered.
    Other lock order is following:
    PG_locked.
    mm->page_table_lock
-       zone_lru_lock
+       pgdat->lru_lock
          lock_page_cgroup.
   In many cases, just lock_page_cgroup() is called.
   per-zone-per-cgroup LRU (cgroup's private LRU) is just guarded by
-  zone_lru_lock, it has no lock of its own.
+  pgdat->lru_lock, it has no lock of its own.
 
 2.7 Kernel Memory Extension (CONFIG_MEMCG_KMEM)
 
index bd549618aea925e8c535d96e3568e753c13f70f4..c7d3e51c70643391724ed27ba2aba18dc2a5b531 100644 (file)
@@ -9835,6 +9835,14 @@ F:       kernel/sched/membarrier.c
 F:     include/uapi/linux/membarrier.h
 F:     arch/powerpc/include/asm/membarrier.h
 
+MEMBLOCK
+M:     Mike Rapoport <rppt@linux.ibm.com>
+L:     linux-mm@kvack.org
+S:     Maintained
+F:     include/linux/memblock.h
+F:     mm/memblock.c
+F:     Documentation/core-api/boot-time-mm.rst
+
 MEMORY MANAGEMENT
 L:     linux-mm@kvack.org
 W:     http://www.linux-mm.org
index e6e13a85796a609153f9c3738ca04c5d68af7d79..5a77a40567fab6a363b1743eee3a40be88cac46c 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/smp.h>
 #include <linux/threads.h>
+#include <linux/numa.h>
 #include <asm/machvec.h>
 
 #ifdef CONFIG_NUMA
@@ -29,7 +30,7 @@ static const struct cpumask *cpumask_of_node(int node)
 {
        int cpu;
 
-       if (node == -1)
+       if (node == NUMA_NO_NODE)
                return cpu_all_mask;
 
        cpumask_clear(&node_to_cpumask_map[node]);
index a4168d36612772a7668ee0a7d9e83afef40a729d..cfbf307d6dc4e2e8f1cf7a33dfb552452fb55360 100644 (file)
@@ -1467,6 +1467,10 @@ config SYSVIPC_COMPAT
        def_bool y
        depends on COMPAT && SYSVIPC
 
+config ARCH_ENABLE_HUGEPAGE_MIGRATION
+       def_bool y
+       depends on HUGETLB_PAGE && MIGRATION
+
 menu "Power management options"
 
 source "kernel/power/Kconfig"
index fb660987545598494ecf9724c6140d4c35c3ccfa..c6a07a3b433e3d09b9b0ff08ed53a881470b6508 100644 (file)
 
 #include <asm/page.h>
 
+#ifdef CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION
+#define arch_hugetlb_migration_supported arch_hugetlb_migration_supported
+extern bool arch_hugetlb_migration_supported(struct hstate *h);
+#endif
+
 #define __HAVE_ARCH_HUGE_PTEP_GET
 static inline pte_t huge_ptep_get(pte_t *ptep)
 {
index 0c656850eeeaa9df40f0e7b3a643228ea33ec9d7..b01ef0180a03cd2f18e27e369082330f03326734 100644 (file)
  */
 #ifdef CONFIG_KASAN
 #define KASAN_SHADOW_SIZE      (UL(1) << (VA_BITS - KASAN_SHADOW_SCALE_SHIFT))
-#ifdef CONFIG_KASAN_EXTRA
-#define KASAN_THREAD_SHIFT     2
-#else
 #define KASAN_THREAD_SHIFT     1
-#endif /* CONFIG_KASAN_EXTRA */
 #else
 #define KASAN_SHADOW_SIZE      (0)
 #define KASAN_THREAD_SHIFT     0
index aa9c94113700e19bc1d43e23879cc8b788d75e8b..66b5d697d943b380ccb76e5f354ae475f9c7a64b 100644 (file)
@@ -321,7 +321,7 @@ void crash_post_resume(void)
  * but does not hold any data of loaded kernel image.
  *
  * Note that all the pages in crash dump kernel memory have been initially
- * marked as Reserved in kexec_reserve_crashkres_pages().
+ * marked as Reserved as memory was allocated via memblock_reserve().
  *
  * In hibernation, the pages which are Reserved and yet "nosave" are excluded
  * from the hibernation iamge. crash_is_nosave() does thich check for crash
@@ -361,7 +361,6 @@ void crash_free_reserved_phys_range(unsigned long begin, unsigned long end)
 
        for (addr = begin; addr < end; addr += PAGE_SIZE) {
                page = phys_to_page(addr);
-               ClearPageReserved(page);
                free_reserved_page(page);
        }
 }
index 28cbc22d7e3052a836b1993c6e96327eace00e6e..6b4a47b3adf4d8e186d96e0b53bd564a353797cb 100644 (file)
 #include <asm/tlbflush.h>
 #include <asm/pgalloc.h>
 
+#ifdef CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION
+bool arch_hugetlb_migration_supported(struct hstate *h)
+{
+       size_t pagesize = huge_page_size(h);
+
+       switch (pagesize) {
+#ifdef CONFIG_ARM64_4K_PAGES
+       case PUD_SIZE:
+#endif
+       case PMD_SIZE:
+       case CONT_PMD_SIZE:
+       case CONT_PTE_SIZE:
+               return true;
+       }
+       pr_warn("%s: unrecognized huge page size 0x%lx\n",
+                       __func__, pagesize);
+       return false;
+}
+#endif
+
 int pmd_huge(pmd_t pmd)
 {
        return pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT);
index 7205a9085b4de23edf68ae194b20c54ceacc029e..c38976b700697eb2e8d6a7e73b2adb06f6539858 100644 (file)
@@ -118,35 +118,10 @@ static void __init reserve_crashkernel(void)
        crashk_res.start = crash_base;
        crashk_res.end = crash_base + crash_size - 1;
 }
-
-static void __init kexec_reserve_crashkres_pages(void)
-{
-#ifdef CONFIG_HIBERNATION
-       phys_addr_t addr;
-       struct page *page;
-
-       if (!crashk_res.end)
-               return;
-
-       /*
-        * To reduce the size of hibernation image, all the pages are
-        * marked as Reserved initially.
-        */
-       for (addr = crashk_res.start; addr < (crashk_res.end + 1);
-                       addr += PAGE_SIZE) {
-               page = phys_to_page(addr);
-               SetPageReserved(page);
-       }
-#endif
-}
 #else
 static void __init reserve_crashkernel(void)
 {
 }
-
-static void __init kexec_reserve_crashkres_pages(void)
-{
-}
 #endif /* CONFIG_KEXEC_CORE */
 
 #ifdef CONFIG_CRASH_DUMP
@@ -586,8 +561,6 @@ void __init mem_init(void)
        /* this will put all unused low memory onto the freelists */
        memblock_free_all();
 
-       kexec_reserve_crashkres_pages();
-
        mem_init_print_info(NULL);
 
        /*
index ae34e3a1cef1c87eaedf28081bbdcd85bfceb86f..7a0a555b366af0aa8c56a801cf9f5ecdbd070112 100644 (file)
@@ -120,7 +120,7 @@ static void __init setup_node_to_cpumask_map(void)
        }
 
        /* cpumask_of_node() will now work */
-       pr_debug("Node to cpumask map for %d nodes\n", nr_node_ids);
+       pr_debug("Node to cpumask map for %u nodes\n", nr_node_ids);
 }
 
 /*
index 92c376279c6d53a1511ab4c95cc95231dffc2510..1315da6c7aebacb7fa9f17e19cd938c0d7107fbb 100644 (file)
@@ -74,7 +74,7 @@ void __init build_cpu_to_node_map(void)
                cpumask_clear(&node_to_cpu_mask[node]);
 
        for_each_possible_early_cpu(cpu) {
-               node = -1;
+               node = NUMA_NO_NODE;
                for (i = 0; i < NR_CPUS; ++i)
                        if (cpu_physical_id(cpu) == node_cpuid[i].phys_id) {
                                node = node_cpuid[i].nid;
index 46bff16618362308ef016a2125cbdc6419c7124f..7a969f4c3534d3d2b2802e4b561202af0cdbf008 100644 (file)
@@ -583,17 +583,6 @@ pfm_put_task(struct task_struct *task)
        if (task != current) put_task_struct(task);
 }
 
-static inline void
-pfm_reserve_page(unsigned long a)
-{
-       SetPageReserved(vmalloc_to_page((void *)a));
-}
-static inline void
-pfm_unreserve_page(unsigned long a)
-{
-       ClearPageReserved(vmalloc_to_page((void*)a));
-}
-
 static inline unsigned long
 pfm_protect_ctx_ctxsw(pfm_context_t *x)
 {
@@ -816,44 +805,6 @@ pfm_reset_msgq(pfm_context_t *ctx)
        DPRINT(("ctx=%p msgq reset\n", ctx));
 }
 
-static void *
-pfm_rvmalloc(unsigned long size)
-{
-       void *mem;
-       unsigned long addr;
-
-       size = PAGE_ALIGN(size);
-       mem  = vzalloc(size);
-       if (mem) {
-               //printk("perfmon: CPU%d pfm_rvmalloc(%ld)=%p\n", smp_processor_id(), size, mem);
-               addr = (unsigned long)mem;
-               while (size > 0) {
-                       pfm_reserve_page(addr);
-                       addr+=PAGE_SIZE;
-                       size-=PAGE_SIZE;
-               }
-       }
-       return mem;
-}
-
-static void
-pfm_rvfree(void *mem, unsigned long size)
-{
-       unsigned long addr;
-
-       if (mem) {
-               DPRINT(("freeing physical buffer @%p size=%lu\n", mem, size));
-               addr = (unsigned long) mem;
-               while ((long) size > 0) {
-                       pfm_unreserve_page(addr);
-                       addr+=PAGE_SIZE;
-                       size-=PAGE_SIZE;
-               }
-               vfree(mem);
-       }
-       return;
-}
-
 static pfm_context_t *
 pfm_context_alloc(int ctx_flags)
 {
@@ -1498,7 +1449,7 @@ pfm_free_smpl_buffer(pfm_context_t *ctx)
        /*
         * free the buffer
         */
-       pfm_rvfree(ctx->ctx_smpl_hdr, ctx->ctx_smpl_size);
+       vfree(ctx->ctx_smpl_hdr);
 
        ctx->ctx_smpl_hdr  = NULL;
        ctx->ctx_smpl_size = 0UL;
@@ -2137,7 +2088,7 @@ doit:
         * All memory free operations (especially for vmalloc'ed memory)
         * MUST be done with interrupts ENABLED.
         */
-       if (smpl_buf_addr)  pfm_rvfree(smpl_buf_addr, smpl_buf_size);
+       vfree(smpl_buf_addr);
 
        /*
         * return the memory used by the context
@@ -2266,10 +2217,8 @@ pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t
 
        /*
         * We do the easy to undo allocations first.
-        *
-        * pfm_rvmalloc(), clears the buffer, so there is no leak
         */
-       smpl_buf = pfm_rvmalloc(size);
+       smpl_buf = vzalloc(size);
        if (smpl_buf == NULL) {
                DPRINT(("Can't allocate sampling buffer\n"));
                return -ENOMEM;
@@ -2346,7 +2295,7 @@ pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t
 error:
        vm_area_free(vma);
 error_kmem:
-       pfm_rvfree(smpl_buf, size);
+       vfree(smpl_buf);
 
        return -ENOMEM;
 }
index 8a965784340c5c3616742fd01c30e3a0457b0092..f9c36750c6a47feeb6190060a71817fe851dc464 100644 (file)
@@ -227,7 +227,7 @@ void __init setup_per_cpu_areas(void)
         * CPUs are put into groups according to node.  Walk cpu_map
         * and create new groups at node boundaries.
         */
-       prev_node = -1;
+       prev_node = NUMA_NO_NODE;
        ai->nr_groups = 0;
        for (unit = 0; unit < nr_units; unit++) {
                cpu = cpu_map[unit];
@@ -435,7 +435,7 @@ static void __init *memory_less_node_alloc(int nid, unsigned long pernodesize)
 {
        void *ptr = NULL;
        u8 best = 0xff;
-       int bestnode = -1, node, anynode = 0;
+       int bestnode = NUMA_NO_NODE, node, anynode = 0;
 
        for_each_online_node(node) {
                if (node_isset(node, memory_less_mask))
@@ -447,7 +447,7 @@ static void __init *memory_less_node_alloc(int nid, unsigned long pernodesize)
                anynode = node;
        }
 
-       if (bestnode == -1)
+       if (bestnode == NUMA_NO_NODE)
                bestnode = anynode;
 
        ptr = memblock_alloc_try_nid(pernodesize, PERCPU_PAGE_SIZE,
index b86a2e21693ba49edf1ca178334d8e563c58bdc4..227c04fe60d299c0c42676041a8d4a697338a204 100644 (file)
@@ -51,7 +51,7 @@ void __init init_pointer_table(unsigned long ptable)
        pr_debug("init_pointer_table: %lx, %x\n", ptable, PD_MARKBITS(dp));
 
        /* unreserve the page so it's possible to free that page */
-       PD_PAGE(dp)->flags &= ~(1 << PG_reserved);
+       __ClearPageReserved(PD_PAGE(dp));
        init_page_count(PD_PAGE(dp));
 
        return;
index 5b0177733994eaeb86572b81a8d378b0cd4f1879..66c1e4f88d654ebf18cadcfff1f906eeae048fce 100644 (file)
@@ -13,6 +13,10 @@ radix__hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
                                unsigned long len, unsigned long pgoff,
                                unsigned long flags);
 
+extern void radix__huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
+                                               unsigned long addr, pte_t *ptep,
+                                               pte_t old_pte, pte_t pte);
+
 static inline int hstate_get_psize(struct hstate *hstate)
 {
        unsigned long shift;
@@ -42,4 +46,12 @@ static inline bool gigantic_page_supported(void)
 /* hugepd entry valid bit */
 #define HUGEPD_VAL_BITS                (0x8000000000000000UL)
 
+#define huge_ptep_modify_prot_start huge_ptep_modify_prot_start
+extern pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma,
+                                        unsigned long addr, pte_t *ptep);
+
+#define huge_ptep_modify_prot_commit huge_ptep_modify_prot_commit
+extern void huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
+                                        unsigned long addr, pte_t *ptep,
+                                        pte_t old_pte, pte_t new_pte);
 #endif
index d8c8d7c9df1510451367dca149df932b30648720..868fcaf56f6bf20425ae03d5fa42715cffa1c809 100644 (file)
@@ -1306,6 +1306,24 @@ static inline int pud_pfn(pud_t pud)
        BUILD_BUG();
        return 0;
 }
+#define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
+pte_t ptep_modify_prot_start(struct vm_area_struct *, unsigned long, pte_t *);
+void ptep_modify_prot_commit(struct vm_area_struct *, unsigned long,
+                            pte_t *, pte_t, pte_t);
+
+/*
+ * Returns true for a R -> RW upgrade of pte
+ */
+static inline bool is_pte_rw_upgrade(unsigned long old_val, unsigned long new_val)
+{
+       if (!(old_val & _PAGE_READ))
+               return false;
+
+       if ((!(old_val & _PAGE_WRITE)) && (new_val & _PAGE_WRITE))
+               return true;
+
+       return false;
+}
 
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_POWERPC_BOOK3S_64_PGTABLE_H_ */
index 7d1a3d1543fc0fc2d699394ac9d0cbf4cd76f9bb..5ab134eeed20c9da92e431bf9ac512ea1ec8d729 100644 (file)
@@ -127,6 +127,10 @@ extern void radix__ptep_set_access_flags(struct vm_area_struct *vma, pte_t *ptep
                                         pte_t entry, unsigned long address,
                                         int psize);
 
+extern void radix__ptep_modify_prot_commit(struct vm_area_struct *vma,
+                                          unsigned long addr, pte_t *ptep,
+                                          pte_t old_pte, pte_t pte);
+
 static inline unsigned long __radix_pte_update(pte_t *ptep, unsigned long clr,
                                               unsigned long set)
 {
index aee4fcc2499021b7ac268fcfc13ae33b61bf225c..77fc21278fa2ad5ba944a7e825bddf8b47caf31b 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/pci.h>
 #include <linux/list.h>
 #include <linux/ioport.h>
+#include <linux/numa.h>
 
 struct device_node;
 
@@ -265,7 +266,7 @@ extern int pcibios_map_io_space(struct pci_bus *bus);
 #ifdef CONFIG_NUMA
 #define PHB_SET_NODE(PHB, NODE)                ((PHB)->node = (NODE))
 #else
-#define PHB_SET_NODE(PHB, NODE)                ((PHB)->node = -1)
+#define PHB_SET_NODE(PHB, NODE)                ((PHB)->node = NUMA_NO_NODE)
 #endif
 
 #endif /* CONFIG_PPC64 */
index 913bfca09c4f1f0a19be2e0e87b55257be3321f6..b8480127793dbc8f261e2254822336764741dacc 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/export.h>
 #include <linux/memblock.h>
 #include <linux/sched/task.h>
+#include <linux/numa.h>
 
 #include <asm/lppaca.h>
 #include <asm/paca.h>
@@ -36,7 +37,7 @@ static void *__init alloc_paca_data(unsigned long size, unsigned long align,
         * which will put its paca in the right place.
         */
        if (cpu == boot_cpuid) {
-               nid = -1;
+               nid = NUMA_NO_NODE;
                memblock_set_bottom_up(true);
        } else {
                nid = early_cpu_to_node(cpu);
index 88e4f69a09e52624dd75c6e6aaa0d1f894d18758..4538e8ddde807fc11e2392e4263ff13287147b1e 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 #include <linux/vgaarb.h>
+#include <linux/numa.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
@@ -132,7 +133,7 @@ struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
                int nid = of_node_to_nid(dev);
 
                if (nid < 0 || !node_online(nid))
-                       nid = -1;
+                       nid = NUMA_NO_NODE;
 
                PHB_SET_NODE(phb, nid);
        }
index 7725a971473670080f27c299181e5c5e228c6c37..a31b6234fcd7c87d3aa456d3deabc5584a1d2a0f 100644 (file)
@@ -798,7 +798,6 @@ static int __init vdso_init(void)
        BUG_ON(vdso32_pagelist == NULL);
        for (i = 0; i < vdso32_pages; i++) {
                struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE);
-               ClearPageReserved(pg);
                get_page(pg);
                vdso32_pagelist[i] = pg;
        }
@@ -812,7 +811,6 @@ static int __init vdso_init(void)
        BUG_ON(vdso64_pagelist == NULL);
        for (i = 0; i < vdso64_pages; i++) {
                struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE);
-               ClearPageReserved(pg);
                get_page(pg);
                vdso64_pagelist[i] = pg;
        }
index 2e6a8f9345d3708b908d76e5745d9ca0f9f1914f..367ce3a4a50395faf636ce72fe78b2a3260b7b84 100644 (file)
@@ -121,3 +121,28 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
        *ptep = __pte(new_pte & ~H_PAGE_BUSY);
        return 0;
 }
+
+pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma,
+                                 unsigned long addr, pte_t *ptep)
+{
+       unsigned long pte_val;
+       /*
+        * Clear the _PAGE_PRESENT so that no hardware parallel update is
+        * possible. Also keep the pte_present true so that we don't take
+        * wrong fault.
+        */
+       pte_val = pte_update(vma->vm_mm, addr, ptep,
+                            _PAGE_PRESENT, _PAGE_INVALID, 1);
+
+       return __pte(pte_val);
+}
+
+void huge_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
+                                 pte_t *ptep, pte_t old_pte, pte_t pte)
+{
+
+       if (radix_enabled())
+               return radix__huge_ptep_modify_prot_commit(vma, addr, ptep,
+                                                          old_pte, pte);
+       set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+}
index 2486bee0f93e33e4a5a119fa90cc1924b056a768..11d9ea28a816ac2fcf88bf19910ba77298bd004d 100644 (file)
@@ -90,3 +90,20 @@ radix__hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
 
        return vm_unmapped_area(&info);
 }
+
+void radix__huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
+                                        unsigned long addr, pte_t *ptep,
+                                        pte_t old_pte, pte_t pte)
+{
+       struct mm_struct *mm = vma->vm_mm;
+
+       /*
+        * To avoid NMMU hang while relaxing access we need to flush the tlb before
+        * we set the new value.
+        */
+       if (is_pte_rw_upgrade(pte_val(old_pte), pte_val(pte)) &&
+           (atomic_read(&mm->context.copros) > 0))
+               radix__flush_hugetlb_page(vma, addr);
+
+       set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+}
index a712a650a8b6d49e499cfabd64fa784fc1ea8bfe..e7a9c4f6bfca49585beffcb6fc3dc755eb054e8f 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/sizes.h>
 #include <asm/mmu_context.h>
 #include <asm/pte-walk.h>
+#include <linux/mm_inline.h>
 
 static DEFINE_MUTEX(mem_list_mutex);
 
@@ -34,8 +35,18 @@ struct mm_iommu_table_group_mem_t {
        atomic64_t mapped;
        unsigned int pageshift;
        u64 ua;                 /* userspace address */
-       u64 entries;            /* number of entries in hpas[] */
-       u64 *hpas;              /* vmalloc'ed */
+       u64 entries;            /* number of entries in hpas/hpages[] */
+       /*
+        * in mm_iommu_get we temporarily use this to store
+        * struct page address.
+        *
+        * We need to convert ua to hpa in real mode. Make it
+        * simpler by storing physical address.
+        */
+       union {
+               struct page **hpages;   /* vmalloc'ed */
+               phys_addr_t *hpas;
+       };
 #define MM_IOMMU_TABLE_INVALID_HPA     ((uint64_t)-1)
        u64 dev_hpa;            /* Device memory base address */
 };
@@ -80,64 +91,13 @@ bool mm_iommu_preregistered(struct mm_struct *mm)
 }
 EXPORT_SYMBOL_GPL(mm_iommu_preregistered);
 
-/*
- * Taken from alloc_migrate_target with changes to remove CMA allocations
- */
-struct page *new_iommu_non_cma_page(struct page *page, unsigned long private)
-{
-       gfp_t gfp_mask = GFP_USER;
-       struct page *new_page;
-
-       if (PageCompound(page))
-               return NULL;
-
-       if (PageHighMem(page))
-               gfp_mask |= __GFP_HIGHMEM;
-
-       /*
-        * We don't want the allocation to force an OOM if possibe
-        */
-       new_page = alloc_page(gfp_mask | __GFP_NORETRY | __GFP_NOWARN);
-       return new_page;
-}
-
-static int mm_iommu_move_page_from_cma(struct page *page)
-{
-       int ret = 0;
-       LIST_HEAD(cma_migrate_pages);
-
-       /* Ignore huge pages for now */
-       if (PageCompound(page))
-               return -EBUSY;
-
-       lru_add_drain();
-       ret = isolate_lru_page(page);
-       if (ret)
-               return ret;
-
-       list_add(&page->lru, &cma_migrate_pages);
-       put_page(page); /* Drop the gup reference */
-
-       ret = migrate_pages(&cma_migrate_pages, new_iommu_non_cma_page,
-                               NULL, 0, MIGRATE_SYNC, MR_CONTIG_RANGE);
-       if (ret) {
-               if (!list_empty(&cma_migrate_pages))
-                       putback_movable_pages(&cma_migrate_pages);
-       }
-
-       return 0;
-}
-
 static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua,
-               unsigned long entries, unsigned long dev_hpa,
-               struct mm_iommu_table_group_mem_t **pmem)
+                             unsigned long entries, unsigned long dev_hpa,
+                             struct mm_iommu_table_group_mem_t **pmem)
 {
        struct mm_iommu_table_group_mem_t *mem;
-       long i, j, ret = 0, locked_entries = 0;
+       long i, ret, locked_entries = 0;
        unsigned int pageshift;
-       unsigned long flags;
-       unsigned long cur_ua;
-       struct page *page = NULL;
 
        mutex_lock(&mem_list_mutex);
 
@@ -187,62 +147,43 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua,
                goto unlock_exit;
        }
 
+       down_read(&mm->mmap_sem);
+       ret = get_user_pages_longterm(ua, entries, FOLL_WRITE, mem->hpages, NULL);
+       up_read(&mm->mmap_sem);
+       if (ret != entries) {
+               /* free the reference taken */
+               for (i = 0; i < ret; i++)
+                       put_page(mem->hpages[i]);
+
+               vfree(mem->hpas);
+               kfree(mem);
+               ret = -EFAULT;
+               goto unlock_exit;
+       }
+
+       pageshift = PAGE_SHIFT;
        for (i = 0; i < entries; ++i) {
-               cur_ua = ua + (i << PAGE_SHIFT);
-               if (1 != get_user_pages_fast(cur_ua,
-                                       1/* pages */, 1/* iswrite */, &page)) {
-                       ret = -EFAULT;
-                       for (j = 0; j < i; ++j)
-                               put_page(pfn_to_page(mem->hpas[j] >>
-                                               PAGE_SHIFT));
-                       vfree(mem->hpas);
-                       kfree(mem);
-                       goto unlock_exit;
-               }
+               struct page *page = mem->hpages[i];
+
                /*
-                * If we get a page from the CMA zone, since we are going to
-                * be pinning these entries, we might as well move them out
-                * of the CMA zone if possible. NOTE: faulting in + migration
-                * can be expensive. Batching can be considered later
+                * Allow to use larger than 64k IOMMU pages. Only do that
+                * if we are backed by hugetlb.
                 */
-               if (is_migrate_cma_page(page)) {
-                       if (mm_iommu_move_page_from_cma(page))
-                               goto populate;
-                       if (1 != get_user_pages_fast(cur_ua,
-                                               1/* pages */, 1/* iswrite */,
-                                               &page)) {
-                               ret = -EFAULT;
-                               for (j = 0; j < i; ++j)
-                                       put_page(pfn_to_page(mem->hpas[j] >>
-                                                               PAGE_SHIFT));
-                               vfree(mem->hpas);
-                               kfree(mem);
-                               goto unlock_exit;
-                       }
-               }
-populate:
-               pageshift = PAGE_SHIFT;
-               if (mem->pageshift > PAGE_SHIFT && PageCompound(page)) {
-                       pte_t *pte;
+               if ((mem->pageshift > PAGE_SHIFT) && PageHuge(page)) {
                        struct page *head = compound_head(page);
-                       unsigned int compshift = compound_order(head);
-                       unsigned int pteshift;
-
-                       local_irq_save(flags); /* disables as well */
-                       pte = find_linux_pte(mm->pgd, cur_ua, NULL, &pteshift);
-
-                       /* Double check it is still the same pinned page */
-                       if (pte && pte_page(*pte) == head &&
-                           pteshift == compshift + PAGE_SHIFT)
-                               pageshift = max_t(unsigned int, pteshift,
-                                               PAGE_SHIFT);
-                       local_irq_restore(flags);
+
+                       pageshift = compound_order(head) + PAGE_SHIFT;
                }
                mem->pageshift = min(mem->pageshift, pageshift);
+               /*
+                * We don't need struct page reference any more, switch
+                * to physical address.
+                */
                mem->hpas[i] = page_to_pfn(page) << PAGE_SHIFT;
        }
 
 good_exit:
+       ret = 0;
        atomic64_set(&mem->mapped, 1);
        mem->used = 1;
        mem->ua = ua;
index 87f0dd004295761b321216adf333f1eab1ca09df..df1e11ebbabbfb9647a7f81bfd41d98259212f03 100644 (file)
@@ -84,7 +84,7 @@ static void __init setup_node_to_cpumask_map(void)
                alloc_bootmem_cpumask_var(&node_to_cpumask_map[node]);
 
        /* cpumask_of_node() will now work */
-       dbg("Node to cpumask map for %d nodes\n", nr_node_ids);
+       dbg("Node to cpumask map for %u nodes\n", nr_node_ids);
 }
 
 static int __init fake_numa_create_new_node(unsigned long end_pfn,
@@ -215,7 +215,7 @@ static void initialize_distance_lookup_table(int nid,
  */
 static int associativity_to_nid(const __be32 *associativity)
 {
-       int nid = -1;
+       int nid = NUMA_NO_NODE;
 
        if (min_common_depth == -1)
                goto out;
@@ -225,7 +225,7 @@ static int associativity_to_nid(const __be32 *associativity)
 
        /* POWER4 LPAR uses 0xffff as invalid node */
        if (nid == 0xffff || nid >= MAX_NUMNODES)
-               nid = -1;
+               nid = NUMA_NO_NODE;
 
        if (nid > 0 &&
                of_read_number(associativity, 1) >= distance_ref_points_depth) {
@@ -244,7 +244,7 @@ out:
  */
 static int of_node_to_nid_single(struct device_node *device)
 {
-       int nid = -1;
+       int nid = NUMA_NO_NODE;
        const __be32 *tmp;
 
        tmp = of_get_associativity(device);
@@ -256,7 +256,7 @@ static int of_node_to_nid_single(struct device_node *device)
 /* Walk the device tree upwards, looking for an associativity id */
 int of_node_to_nid(struct device_node *device)
 {
-       int nid = -1;
+       int nid = NUMA_NO_NODE;
 
        of_node_get(device);
        while (device) {
@@ -454,7 +454,7 @@ static int of_drconf_to_nid_single(struct drmem_lmb *lmb)
  */
 static int numa_setup_cpu(unsigned long lcpu)
 {
-       int nid = -1;
+       int nid = NUMA_NO_NODE;
        struct device_node *cpu;
 
        /*
@@ -930,7 +930,7 @@ static int hot_add_drconf_scn_to_nid(unsigned long scn_addr)
 {
        struct drmem_lmb *lmb;
        unsigned long lmb_size;
-       int nid = -1;
+       int nid = NUMA_NO_NODE;
 
        lmb_size = drmem_lmb_size();
 
@@ -960,7 +960,7 @@ static int hot_add_drconf_scn_to_nid(unsigned long scn_addr)
 static int hot_add_node_scn_to_nid(unsigned long scn_addr)
 {
        struct device_node *memory;
-       int nid = -1;
+       int nid = NUMA_NO_NODE;
 
        for_each_node_by_type(memory, "memory") {
                unsigned long start, size;
index ecd31569a120a716d30d1f030b6732e0298a172b..e7da590c7a786f5325f17f7e1abc6cb112bebf80 100644 (file)
@@ -401,6 +401,31 @@ void arch_report_meminfo(struct seq_file *m)
 }
 #endif /* CONFIG_PROC_FS */
 
+pte_t ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr,
+                            pte_t *ptep)
+{
+       unsigned long pte_val;
+
+       /*
+        * Clear the _PAGE_PRESENT so that no hardware parallel update is
+        * possible. Also keep the pte_present true so that we don't take
+        * wrong fault.
+        */
+       pte_val = pte_update(vma->vm_mm, addr, ptep, _PAGE_PRESENT, _PAGE_INVALID, 0);
+
+       return __pte(pte_val);
+
+}
+
+void ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
+                            pte_t *ptep, pte_t old_pte, pte_t pte)
+{
+       if (radix_enabled())
+               return radix__ptep_modify_prot_commit(vma, addr,
+                                                     ptep, old_pte, pte);
+       set_pte_at(vma->vm_mm, addr, ptep, pte);
+}
+
 /*
  * For hash translation mode, we use the deposited table to store hash slot
  * information and they are stored at PTRS_PER_PMD offset from related pmd
index 931156069a81b03a91eddcc83ede2103e4f54ac3..dced3cd241c2920d68ae1cda6919a4195e840a85 100644 (file)
@@ -1063,3 +1063,21 @@ void radix__ptep_set_access_flags(struct vm_area_struct *vma, pte_t *ptep,
        }
        /* See ptesync comment in radix__set_pte_at */
 }
+
+void radix__ptep_modify_prot_commit(struct vm_area_struct *vma,
+                                   unsigned long addr, pte_t *ptep,
+                                   pte_t old_pte, pte_t pte)
+{
+       struct mm_struct *mm = vma->vm_mm;
+
+       /*
+        * To avoid NMMU hang while relaxing access we need to flush the tlb before
+        * we set the new value. We need to do this only for radix, because hash
+        * translation does flush when updating the linux pte.
+        */
+       if (is_pte_rw_upgrade(pte_val(old_pte), pte_val(pte)) &&
+           (atomic_read(&mm->context.copros) > 0))
+               radix__flush_tlb_page(vma, addr);
+
+       set_pte_at(mm, addr, ptep, pte);
+}
index 84d038ed3882a7794987ba3f222aab7351895d8f..248a38ad25c79c15cefb883d50b9895ba2395ad8 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/memory.h>
 #include <linux/memory_hotplug.h>
+#include <linux/numa.h>
 #include <asm/machdep.h>
 #include <asm/debugfs.h>
 
@@ -223,7 +224,7 @@ static int memtrace_online(void)
                ent = &memtrace_array[i];
 
                /* We have onlined this chunk previously */
-               if (ent->nid == -1)
+               if (ent->nid == NUMA_NO_NODE)
                        continue;
 
                /* Remove from io mappings */
@@ -257,7 +258,7 @@ static int memtrace_online(void)
                 */
                debugfs_remove_recursive(ent->dir);
                pr_info("Added trace memory back to node %d\n", ent->nid);
-               ent->size = ent->start = ent->nid = -1;
+               ent->size = ent->start = ent->nid = NUMA_NO_NODE;
        }
        if (ret)
                return ret;
index 582cb153eb248a7f39c1573ebc078e71183e9ae5..0cd044122234eb6c16c426271418be4dd0bb47a7 100644 (file)
@@ -54,7 +54,6 @@ static int __init vdso_init(void)
                struct page *pg;
 
                pg = virt_to_page(vdso_start + (i << PAGE_SHIFT));
-               ClearPageReserved(pg);
                vdso_pagelist[i] = pg;
        }
        vdso_pagelist[i] = virt_to_page(vdso_data);
index 063732414dfbb5076c431d13e694e239e878ebef..76dc344edb8cfd9c661b456d8c19afa54d0fa530 100644 (file)
@@ -1069,8 +1069,9 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
 }
 
 #define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
-pte_t ptep_modify_prot_start(struct mm_struct *, unsigned long, pte_t *);
-void ptep_modify_prot_commit(struct mm_struct *, unsigned long, pte_t *, pte_t);
+pte_t ptep_modify_prot_start(struct vm_area_struct *, unsigned long, pte_t *);
+void ptep_modify_prot_commit(struct vm_area_struct *, unsigned long,
+                            pte_t *, pte_t, pte_t);
 
 #define __HAVE_ARCH_PTEP_CLEAR_FLUSH
 static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
index 4ff354887db412a504bb432956c28b2ba6b8a936..e7920a68a12ecf977e73a237a446bf65a5dfbecc 100644 (file)
@@ -291,7 +291,6 @@ static int __init vdso_init(void)
        BUG_ON(vdso32_pagelist == NULL);
        for (i = 0; i < vdso32_pages - 1; i++) {
                struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE);
-               ClearPageReserved(pg);
                get_page(pg);
                vdso32_pagelist[i] = pg;
        }
@@ -309,7 +308,6 @@ static int __init vdso_init(void)
        BUG_ON(vdso64_pagelist == NULL);
        for (i = 0; i < vdso64_pages - 1; i++) {
                struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE);
-               ClearPageReserved(pg);
                get_page(pg);
                vdso64_pagelist[i] = pg;
        }
index 689b66f29fc606285482939bbb574aef5758fa2e..8485d6dc275496ab69d76cfa29bb2ae66c14e9b5 100644 (file)
@@ -301,12 +301,13 @@ pte_t ptep_xchg_lazy(struct mm_struct *mm, unsigned long addr,
 }
 EXPORT_SYMBOL(ptep_xchg_lazy);
 
-pte_t ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr,
+pte_t ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr,
                             pte_t *ptep)
 {
        pgste_t pgste;
        pte_t old;
        int nodat;
+       struct mm_struct *mm = vma->vm_mm;
 
        preempt_disable();
        pgste = ptep_xchg_start(mm, addr, ptep);
@@ -319,10 +320,11 @@ pte_t ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr,
        return old;
 }
 
-void ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
-                            pte_t *ptep, pte_t pte)
+void ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
+                            pte_t *ptep, pte_t old_pte, pte_t pte)
 {
        pgste_t pgste;
+       struct mm_struct *mm = vma->vm_mm;
 
        if (!MACHINE_HAS_NX)
                pte_val(pte) &= ~_PAGE_NOEXEC;
index 85d78d9309adc4ab2199a4a9fafdce0997da5f87..904b8e6e625d29f9fcfc082605a10108b6b4838d 100644 (file)
@@ -13,10 +13,10 @@ emit() {
        t_entry="$3"
 
        while [ $t_nxt -lt $t_nr ]; do
-               printf "__SYSCALL(%s, sys_ni_syscall, )\n" "${t_nxt}"
+               printf "__SYSCALL(%s,sys_ni_syscall)\n" "${t_nxt}"
                t_nxt=$((t_nxt+1))
        done
-       printf "__SYSCALL(%s, %s, )\n" "${t_nxt}" "${t_entry}"
+       printf "__SYSCALL(%s,%s)\n" "${t_nxt}" "${t_entry}"
 }
 
 grep -E "^[0-9A-Fa-fXx]+[[:space:]]+${my_abis}" "$in" | sort -n | (
index 96e9c54a07f5209af186fbfddeb89a6457c9208d..bd1a9c54476732565b355476523dd656cfda86a7 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/sys.h>
 #include <linux/linkage.h>
 
-#define __SYSCALL(nr, entry, nargs) .long entry
+#define __SYSCALL(nr, entry)   .long entry
        .data
 ENTRY(sys_call_table)
 #include <asm/syscall_table.h>
index be71ae086622662b1b3f851f4301771968ff83c2..0ca08d455e805d7cc72bfc74377105e78d699a68 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/export.h>
 #include <linux/irq.h>
 #include <linux/of_device.h>
+#include <linux/numa.h>
 
 #include <asm/prom.h>
 #include <asm/irq.h>
@@ -416,7 +417,7 @@ static int pci_fire_pbm_init(struct pci_pbm_info *pbm,
        struct device_node *dp = op->dev.of_node;
        int err;
 
-       pbm->numa_node = -1;
+       pbm->numa_node = NUMA_NO_NODE;
 
        pbm->pci_ops = &sun4u_pci_ops;
        pbm->config_space_reg_bits = 12;
index 934b97c72f7ccd3c3d4fc9fd5242dda7d3499c5b..421aba00e6b0a410f23687ed606cc136cc63fe8a 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
+#include <linux/numa.h>
 
 #include <asm/iommu.h>
 #include <asm/irq.h>
@@ -1347,7 +1348,7 @@ static int schizo_pbm_init(struct pci_pbm_info *pbm,
        pbm->next = pci_pbm_root;
        pci_pbm_root = pbm;
 
-       pbm->numa_node = -1;
+       pbm->numa_node = NUMA_NO_NODE;
 
        pbm->pci_ops = &sun4u_pci_ops;
        pbm->config_space_reg_bits = 8;
index 81aa91e5c0e6c38e1305948279de6602e98fe961..e90bcb6bad7fc76b24a241eb224aff738c2e0296 100644 (file)
@@ -5,6 +5,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/numa.h>
 
 #include <asm/upa.h>
 
@@ -454,7 +455,7 @@ void psycho_pbm_init_common(struct pci_pbm_info *pbm, struct platform_device *op
        struct device_node *dp = op->dev.of_node;
 
        pbm->name = dp->full_name;
-       pbm->numa_node = -1;
+       pbm->numa_node = NUMA_NO_NODE;
        pbm->chip_type = chip_type;
        pbm->chip_version = of_getintprop_default(dp, "version#", 0);
        pbm->chip_revision = of_getintprop_default(dp, "module-revision#", 0);
index 41c5deb581b8ddeebfac032b7a6d7c923877d3e5..32141e1006c4a4907c5d6bbc4caba20aa30cb5db 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/interrupt.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/numa.h>
 
 #include <asm/page.h>
 #include <asm/io.h>
@@ -561,7 +562,7 @@ static void __init sbus_iommu_init(struct platform_device *op)
 
        op->dev.archdata.iommu = iommu;
        op->dev.archdata.stc = strbuf;
-       op->dev.archdata.numa_node = -1;
+       op->dev.archdata.numa_node = NUMA_NO_NODE;
 
        reg_base = regs + SYSIO_IOMMUREG_BASE;
        iommu->iommu_control = reg_base + IOMMU_CONTROL;
index b4221d3727d0a5abe88eb631b39a3ef320877bfe..9e6bd868ba6f1403b5a985a06ab8b5270c2acc8b 100644 (file)
@@ -976,13 +976,13 @@ static u64 __init memblock_nid_range_sun4u(u64 start, u64 end, int *nid)
 {
        int prev_nid, new_nid;
 
-       prev_nid = -1;
+       prev_nid = NUMA_NO_NODE;
        for ( ; start < end; start += PAGE_SIZE) {
                for (new_nid = 0; new_nid < num_node_masks; new_nid++) {
                        struct node_mem_mask *p = &node_masks[new_nid];
 
                        if ((start & p->mask) == p->match) {
-                               if (prev_nid == -1)
+                               if (prev_nid == NUMA_NO_NODE)
                                        prev_nid = new_nid;
                                break;
                        }
@@ -1208,7 +1208,7 @@ int of_node_to_nid(struct device_node *dp)
        md = mdesc_grab();
 
        count = 0;
-       nid = -1;
+       nid = NUMA_NO_NODE;
        mdesc_for_each_node_by_name(md, grp, "group") {
                if (!scan_arcs_for_cfg_handle(md, grp, cfg_handle)) {
                        nid = count;
index a97f28d914d564abc99228d99ca0e4d637b143fb..c25c38a05c1c944f7e7c7c51509bee0499705573 100644 (file)
@@ -422,25 +422,26 @@ static inline pgdval_t pgd_val(pgd_t pgd)
 }
 
 #define  __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
-static inline pte_t ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr,
+static inline pte_t ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr,
                                           pte_t *ptep)
 {
        pteval_t ret;
 
-       ret = PVOP_CALL3(pteval_t, mmu.ptep_modify_prot_start, mm, addr, ptep);
+       ret = PVOP_CALL3(pteval_t, mmu.ptep_modify_prot_start, vma, addr, ptep);
 
        return (pte_t) { .pte = ret };
 }
 
-static inline void ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
-                                          pte_t *ptep, pte_t pte)
+static inline void ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
+                                          pte_t *ptep, pte_t old_pte, pte_t pte)
 {
+
        if (sizeof(pteval_t) > sizeof(long))
                /* 5 arg words */
-               pv_ops.mmu.ptep_modify_prot_commit(mm, addr, ptep, pte);
+               pv_ops.mmu.ptep_modify_prot_commit(vma, addr, ptep, pte);
        else
                PVOP_VCALL4(mmu.ptep_modify_prot_commit,
-                           mm, addr, ptep, pte.pte);
+                           vma, addr, ptep, pte.pte);
 }
 
 static inline void set_pte(pte_t *ptep, pte_t pte)
index 488c59686a733cc8ad627f7150a7d4aab72507b9..2474e434a6f72c42ed12f2ca6ab7ed2b4aeae08b 100644 (file)
@@ -55,6 +55,7 @@ struct task_struct;
 struct cpumask;
 struct flush_tlb_info;
 struct mmu_gather;
+struct vm_area_struct;
 
 /*
  * Wrapper type for pointers to code which uses the non-standard
@@ -254,9 +255,9 @@ struct pv_mmu_ops {
                           pte_t *ptep, pte_t pteval);
        void (*set_pmd)(pmd_t *pmdp, pmd_t pmdval);
 
-       pte_t (*ptep_modify_prot_start)(struct mm_struct *mm, unsigned long addr,
+       pte_t (*ptep_modify_prot_start)(struct vm_area_struct *vma, unsigned long addr,
                                        pte_t *ptep);
-       void (*ptep_modify_prot_commit)(struct mm_struct *mm, unsigned long addr,
+       void (*ptep_modify_prot_commit)(struct vm_area_struct *vma, unsigned long addr,
                                        pte_t *ptep, pte_t pte);
 
        struct paravirt_callee_save pte_val;
index 662963681ea6c3f7d9235c246734844592579755..e662f987dfa2cb093a25e1684e06c0067e78eb58 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/scatterlist.h>
+#include <linux/numa.h>
 #include <asm/io.h>
 #include <asm/pat.h>
 #include <asm/x86_init.h>
@@ -141,7 +142,7 @@ cpumask_of_pcibus(const struct pci_bus *bus)
        int node;
 
        node = __pcibus_to_node(bus);
-       return (node == -1) ? cpu_online_mask :
+       return (node == NUMA_NO_NODE) ? cpu_online_mask :
                              cpumask_of_node(node);
 }
 #endif
index 5e49a0acb5eeb194fa892baebf01f4c0bfbfc531..62004d22524a7cea9fa04ae83f1610e4ba5d6985 100644 (file)
@@ -75,7 +75,7 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
 #endif
 
 /**
- * access_ok: - Checks if a user space pointer is valid
+ * access_ok - Checks if a user space pointer is valid
  * @addr: User space pointer to start of block to check
  * @size: Size of block to check
  *
@@ -84,12 +84,12 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
  *
  * Checks if a pointer to a block of memory in user space is valid.
  *
- * Returns true (nonzero) if the memory block may be valid, false (zero)
- * if it is definitely invalid.
- *
  * Note that, depending on architecture, this function probably just
  * checks that the pointer is in the user space range - after calling
  * this function, memory access functions may still return -EFAULT.
+ *
+ * Return: true (nonzero) if the memory block may be valid, false (zero)
+ * if it is definitely invalid.
  */
 #define access_ok(addr, size)                                  \
 ({                                                                     \
@@ -134,7 +134,7 @@ extern int __get_user_bad(void);
 __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
 
 /**
- * get_user: - Get a simple variable from user space.
+ * get_user - Get a simple variable from user space.
  * @x:   Variable to store result.
  * @ptr: Source address, in user space.
  *
@@ -148,7 +148,7 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
  * @ptr must have pointer-to-simple-variable type, and the result of
  * dereferencing @ptr must be assignable to @x without a cast.
  *
- * Returns zero on success, or -EFAULT on error.
+ * Return: zero on success, or -EFAULT on error.
  * On error, the variable @x is set to zero.
  */
 /*
@@ -226,7 +226,7 @@ extern void __put_user_4(void);
 extern void __put_user_8(void);
 
 /**
- * put_user: - Write a simple value into user space.
+ * put_user - Write a simple value into user space.
  * @x:   Value to copy to user space.
  * @ptr: Destination address, in user space.
  *
@@ -240,7 +240,7 @@ extern void __put_user_8(void);
  * @ptr must have pointer-to-simple-variable type, and @x must be assignable
  * to the result of dereferencing @ptr.
  *
- * Returns zero on success, or -EFAULT on error.
+ * Return: zero on success, or -EFAULT on error.
  */
 #define put_user(x, ptr)                                       \
 ({                                                             \
@@ -502,7 +502,7 @@ struct __large_struct { unsigned long buf[100]; };
 } while (0)
 
 /**
- * __get_user: - Get a simple variable from user space, with less checking.
+ * __get_user - Get a simple variable from user space, with less checking.
  * @x:   Variable to store result.
  * @ptr: Source address, in user space.
  *
@@ -519,7 +519,7 @@ struct __large_struct { unsigned long buf[100]; };
  * Caller must check the pointer with access_ok() before calling this
  * function.
  *
- * Returns zero on success, or -EFAULT on error.
+ * Return: zero on success, or -EFAULT on error.
  * On error, the variable @x is set to zero.
  */
 
@@ -527,7 +527,7 @@ struct __large_struct { unsigned long buf[100]; };
        __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
 
 /**
- * __put_user: - Write a simple value into user space, with less checking.
+ * __put_user - Write a simple value into user space, with less checking.
  * @x:   Value to copy to user space.
  * @ptr: Destination address, in user space.
  *
@@ -544,7 +544,7 @@ struct __large_struct { unsigned long buf[100]; };
  * Caller must check the pointer with access_ok() before calling this
  * function.
  *
- * Returns zero on success, or -EFAULT on error.
+ * Return: zero on success, or -EFAULT on error.
  */
 
 #define __put_user(x, ptr)                                             \
index a555da094157096a50668940dc550b7f7f62ddb7..1e225528f0d7f4a1226dec1bdfba0920fa7da4d3 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/crash_dump.h>
 #include <linux/reboot.h>
 #include <linux/memory.h>
+#include <linux/numa.h>
 
 #include <asm/uv/uv_mmrs.h>
 #include <asm/uv/uv_hub.h>
@@ -1390,7 +1391,7 @@ static void __init build_socket_tables(void)
        }
 
        /* Set socket -> node values: */
-       lnid = -1;
+       lnid = NUMA_NO_NODE;
        for_each_present_cpu(cpu) {
                int nid = cpu_to_node(cpu);
                int apicid, sockid;
@@ -1521,7 +1522,7 @@ static void __init uv_system_init_hub(void)
                        new_hub->pnode = 0xffff;
 
                new_hub->numa_blade_id = uv_node_to_blade_id(nodeid);
-               new_hub->memory_nid = -1;
+               new_hub->memory_nid = NUMA_NO_NODE;
                new_hub->nr_possible_cpus = 0;
                new_hub->nr_online_cpus = 0;
        }
@@ -1538,7 +1539,7 @@ static void __init uv_system_init_hub(void)
 
                uv_cpu_info_per(cpu)->p_uv_hub_info = uv_hub_info_list(nodeid);
                uv_cpu_info_per(cpu)->blade_cpu_id = uv_cpu_hub_info(cpu)->nr_possible_cpus++;
-               if (uv_cpu_hub_info(cpu)->memory_nid == -1)
+               if (uv_cpu_hub_info(cpu)->memory_nid == NUMA_NO_NODE)
                        uv_cpu_hub_info(cpu)->memory_nid = cpu_to_node(cpu);
 
                /* Init memoryless node: */
index e8796fcd7e5a5ec2be8608a7c43ba78fc34b4e6f..13af08827eefc61e4252f7ffc6cc014f661e1f27 100644 (file)
@@ -171,7 +171,7 @@ void __init setup_per_cpu_areas(void)
        unsigned long delta;
        int rc;
 
-       pr_info("NR_CPUS:%d nr_cpumask_bits:%d nr_cpu_ids:%u nr_node_ids:%d\n",
+       pr_info("NR_CPUS:%d nr_cpumask_bits:%d nr_cpu_ids:%u nr_node_ids:%u\n",
                NR_CPUS, nr_cpumask_bits, nr_cpu_ids, nr_node_ids);
 
        /*
index ccd1f2a8e5577e9ef3a7dea410029b9daa0e1b8b..c91ff9f9fe8a7cde3f081698beda1ebeef9b9797 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/stackprotector.h>
 #include <linux/gfp.h>
 #include <linux/cpuidle.h>
+#include <linux/numa.h>
 
 #include <asm/acpi.h>
 #include <asm/desc.h>
@@ -841,7 +842,7 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
 /* reduce the number of lines printed when booting a large cpu count system */
 static void announce_cpu(int cpu, int apicid)
 {
-       static int current_node = -1;
+       static int current_node = NUMA_NO_NODE;
        int node = early_cpu_to_node(cpu);
        static int width, node_width;
 
index bfd94e7812fcb8642817784ab7be3032fa95ef37..7d290777246d202f36747c74be866ae3724e7f48 100644 (file)
@@ -54,13 +54,13 @@ do {                                                                        \
 } while (0)
 
 /**
- * clear_user: - Zero a block of memory in user space.
+ * clear_user - Zero a block of memory in user space.
  * @to:   Destination address, in user space.
  * @n:    Number of bytes to zero.
  *
  * Zero a block of memory in user space.
  *
- * Returns number of bytes that could not be cleared.
+ * Return: number of bytes that could not be cleared.
  * On success, this will be zero.
  */
 unsigned long
@@ -74,14 +74,14 @@ clear_user(void __user *to, unsigned long n)
 EXPORT_SYMBOL(clear_user);
 
 /**
- * __clear_user: - Zero a block of memory in user space, with less checking.
+ * __clear_user - Zero a block of memory in user space, with less checking.
  * @to:   Destination address, in user space.
  * @n:    Number of bytes to zero.
  *
  * Zero a block of memory in user space.  Caller must check
  * the specified block with access_ok() before calling this function.
  *
- * Returns number of bytes that could not be cleared.
+ * Return: number of bytes that could not be cleared.
  * On success, this will be zero.
  */
 unsigned long
index 1308f5408bf74881f89c5b323a465e23ac83177f..12c1b7a83ed7b03145ed487e1fbe54a8f60c78cd 100644 (file)
@@ -123,7 +123,7 @@ void __init setup_node_to_cpumask_map(void)
                alloc_bootmem_cpumask_var(&node_to_cpumask_map[node]);
 
        /* cpumask_of_node() will now work */
-       pr_debug("Node to cpumask map for %d nodes\n", nr_node_ids);
+       pr_debug("Node to cpumask map for %u nodes\n", nr_node_ids);
 }
 
 static int __init numa_add_memblk_to(int nid, u64 start, u64 end,
@@ -866,7 +866,7 @@ const struct cpumask *cpumask_of_node(int node)
 {
        if (node >= nr_node_ids) {
                printk(KERN_WARNING
-                       "cpumask_of_node(%d): node > nr_node_ids(%d)\n",
+                       "cpumask_of_node(%d): node > nr_node_ids(%u)\n",
                        node, nr_node_ids);
                dump_stack();
                return cpu_none_mask;
index a7e47cf7ec6cdc2eb709188d47829a415bbbffec..6e4c6bd622033bf0ebd8fdd6722da05bf9f489fe 100644 (file)
@@ -17,8 +17,8 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
 
 void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
 
-pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
-void  xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
+pte_t xen_ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep);
+void  xen_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
                                  pte_t *ptep, pte_t pte);
 
 unsigned long xen_read_cr2_direct(void);
index 0f4fe206dcc2015ce212b19c8865b06f854fb3b1..856a85814f005e270354f265dbae95cc4c452f9c 100644 (file)
@@ -306,20 +306,20 @@ static void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
        __xen_set_pte(ptep, pteval);
 }
 
-pte_t xen_ptep_modify_prot_start(struct mm_struct *mm,
+pte_t xen_ptep_modify_prot_start(struct vm_area_struct *vma,
                                 unsigned long addr, pte_t *ptep)
 {
        /* Just return the pte as-is.  We preserve the bits on commit */
-       trace_xen_mmu_ptep_modify_prot_start(mm, addr, ptep, *ptep);
+       trace_xen_mmu_ptep_modify_prot_start(vma->vm_mm, addr, ptep, *ptep);
        return *ptep;
 }
 
-void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
+void xen_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
                                 pte_t *ptep, pte_t pte)
 {
        struct mmu_update u;
 
-       trace_xen_mmu_ptep_modify_prot_commit(mm, addr, ptep, pte);
+       trace_xen_mmu_ptep_modify_prot_commit(vma->vm_mm, addr, ptep, pte);
        xen_mc_batch();
 
        u.ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
index 88e8440e75c3f4a6e73383740e4d520133e352bb..2f3ee4d6af827645248f2d49f6e2de033782b044 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/export.h>
 #include <linux/debugfs.h>
 #include <linux/prefetch.h>
+#include <linux/numa.h>
 #include "mtip32xx.h"
 
 #define HW_CMD_SLOT_SZ         (MTIP_MAX_COMMAND_SLOTS * 32)
@@ -4018,9 +4019,9 @@ static int get_least_used_cpu_on_node(int node)
 /* Helper for selecting a node in round robin mode */
 static inline int mtip_get_next_rr_node(void)
 {
-       static int next_node = -1;
+       static int next_node = NUMA_NO_NODE;
 
-       if (next_node == -1) {
+       if (next_node == NUMA_NO_NODE) {
                next_node = first_online_node;
                return next_node;
        }
index 7f88490b5479c3f47341712d01f36095c0477b0e..c53f0f9ef5b0b2db8bcd835163ef30e0264b6c37 100644 (file)
@@ -163,7 +163,6 @@ static int efficeon_free_gatt_table(struct agp_bridge_data *bridge)
                unsigned long page = efficeon_private.l1_table[index];
                if (page) {
                        efficeon_private.l1_table[index] = 0;
-                       ClearPageReserved(virt_to_page((char *)page));
                        free_page(page);
                        freed++;
                }
@@ -219,7 +218,6 @@ static int efficeon_create_gatt_table(struct agp_bridge_data *bridge)
                        efficeon_free_gatt_table(agp_bridge);
                        return -ENOMEM;
                }
-               SetPageReserved(virt_to_page((char *)page));
 
                for (offset = 0; offset < PAGE_SIZE; offset += clflush_chunk)
                        clflush((char *)page+offset);
index f1a441ab395d7529ebbc4f8d59e891e20c61419d..3a11b1092e807bb8a7d7ec1422a6e5367298ee25 100644 (file)
@@ -63,6 +63,7 @@
 #include <linux/acpi_dma.h>
 #include <linux/of_dma.h>
 #include <linux/mempool.h>
+#include <linux/numa.h>
 
 static DEFINE_MUTEX(dma_list_mutex);
 static DEFINE_IDA(dma_ida);
@@ -386,7 +387,8 @@ EXPORT_SYMBOL(dma_issue_pending_all);
 static bool dma_chan_is_local(struct dma_chan *chan, int cpu)
 {
        int node = dev_to_node(chan->device->dev);
-       return node == -1 || cpumask_test_cpu(cpu, cpumask_of_node(node));
+       return node == NUMA_NO_NODE ||
+               cpumask_test_cpu(cpu, cpumask_of_node(node));
 }
 
 /**
index 9726df37c4c41b2ce2316a2fd6438363275e654c..540e20eb032c564d1c01d633c8564f8ccf2edca6 100644 (file)
@@ -123,12 +123,6 @@ static inline u64 ptr_to_u64(const void *ptr)
 
 #include <linux/list.h>
 
-static inline int list_is_first(const struct list_head *list,
-                               const struct list_head *head)
-{
-       return head->next == list;
-}
-
 static inline void __list_del_many(struct list_head *head,
                                   struct list_head *first)
 {
index 7c6349a50ef173421cdafea3b289ae9868da711e..dd475f3bcc8ae7c6926f427251650339958f1d4c 100644 (file)
@@ -681,8 +681,13 @@ static struct notifier_block hv_memory_nb = {
 /* Check if the particular page is backed and can be onlined and online it. */
 static void hv_page_online_one(struct hv_hotadd_state *has, struct page *pg)
 {
-       if (!has_pfn_is_backed(has, page_to_pfn(pg)))
+       if (!has_pfn_is_backed(has, page_to_pfn(pg))) {
+               if (!PageOffline(pg))
+                       __SetPageOffline(pg);
                return;
+       }
+       if (PageOffline(pg))
+               __ClearPageOffline(pg);
 
        /* This frame is currently backed; online the page. */
        __online_page_set_limits(pg);
@@ -771,7 +776,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
        }
 }
 
-static void hv_online_page(struct page *pg)
+static void hv_online_page(struct page *pg, unsigned int order)
 {
        struct hv_hotadd_state *has;
        unsigned long flags;
@@ -780,10 +785,11 @@ static void hv_online_page(struct page *pg)
        spin_lock_irqsave(&dm_device.ha_lock, flags);
        list_for_each_entry(has, &dm_device.ha_region_list, list) {
                /* The page belongs to a different HAS. */
-               if ((pfn < has->start_pfn) || (pfn >= has->end_pfn))
+               if ((pfn < has->start_pfn) ||
+                               (pfn + (1UL << order) > has->end_pfn))
                        continue;
 
-               hv_page_online_one(has, pg);
+               hv_bring_pgs_online(has, pfn, 1UL << order);
                break;
        }
        spin_unlock_irqrestore(&dm_device.ha_lock, flags);
@@ -1201,6 +1207,7 @@ static void free_balloon_pages(struct hv_dynmem_device *dm,
 
        for (i = 0; i < num_pages; i++) {
                pg = pfn_to_page(i + start_frame);
+               __ClearPageOffline(pg);
                __free_page(pg);
                dm->num_pages_ballooned--;
        }
@@ -1213,7 +1220,7 @@ static unsigned int alloc_balloon_pages(struct hv_dynmem_device *dm,
                                        struct dm_balloon_response *bl_resp,
                                        int alloc_unit)
 {
-       unsigned int i = 0;
+       unsigned int i, j;
        struct page *pg;
 
        if (num_pages < alloc_unit)
@@ -1245,6 +1252,10 @@ static unsigned int alloc_balloon_pages(struct hv_dynmem_device *dm,
                if (alloc_unit != 1)
                        split_page(pg, get_order(alloc_unit << PAGE_SHIFT));
 
+               /* mark all pages offline */
+               for (j = 0; j < (1 << get_order(alloc_unit << PAGE_SHIFT)); j++)
+                       __SetPageOffline(pg + j);
+
                bl_resp->range_count++;
                bl_resp->range_array[i].finfo.start_page =
                        page_to_pfn(pg);
index 2baf38cc1e231b00aaaf54ed5843a91ac9971b2f..4fe662c3bbc1cda401e95cf90afe366554e471c2 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/cpumask.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/numa.h>
 
 #include "hfi.h"
 #include "affinity.h"
@@ -777,7 +778,7 @@ void hfi1_dev_affinity_clean_up(struct hfi1_devdata *dd)
        _dev_comp_vect_cpu_mask_clean_up(dd, entry);
 unlock:
        mutex_unlock(&node_affinity.lock);
-       dd->node = -1;
+       dd->node = NUMA_NO_NODE;
 }
 
 /*
index 7835eb52e7c578dd3052bf50e702eb6466fd89c1..441b06e2a15432e270f92672c02509711b6d3ebf 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/printk.h>
 #include <linux/hrtimer.h>
 #include <linux/bitmap.h>
+#include <linux/numa.h>
 #include <rdma/rdma_vt.h>
 
 #include "hfi.h"
@@ -1303,7 +1304,7 @@ static struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev,
                dd->unit = ret;
                list_add(&dd->list, &hfi1_dev_list);
        }
-       dd->node = -1;
+       dd->node = NUMA_NO_NODE;
 
        spin_unlock_irqrestore(&hfi1_devs_lock, flags);
        idr_preload_end();
index 58dc70bffd5b87ec682984e3a9e8842b5dcfb68d..9c49300e9fb76ace67cee9930356794234de81d0 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/dmi.h>
 #include <linux/slab.h>
 #include <linux/iommu.h>
+#include <linux/numa.h>
 #include <asm/irq_remapping.h>
 #include <asm/iommu_table.h>
 
@@ -477,7 +478,7 @@ static int dmar_parse_one_rhsa(struct acpi_dmar_header *header, void *arg)
                        int node = acpi_map_pxm_to_node(rhsa->proximity_domain);
 
                        if (!node_online(node))
-                               node = -1;
+                               node = NUMA_NO_NODE;
                        drhd->iommu->node = node;
                        return 0;
                }
@@ -1062,7 +1063,7 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
        iommu->msagaw = msagaw;
        iommu->segment = drhd->segment;
 
-       iommu->node = -1;
+       iommu->node = NUMA_NO_NODE;
 
        ver = readl(iommu->reg + DMAR_VER_REG);
        pr_info("%s: reg_base_addr %llx ver %d:%d cap %llx ecap %llx\n",
index 78188bf7e90d7a42f6dbc263f2e412c77de92e0c..39a33dec4d0bc33a88fca0806a0c2bfab5c271f9 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/dma-contiguous.h>
 #include <linux/dma-direct.h>
 #include <linux/crash_dump.h>
+#include <linux/numa.h>
 #include <asm/irq_remapping.h>
 #include <asm/cacheflush.h>
 #include <asm/iommu.h>
@@ -1716,7 +1717,7 @@ static struct dmar_domain *alloc_domain(int flags)
                return NULL;
 
        memset(domain, 0, sizeof(*domain));
-       domain->nid = -1;
+       domain->nid = NUMA_NO_NODE;
        domain->flags = flags;
        domain->has_iotlb_device = false;
        INIT_LIST_HEAD(&domain->devices);
index 0441abe87880a303d54f4c8119d7e368afd87d91..9e443df44b3b4ee3901a5f857796246bac754e49 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/slab.h>
+#include <linux/numa.h>
 #include <asm/uv/uv_hub.h>
 #if defined CONFIG_X86_64
 #include <asm/uv/bios.h>
@@ -61,7 +62,7 @@ static struct xpc_heartbeat_uv *xpc_heartbeat_uv;
                                         XPC_NOTIFY_MSG_SIZE_UV)
 #define XPC_NOTIFY_IRQ_NAME            "xpc_notify"
 
-static int xpc_mq_node = -1;
+static int xpc_mq_node = NUMA_NO_NODE;
 
 static struct xpc_gru_mq_uv *xpc_activate_mq_uv;
 static struct xpc_gru_mq_uv *xpc_notify_mq_uv;
index f8240b87df2295a435a84b7aaa05631fad0550d4..869ec842729efd07076419b7eb74a6f40fc8df93 100644 (file)
@@ -556,6 +556,36 @@ vmballoon_page_in_frames(enum vmballoon_page_size_type page_size)
        return 1 << vmballoon_page_order(page_size);
 }
 
+/**
+ * vmballoon_mark_page_offline() - mark a page as offline
+ * @page: pointer for the page.
+ * @page_size: the size of the page.
+ */
+static void
+vmballoon_mark_page_offline(struct page *page,
+                           enum vmballoon_page_size_type page_size)
+{
+       int i;
+
+       for (i = 0; i < vmballoon_page_in_frames(page_size); i++)
+               __SetPageOffline(page + i);
+}
+
+/**
+ * vmballoon_mark_page_online() - mark a page as online
+ * @page: pointer for the page.
+ * @page_size: the size of the page.
+ */
+static void
+vmballoon_mark_page_online(struct page *page,
+                          enum vmballoon_page_size_type page_size)
+{
+       int i;
+
+       for (i = 0; i < vmballoon_page_in_frames(page_size); i++)
+               __ClearPageOffline(page + i);
+}
+
 /**
  * vmballoon_send_get_target() - Retrieve desired balloon size from the host.
  *
@@ -612,6 +642,7 @@ static int vmballoon_alloc_page_list(struct vmballoon *b,
                                         ctl->page_size);
 
                if (page) {
+                       vmballoon_mark_page_offline(page, ctl->page_size);
                        /* Success. Add the page to the list and continue. */
                        list_add(&page->lru, &ctl->pages);
                        continue;
@@ -850,6 +881,7 @@ static void vmballoon_release_page_list(struct list_head *page_list,
 
        list_for_each_entry_safe(page, tmp, page_list, lru) {
                list_del(&page->lru);
+               vmballoon_mark_page_online(page, page_size);
                __free_pages(page, vmballoon_page_order(page_size));
        }
 
index a4e7584a50cba71bbd4993ee787748c2aed321df..e100054a3765e2f16c4aba9f3af8411c9dcdca4a 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/bpf.h>
 #include <linux/bpf_trace.h>
 #include <linux/atomic.h>
+#include <linux/numa.h>
 #include <scsi/fc/fc_fcoe.h>
 #include <net/udp_tunnel.h>
 #include <net/pkt_cls.h>
@@ -6418,7 +6419,7 @@ int ixgbe_setup_tx_resources(struct ixgbe_ring *tx_ring)
 {
        struct device *dev = tx_ring->dev;
        int orig_node = dev_to_node(dev);
-       int ring_node = -1;
+       int ring_node = NUMA_NO_NODE;
        int size;
 
        size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count;
@@ -6512,7 +6513,7 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
 {
        struct device *dev = rx_ring->dev;
        int orig_node = dev_to_node(dev);
-       int ring_node = -1;
+       int ring_node = NUMA_NO_NODE;
        int size;
 
        size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count;
index ceb5048de9a7eb8f2e861380964ebf3c15f8a23a..39b229f9e256e3ab23a5ee739f5ebd80ac55f515 100644 (file)
@@ -369,14 +369,20 @@ static enum bp_state reserve_additional_memory(void)
        return BP_ECANCELED;
 }
 
-static void xen_online_page(struct page *page)
+static void xen_online_page(struct page *page, unsigned int order)
 {
-       __online_page_set_limits(page);
+       unsigned long i, size = (1 << order);
+       unsigned long start_pfn = page_to_pfn(page);
+       struct page *p;
 
+       pr_debug("Online %lu pages starting at pfn 0x%lx\n", size, start_pfn);
        mutex_lock(&balloon_mutex);
-
-       __balloon_append(page);
-
+       for (i = 0; i < size; i++) {
+               p = pfn_to_page(start_pfn + i);
+               __online_page_set_limits(p);
+               __SetPageOffline(p);
+               __balloon_append(p);
+       }
        mutex_unlock(&balloon_mutex);
 }
 
@@ -441,6 +447,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages)
                xenmem_reservation_va_mapping_update(1, &page, &frame_list[i]);
 
                /* Relinquish the page back to the allocator. */
+               __ClearPageOffline(page);
                free_reserved_page(page);
        }
 
@@ -467,6 +474,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
                        state = BP_EAGAIN;
                        break;
                }
+               __SetPageOffline(page);
                adjust_managed_page_count(page, -1);
                xenmem_reservation_scrub_page(page);
                list_add(&page->lru, &pages);
index 3209ee271c41d15f0138164fd822e236e5125560..a10487aa0a84359e42e689a3de941dacb20749e5 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -457,6 +457,7 @@ struct files_struct init_files = {
                .full_fds_bits  = init_files.full_fds_bits_init,
        },
        .file_lock      = __SPIN_LOCK_UNLOCKED(init_files.file_lock),
+       .resize_wait    = __WAIT_QUEUE_HEAD_INITIALIZER(init_files.resize_wait),
 };
 
 static unsigned int find_next_fd(struct fdtable *fdt, unsigned int start)
index a7fa037b876b7fa32afcc891345cd44f0315b4f9..b0eef008de67f877096dc5f83604c7307cdb92e3 100644 (file)
@@ -530,7 +530,7 @@ static long hugetlbfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
                inode_lock(inode);
 
                /* protected by i_mutex */
-               if (info->seals & F_SEAL_WRITE) {
+               if (info->seals & (F_SEAL_WRITE | F_SEAL_FUTURE_WRITE)) {
                        inode_unlock(inode);
                        return -EPERM;
                }
index 73432e64f8746179e94bcd580984d78f40da823a..e9d97add2b36c9731a8d877e2fd32c7c2e1a382d 100644 (file)
@@ -2093,14 +2093,8 @@ EXPORT_SYMBOL(inode_dio_wait);
 void inode_set_flags(struct inode *inode, unsigned int flags,
                     unsigned int mask)
 {
-       unsigned int old_flags, new_flags;
-
        WARN_ON_ONCE(flags & ~mask);
-       do {
-               old_flags = READ_ONCE(inode->i_flags);
-               new_flags = (old_flags & ~mask) | flags;
-       } while (unlikely(cmpxchg(&inode->i_flags, old_flags,
-                                 new_flags) != old_flags));
+       set_mask_bits(&inode->i_flags, mask, flags);
 }
 EXPORT_SYMBOL(inode_set_flags);
 
index f8d5021a652ead80f898ea5d4c421821ab8bae3b..ae948aaa4c5352ef57cc507262464dc9514e1e10 100644 (file)
@@ -832,26 +832,35 @@ void kernfs_drain_open_files(struct kernfs_node *kn)
  * to see if it supports poll (Neither 'poll' nor 'select' return
  * an appropriate error code).  When in doubt, set a suitable timeout value.
  */
+__poll_t kernfs_generic_poll(struct kernfs_open_file *of, poll_table *wait)
+{
+       struct kernfs_node *kn = kernfs_dentry_node(of->file->f_path.dentry);
+       struct kernfs_open_node *on = kn->attr.open;
+
+       poll_wait(of->file, &on->poll, wait);
+
+       if (of->event != atomic_read(&on->event))
+               return DEFAULT_POLLMASK|EPOLLERR|EPOLLPRI;
+
+       return DEFAULT_POLLMASK;
+}
+
 static __poll_t kernfs_fop_poll(struct file *filp, poll_table *wait)
 {
        struct kernfs_open_file *of = kernfs_of(filp);
        struct kernfs_node *kn = kernfs_dentry_node(filp->f_path.dentry);
-       struct kernfs_open_node *on = kn->attr.open;
+       __poll_t ret;
 
        if (!kernfs_get_active(kn))
-               goto trigger;
+               return DEFAULT_POLLMASK|EPOLLERR|EPOLLPRI;
 
-       poll_wait(filp, &on->poll, wait);
+       if (kn->attr.ops->poll)
+               ret = kn->attr.ops->poll(of, wait);
+       else
+               ret = kernfs_generic_poll(of, wait);
 
        kernfs_put_active(kn);
-
-       if (of->event != atomic_read(&on->event))
-               goto trigger;
-
-       return DEFAULT_POLLMASK;
-
- trigger:
-       return DEFAULT_POLLMASK|EPOLLERR|EPOLLPRI;
+       return ret;
 }
 
 static void kernfs_notify_workfn(struct work_struct *work)
index d1cbb27808e27597592538a176d99e388a5d2705..6f0999015a44e536b89fec658bf931437558a9aa 100644 (file)
@@ -7532,10 +7532,11 @@ static int ocfs2_trim_group(struct super_block *sb,
        return count;
 }
 
-int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range)
+static
+int ocfs2_trim_mainbm(struct super_block *sb, struct fstrim_range *range)
 {
        struct ocfs2_super *osb = OCFS2_SB(sb);
-       u64 start, len, trimmed, first_group, last_group, group;
+       u64 start, len, trimmed = 0, first_group, last_group = 0, group = 0;
        int ret, cnt;
        u32 first_bit, last_bit, minlen;
        struct buffer_head *main_bm_bh = NULL;
@@ -7543,7 +7544,6 @@ int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range)
        struct buffer_head *gd_bh = NULL;
        struct ocfs2_dinode *main_bm;
        struct ocfs2_group_desc *gd = NULL;
-       struct ocfs2_trim_fs_info info, *pinfo = NULL;
 
        start = range->start >> osb->s_clustersize_bits;
        len = range->len >> osb->s_clustersize_bits;
@@ -7552,6 +7552,9 @@ int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range)
        if (minlen >= osb->bitmap_cpg || range->len < sb->s_blocksize)
                return -EINVAL;
 
+       trace_ocfs2_trim_mainbm(start, len, minlen);
+
+next_group:
        main_bm_inode = ocfs2_get_system_file_inode(osb,
                                                    GLOBAL_BITMAP_SYSTEM_INODE,
                                                    OCFS2_INVALID_SLOT);
@@ -7570,64 +7573,34 @@ int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range)
        }
        main_bm = (struct ocfs2_dinode *)main_bm_bh->b_data;
 
-       if (start >= le32_to_cpu(main_bm->i_clusters)) {
-               ret = -EINVAL;
-               goto out_unlock;
-       }
-
-       len = range->len >> osb->s_clustersize_bits;
-       if (start + len > le32_to_cpu(main_bm->i_clusters))
-               len = le32_to_cpu(main_bm->i_clusters) - start;
-
-       trace_ocfs2_trim_fs(start, len, minlen);
-
-       ocfs2_trim_fs_lock_res_init(osb);
-       ret = ocfs2_trim_fs_lock(osb, NULL, 1);
-       if (ret < 0) {
-               if (ret != -EAGAIN) {
-                       mlog_errno(ret);
-                       ocfs2_trim_fs_lock_res_uninit(osb);
+       /*
+        * Do some check before trim the first group.
+        */
+       if (!group) {
+               if (start >= le32_to_cpu(main_bm->i_clusters)) {
+                       ret = -EINVAL;
                        goto out_unlock;
                }
 
-               mlog(ML_NOTICE, "Wait for trim on device (%s) to "
-                    "finish, which is running from another node.\n",
-                    osb->dev_str);
-               ret = ocfs2_trim_fs_lock(osb, &info, 0);
-               if (ret < 0) {
-                       mlog_errno(ret);
-                       ocfs2_trim_fs_lock_res_uninit(osb);
-                       goto out_unlock;
-               }
+               if (start + len > le32_to_cpu(main_bm->i_clusters))
+                       len = le32_to_cpu(main_bm->i_clusters) - start;
 
-               if (info.tf_valid && info.tf_success &&
-                   info.tf_start == start && info.tf_len == len &&
-                   info.tf_minlen == minlen) {
-                       /* Avoid sending duplicated trim to a shared device */
-                       mlog(ML_NOTICE, "The same trim on device (%s) was "
-                            "just done from node (%u), return.\n",
-                            osb->dev_str, info.tf_nodenum);
-                       range->len = info.tf_trimlen;
-                       goto out_trimunlock;
-               }
+               /*
+                * Determine first and last group to examine based on
+                * start and len
+                */
+               first_group = ocfs2_which_cluster_group(main_bm_inode, start);
+               if (first_group == osb->first_cluster_group_blkno)
+                       first_bit = start;
+               else
+                       first_bit = start - ocfs2_blocks_to_clusters(sb,
+                                                               first_group);
+               last_group = ocfs2_which_cluster_group(main_bm_inode,
+                                                      start + len - 1);
+               group = first_group;
        }
 
-       info.tf_nodenum = osb->node_num;
-       info.tf_start = start;
-       info.tf_len = len;
-       info.tf_minlen = minlen;
-
-       /* Determine first and last group to examine based on start and len */
-       first_group = ocfs2_which_cluster_group(main_bm_inode, start);
-       if (first_group == osb->first_cluster_group_blkno)
-               first_bit = start;
-       else
-               first_bit = start - ocfs2_blocks_to_clusters(sb, first_group);
-       last_group = ocfs2_which_cluster_group(main_bm_inode, start + len - 1);
-       last_bit = osb->bitmap_cpg;
-
-       trimmed = 0;
-       for (group = first_group; group <= last_group;) {
+       do {
                if (first_bit + len >= osb->bitmap_cpg)
                        last_bit = osb->bitmap_cpg;
                else
@@ -7659,21 +7632,81 @@ int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range)
                        group = ocfs2_clusters_to_blocks(sb, osb->bitmap_cpg);
                else
                        group += ocfs2_clusters_to_blocks(sb, osb->bitmap_cpg);
-       }
-       range->len = trimmed * sb->s_blocksize;
+       } while (0);
 
-       info.tf_trimlen = range->len;
-       info.tf_success = (ret ? 0 : 1);
-       pinfo = &info;
-out_trimunlock:
-       ocfs2_trim_fs_unlock(osb, pinfo);
-       ocfs2_trim_fs_lock_res_uninit(osb);
 out_unlock:
        ocfs2_inode_unlock(main_bm_inode, 0);
        brelse(main_bm_bh);
+       main_bm_bh = NULL;
 out_mutex:
        inode_unlock(main_bm_inode);
        iput(main_bm_inode);
+
+       /*
+        * If all the groups trim are not done or failed, but we should release
+        * main_bm related locks for avoiding the current IO starve, then go to
+        * trim the next group
+        */
+       if (ret >= 0 && group <= last_group)
+               goto next_group;
 out:
+       range->len = trimmed * sb->s_blocksize;
+       return ret;
+}
+
+int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range)
+{
+       int ret;
+       struct ocfs2_super *osb = OCFS2_SB(sb);
+       struct ocfs2_trim_fs_info info, *pinfo = NULL;
+
+       ocfs2_trim_fs_lock_res_init(osb);
+
+       trace_ocfs2_trim_fs(range->start, range->len, range->minlen);
+
+       ret = ocfs2_trim_fs_lock(osb, NULL, 1);
+       if (ret < 0) {
+               if (ret != -EAGAIN) {
+                       mlog_errno(ret);
+                       ocfs2_trim_fs_lock_res_uninit(osb);
+                       return ret;
+               }
+
+               mlog(ML_NOTICE, "Wait for trim on device (%s) to "
+                    "finish, which is running from another node.\n",
+                    osb->dev_str);
+               ret = ocfs2_trim_fs_lock(osb, &info, 0);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       ocfs2_trim_fs_lock_res_uninit(osb);
+                       return ret;
+               }
+
+               if (info.tf_valid && info.tf_success &&
+                   info.tf_start == range->start &&
+                   info.tf_len == range->len &&
+                   info.tf_minlen == range->minlen) {
+                       /* Avoid sending duplicated trim to a shared device */
+                       mlog(ML_NOTICE, "The same trim on device (%s) was "
+                            "just done from node (%u), return.\n",
+                            osb->dev_str, info.tf_nodenum);
+                       range->len = info.tf_trimlen;
+                       goto out;
+               }
+       }
+
+       info.tf_nodenum = osb->node_num;
+       info.tf_start = range->start;
+       info.tf_len = range->len;
+       info.tf_minlen = range->minlen;
+
+       ret = ocfs2_trim_mainbm(sb, range);
+
+       info.tf_trimlen = range->len;
+       info.tf_success = (ret < 0 ? 0 : 1);
+       pinfo = &info;
+out:
+       ocfs2_trim_fs_unlock(osb, pinfo);
+       ocfs2_trim_fs_lock_res_uninit(osb);
        return ret;
 }
index 0e4166cc23a0a1fe90528a66afb8c77a23b8a294..4ac775e32240f4c629c96febeb1e0de83b2133d0 100644 (file)
@@ -621,13 +621,15 @@ static void o2nm_node_group_drop_item(struct config_group *group,
        struct o2nm_node *node = to_o2nm_node(item);
        struct o2nm_cluster *cluster = to_o2nm_cluster(group->cg_item.ci_parent);
 
-       o2net_disconnect_node(node);
+       if (cluster->cl_nodes[node->nd_num] == node) {
+               o2net_disconnect_node(node);
 
-       if (cluster->cl_has_local &&
-           (cluster->cl_local_node == node->nd_num)) {
-               cluster->cl_has_local = 0;
-               cluster->cl_local_node = O2NM_INVALID_NODE_NUM;
-               o2net_stop_listening(node);
+               if (cluster->cl_has_local &&
+                   (cluster->cl_local_node == node->nd_num)) {
+                       cluster->cl_has_local = 0;
+                       cluster->cl_local_node = O2NM_INVALID_NODE_NUM;
+                       o2net_stop_listening(node);
+               }
        }
 
        /* XXX call into net to stop this node from trading messages */
index 7c835824247eb7a64446467b03080f07f67aa90e..af405586c5b111f5ddb4612728131e28d597f8fe 100644 (file)
@@ -686,6 +686,9 @@ void ocfs2_trim_fs_lock_res_init(struct ocfs2_super *osb)
 {
        struct ocfs2_lock_res *lockres = &osb->osb_trim_fs_lockres;
 
+       /* Only one trimfs thread are allowed to work at the same time. */
+       mutex_lock(&osb->obs_trim_fs_mutex);
+
        ocfs2_lock_res_init_once(lockres);
        ocfs2_build_lock_name(OCFS2_LOCK_TYPE_TRIM_FS, 0, 0, lockres->l_name);
        ocfs2_lock_res_init_common(osb, lockres, OCFS2_LOCK_TYPE_TRIM_FS,
@@ -698,6 +701,8 @@ void ocfs2_trim_fs_lock_res_uninit(struct ocfs2_super *osb)
 
        ocfs2_simple_drop_lockres(osb, lockres);
        ocfs2_lock_res_free(lockres);
+
+       mutex_unlock(&osb->obs_trim_fs_mutex);
 }
 
 static void ocfs2_orphan_scan_lock_res_init(struct ocfs2_lock_res *res,
index 4f86ac0027b5ba376495e3bf859c8e8f57ccf452..1f029fbe8b8d1d210ee7ebe70294246c87885fe9 100644 (file)
@@ -407,6 +407,7 @@ struct ocfs2_super
        struct ocfs2_lock_res osb_rename_lockres;
        struct ocfs2_lock_res osb_nfs_sync_lockres;
        struct ocfs2_lock_res osb_trim_fs_lockres;
+       struct mutex obs_trim_fs_mutex;
        struct ocfs2_dlm_debug *osb_dlm_debug;
 
        struct dentry *osb_debug_root;
index 2ee76a90ba8f7406548da0b15bcc8624a332ae73..dc4bce1649c1bc36563499d1da8d84a862257782 100644 (file)
@@ -712,6 +712,8 @@ TRACE_EVENT(ocfs2_trim_extent,
 
 DEFINE_OCFS2_ULL_UINT_UINT_UINT_EVENT(ocfs2_trim_group);
 
+DEFINE_OCFS2_ULL_ULL_ULL_EVENT(ocfs2_trim_mainbm);
+
 DEFINE_OCFS2_ULL_ULL_ULL_EVENT(ocfs2_trim_fs);
 
 /* End of trace events for fs/ocfs2/alloc.c. */
index d7407994f308076fbb8690f00419f5e663aa9bea..ea0756d8325091dca7bd75183e74c3c264554f0c 100644 (file)
@@ -55,7 +55,7 @@ struct ocfs2_slot_info {
        unsigned int si_blocks;
        struct buffer_head **si_bh;
        unsigned int si_num_slots;
-       struct ocfs2_slot *si_slots;
+       struct ocfs2_slot si_slots[];
 };
 
 
@@ -420,9 +420,7 @@ int ocfs2_init_slot_info(struct ocfs2_super *osb)
        struct inode *inode = NULL;
        struct ocfs2_slot_info *si;
 
-       si = kzalloc(sizeof(struct ocfs2_slot_info) +
-                    (sizeof(struct ocfs2_slot) * osb->max_slots),
-                    GFP_KERNEL);
+       si = kzalloc(struct_size(si, si_slots, osb->max_slots), GFP_KERNEL);
        if (!si) {
                status = -ENOMEM;
                mlog_errno(status);
@@ -431,8 +429,6 @@ int ocfs2_init_slot_info(struct ocfs2_super *osb)
 
        si->si_extended = ocfs2_uses_extended_slot_map(osb);
        si->si_num_slots = osb->max_slots;
-       si->si_slots = (struct ocfs2_slot *)((char *)si +
-                                            sizeof(struct ocfs2_slot_info));
 
        inode = ocfs2_get_system_file_inode(osb, SLOT_MAP_SYSTEM_INODE,
                                            OCFS2_INVALID_SLOT);
index 3415e0b09398fb50a813499f14596db104cd414c..96ae7cedd487931ca8d1af33270763c9e186931b 100644 (file)
@@ -1847,6 +1847,8 @@ static int ocfs2_mount_volume(struct super_block *sb)
        if (ocfs2_is_hard_readonly(osb))
                goto leave;
 
+       mutex_init(&osb->obs_trim_fs_mutex);
+
        status = ocfs2_dlm_init(osb);
        if (status < 0) {
                mlog_errno(status);
index bdc5d3c0977d09b37d5eb80abfb92c3a336f6c92..51d5fd8840abd895b7d39c8ca0c22770615bfa7b 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -140,8 +140,7 @@ static int anon_pipe_buf_steal(struct pipe_inode_info *pipe,
        struct page *page = buf->page;
 
        if (page_count(page) == 1) {
-               if (memcg_kmem_enabled())
-                       memcg_kmem_uncharge(page, 0);
+               memcg_kmem_uncharge(page, 0);
                __SetPageLocked(page);
                return 0;
        }
index 9d428d5a0ac88c4a2ca65f3d74eba922ee72f3a8..2edbb657f859bff9528eff4b83dc14da121b17e0 100644 (file)
@@ -343,28 +343,28 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p)
 #ifdef CONFIG_SECCOMP
        seq_put_decimal_ull(m, "\nSeccomp:\t", p->seccomp.mode);
 #endif
-       seq_printf(m, "\nSpeculation_Store_Bypass:\t");
+       seq_puts(m, "\nSpeculation_Store_Bypass:\t");
        switch (arch_prctl_spec_ctrl_get(p, PR_SPEC_STORE_BYPASS)) {
        case -EINVAL:
-               seq_printf(m, "unknown");
+               seq_puts(m, "unknown");
                break;
        case PR_SPEC_NOT_AFFECTED:
-               seq_printf(m, "not vulnerable");
+               seq_puts(m, "not vulnerable");
                break;
        case PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE:
-               seq_printf(m, "thread force mitigated");
+               seq_puts(m, "thread force mitigated");
                break;
        case PR_SPEC_PRCTL | PR_SPEC_DISABLE:
-               seq_printf(m, "thread mitigated");
+               seq_puts(m, "thread mitigated");
                break;
        case PR_SPEC_PRCTL | PR_SPEC_ENABLE:
-               seq_printf(m, "thread vulnerable");
+               seq_puts(m, "thread vulnerable");
                break;
        case PR_SPEC_DISABLE:
-               seq_printf(m, "globally mitigated");
+               seq_puts(m, "globally mitigated");
                break;
        default:
-               seq_printf(m, "vulnerable");
+               seq_puts(m, "vulnerable");
                break;
        }
        seq_putc(m, '\n');
index f5ed9512d193a2d93df6fc54cd2202ad3367fb41..511b279ec69cdce7a3e434d9d9152fd95678bd36 100644 (file)
@@ -456,7 +456,7 @@ static int proc_pid_schedstat(struct seq_file *m, struct pid_namespace *ns,
                              struct pid *pid, struct task_struct *task)
 {
        if (unlikely(!sched_info_on()))
-               seq_printf(m, "0 0 0\n");
+               seq_puts(m, "0 0 0\n");
        else
                seq_printf(m, "%llu %llu %lu\n",
                   (unsigned long long)task->se.sum_exec_runtime,
@@ -3161,7 +3161,7 @@ static struct dentry *proc_pid_instantiate(struct dentry * dentry,
        return d_splice_alias(inode, dentry);
 }
 
-struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
+struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
 {
        struct task_struct *task;
        unsigned tgid;
index 95b14196f28420934f9fe091854809151e5f39d3..4fc5a9b68f76d8d1f9498aacef8920eb42ffc9b3 100644 (file)
@@ -162,7 +162,7 @@ extern struct inode *proc_pid_make_inode(struct super_block *, struct task_struc
 extern void pid_update_inode(struct task_struct *, struct inode *);
 extern int pid_delete_dentry(const struct dentry *);
 extern int proc_pid_readdir(struct file *, struct dir_context *);
-extern struct dentry *proc_pid_lookup(struct inode *, struct dentry *, unsigned int);
+struct dentry *proc_pid_lookup(struct dentry *, unsigned int);
 extern loff_t mem_lseek(struct file *, loff_t, int);
 
 /* Lookups */
index 40b05e0d427464aef7670d299b059aa50b322e94..544d1ee15aeece96efa3e5b39a9481c879584419 100644 (file)
@@ -152,8 +152,8 @@ u64 stable_page_flags(struct page *page)
        else if (page_count(page) == 0 && is_free_buddy_page(page))
                u |= 1 << KPF_BUDDY;
 
-       if (PageBalloon(page))
-               u |= 1 << KPF_BALLOON;
+       if (PageOffline(page))
+               u |= 1 << KPF_OFFLINE;
        if (PageTable(page))
                u |= 1 << KPF_PGTABLE;
 
index f4b1a9d2eca6010be2838197dc9741ec67a3857e..621e6ec322ca93032d915519717f995abfeaf266 100644 (file)
@@ -154,7 +154,7 @@ static int proc_root_getattr(const struct path *path, struct kstat *stat,
 
 static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags)
 {
-       if (!proc_pid_lookup(dir, dentry, flags))
+       if (!proc_pid_lookup(dentry, flags))
                return NULL;
        
        return proc_lookup(dir, dentry, flags);
index 127265e5c55f81d1ec3d780dad1e7b23f86a8caf..57c0a1047250be30f27004a1c4477365bef4bb33 100644 (file)
@@ -38,6 +38,7 @@ int proc_setup_self(struct super_block *s)
        struct inode *root_inode = d_inode(s->s_root);
        struct pid_namespace *ns = proc_pid_ns(root_inode);
        struct dentry *self;
+       int ret = -ENOMEM;
        
        inode_lock(root_inode);
        self = d_alloc_name(s->s_root, "self");
@@ -51,20 +52,19 @@ int proc_setup_self(struct super_block *s)
                        inode->i_gid = GLOBAL_ROOT_GID;
                        inode->i_op = &proc_self_inode_operations;
                        d_add(self, inode);
+                       ret = 0;
                } else {
                        dput(self);
-                       self = ERR_PTR(-ENOMEM);
                }
-       } else {
-               self = ERR_PTR(-ENOMEM);
        }
        inode_unlock(root_inode);
-       if (IS_ERR(self)) {
+
+       if (ret)
                pr_err("proc_fill_super: can't allocate /proc/self\n");
-               return PTR_ERR(self);
-       }
-       ns->proc_self = self;
-       return 0;
+       else
+               ns->proc_self = self;
+
+       return ret;
 }
 
 void __init proc_self_init(void)
index 76175211b304a6b9949ce719a10a35bfe8336d86..80c305f206bba89a9cb1e6b72074fdf9e1d0e713 100644 (file)
 
 #ifdef arch_idle_time
 
-static u64 get_idle_time(int cpu)
+static u64 get_idle_time(struct kernel_cpustat *kcs, int cpu)
 {
        u64 idle;
 
-       idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE];
+       idle = kcs->cpustat[CPUTIME_IDLE];
        if (cpu_online(cpu) && !nr_iowait_cpu(cpu))
                idle += arch_idle_time(cpu);
        return idle;
 }
 
-static u64 get_iowait_time(int cpu)
+static u64 get_iowait_time(struct kernel_cpustat *kcs, int cpu)
 {
        u64 iowait;
 
-       iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT];
+       iowait = kcs->cpustat[CPUTIME_IOWAIT];
        if (cpu_online(cpu) && nr_iowait_cpu(cpu))
                iowait += arch_idle_time(cpu);
        return iowait;
@@ -45,7 +45,7 @@ static u64 get_iowait_time(int cpu)
 
 #else
 
-static u64 get_idle_time(int cpu)
+static u64 get_idle_time(struct kernel_cpustat *kcs, int cpu)
 {
        u64 idle, idle_usecs = -1ULL;
 
@@ -54,14 +54,14 @@ static u64 get_idle_time(int cpu)
 
        if (idle_usecs == -1ULL)
                /* !NO_HZ or cpu offline so we can rely on cpustat.idle */
-               idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE];
+               idle = kcs->cpustat[CPUTIME_IDLE];
        else
                idle = idle_usecs * NSEC_PER_USEC;
 
        return idle;
 }
 
-static u64 get_iowait_time(int cpu)
+static u64 get_iowait_time(struct kernel_cpustat *kcs, int cpu)
 {
        u64 iowait, iowait_usecs = -1ULL;
 
@@ -70,7 +70,7 @@ static u64 get_iowait_time(int cpu)
 
        if (iowait_usecs == -1ULL)
                /* !NO_HZ or cpu offline so we can rely on cpustat.iowait */
-               iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT];
+               iowait = kcs->cpustat[CPUTIME_IOWAIT];
        else
                iowait = iowait_usecs * NSEC_PER_USEC;
 
@@ -120,16 +120,18 @@ static int show_stat(struct seq_file *p, void *v)
        getboottime64(&boottime);
 
        for_each_possible_cpu(i) {
-               user += kcpustat_cpu(i).cpustat[CPUTIME_USER];
-               nice += kcpustat_cpu(i).cpustat[CPUTIME_NICE];
-               system += kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM];
-               idle += get_idle_time(i);
-               iowait += get_iowait_time(i);
-               irq += kcpustat_cpu(i).cpustat[CPUTIME_IRQ];
-               softirq += kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ];
-               steal += kcpustat_cpu(i).cpustat[CPUTIME_STEAL];
-               guest += kcpustat_cpu(i).cpustat[CPUTIME_GUEST];
-               guest_nice += kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE];
+               struct kernel_cpustat *kcs = &kcpustat_cpu(i);
+
+               user += kcs->cpustat[CPUTIME_USER];
+               nice += kcs->cpustat[CPUTIME_NICE];
+               system += kcs->cpustat[CPUTIME_SYSTEM];
+               idle += get_idle_time(kcs, i);
+               iowait += get_iowait_time(kcs, i);
+               irq += kcs->cpustat[CPUTIME_IRQ];
+               softirq += kcs->cpustat[CPUTIME_SOFTIRQ];
+               steal += kcs->cpustat[CPUTIME_STEAL];
+               guest += kcs->cpustat[CPUTIME_GUEST];
+               guest_nice += kcs->cpustat[CPUTIME_GUEST_NICE];
                sum += kstat_cpu_irqs_sum(i);
                sum += arch_irq_stat_cpu(i);
 
@@ -155,17 +157,19 @@ static int show_stat(struct seq_file *p, void *v)
        seq_putc(p, '\n');
 
        for_each_online_cpu(i) {
+               struct kernel_cpustat *kcs = &kcpustat_cpu(i);
+
                /* Copy values here to work around gcc-2.95.3, gcc-2.96 */
-               user = kcpustat_cpu(i).cpustat[CPUTIME_USER];
-               nice = kcpustat_cpu(i).cpustat[CPUTIME_NICE];
-               system = kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM];
-               idle = get_idle_time(i);
-               iowait = get_iowait_time(i);
-               irq = kcpustat_cpu(i).cpustat[CPUTIME_IRQ];
-               softirq = kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ];
-               steal = kcpustat_cpu(i).cpustat[CPUTIME_STEAL];
-               guest = kcpustat_cpu(i).cpustat[CPUTIME_GUEST];
-               guest_nice = kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE];
+               user = kcs->cpustat[CPUTIME_USER];
+               nice = kcs->cpustat[CPUTIME_NICE];
+               system = kcs->cpustat[CPUTIME_SYSTEM];
+               idle = get_idle_time(kcs, i);
+               iowait = get_iowait_time(kcs, i);
+               irq = kcs->cpustat[CPUTIME_IRQ];
+               softirq = kcs->cpustat[CPUTIME_SOFTIRQ];
+               steal = kcs->cpustat[CPUTIME_STEAL];
+               guest = kcs->cpustat[CPUTIME_GUEST];
+               guest_nice = kcs->cpustat[CPUTIME_GUEST_NICE];
                seq_printf(p, "cpu%d", i);
                seq_put_decimal_ull(p, " ", nsec_to_clock_t(user));
                seq_put_decimal_ull(p, " ", nsec_to_clock_t(nice));
index 85b0ef890b280a8339673b391e058dc68d2fb81c..beccb0b1d57c77ca3462513ef9912822ff7740bc 100644 (file)
@@ -948,10 +948,12 @@ static inline void clear_soft_dirty(struct vm_area_struct *vma,
        pte_t ptent = *pte;
 
        if (pte_present(ptent)) {
-               ptent = ptep_modify_prot_start(vma->vm_mm, addr, pte);
-               ptent = pte_wrprotect(ptent);
+               pte_t old_pte;
+
+               old_pte = ptep_modify_prot_start(vma, addr, pte);
+               ptent = pte_wrprotect(old_pte);
                ptent = pte_clear_soft_dirty(ptent);
-               ptep_modify_prot_commit(vma->vm_mm, addr, pte, ptent);
+               ptep_modify_prot_commit(vma, addr, pte, old_pte, ptent);
        } else if (is_swap_pte(ptent)) {
                ptent = pte_swp_clear_soft_dirty(ptent);
                set_pte_at(vma->vm_mm, addr, pte, ptent);
index f912872fbf9139e06096972cdedab2ebee0d3377..36bf0f2e102e7811d8e8b6bee41a64cb64b65930 100644 (file)
@@ -178,7 +178,7 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
                seq_file_path(m, file, "");
        } else if (mm && is_stack(vma)) {
                seq_pad(m, ' ');
-               seq_printf(m, "[stack]");
+               seq_puts(m, "[stack]");
        }
 
        seq_putc(m, '\n');
index b905010ca9ebafe098766a66af8f99d96e4f4237..f61ae53533f58af35dcf14c64131c44e55f6a780 100644 (file)
@@ -38,6 +38,7 @@ int proc_setup_thread_self(struct super_block *s)
        struct inode *root_inode = d_inode(s->s_root);
        struct pid_namespace *ns = proc_pid_ns(root_inode);
        struct dentry *thread_self;
+       int ret = -ENOMEM;
 
        inode_lock(root_inode);
        thread_self = d_alloc_name(s->s_root, "thread-self");
@@ -51,20 +52,19 @@ int proc_setup_thread_self(struct super_block *s)
                        inode->i_gid = GLOBAL_ROOT_GID;
                        inode->i_op = &proc_thread_self_inode_operations;
                        d_add(thread_self, inode);
+                       ret = 0;
                } else {
                        dput(thread_self);
-                       thread_self = ERR_PTR(-ENOMEM);
                }
-       } else {
-               thread_self = ERR_PTR(-ENOMEM);
        }
        inode_unlock(root_inode);
-       if (IS_ERR(thread_self)) {
+
+       if (ret)
                pr_err("proc_fill_super: can't allocate /proc/thread_self\n");
-               return PTR_ERR(thread_self);
-       }
-       ns->proc_thread_self = thread_self;
-       return 0;
+       else
+               ns->proc_thread_self = thread_self;
+
+       return ret;
 }
 
 void __init proc_thread_self_init(void)
index 05e61e6c843f3d82f935c4bdefbc721f659a4ea7..fa782fba51eebac4a3776ed1c9565abbeeb309c6 100644 (file)
@@ -606,7 +606,7 @@ static inline int pmd_none_or_clear_bad(pmd_t *pmd)
        return 0;
 }
 
-static inline pte_t __ptep_modify_prot_start(struct mm_struct *mm,
+static inline pte_t __ptep_modify_prot_start(struct vm_area_struct *vma,
                                             unsigned long addr,
                                             pte_t *ptep)
 {
@@ -615,10 +615,10 @@ static inline pte_t __ptep_modify_prot_start(struct mm_struct *mm,
         * non-present, preventing the hardware from asynchronously
         * updating it.
         */
-       return ptep_get_and_clear(mm, addr, ptep);
+       return ptep_get_and_clear(vma->vm_mm, addr, ptep);
 }
 
-static inline void __ptep_modify_prot_commit(struct mm_struct *mm,
+static inline void __ptep_modify_prot_commit(struct vm_area_struct *vma,
                                             unsigned long addr,
                                             pte_t *ptep, pte_t pte)
 {
@@ -626,7 +626,7 @@ static inline void __ptep_modify_prot_commit(struct mm_struct *mm,
         * The pte is non-present, so there's no hardware state to
         * preserve.
         */
-       set_pte_at(mm, addr, ptep, pte);
+       set_pte_at(vma->vm_mm, addr, ptep, pte);
 }
 
 #ifndef __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
@@ -644,22 +644,22 @@ static inline void __ptep_modify_prot_commit(struct mm_struct *mm,
  * queue the update to be done at some later time.  The update must be
  * actually committed before the pte lock is released, however.
  */
-static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
+static inline pte_t ptep_modify_prot_start(struct vm_area_struct *vma,
                                           unsigned long addr,
                                           pte_t *ptep)
 {
-       return __ptep_modify_prot_start(mm, addr, ptep);
+       return __ptep_modify_prot_start(vma, addr, ptep);
 }
 
 /*
  * Commit an update to a pte, leaving any hardware-controlled bits in
  * the PTE unmodified.
  */
-static inline void ptep_modify_prot_commit(struct mm_struct *mm,
+static inline void ptep_modify_prot_commit(struct vm_area_struct *vma,
                                           unsigned long addr,
-                                          pte_t *ptep, pte_t pte)
+                                          pte_t *ptep, pte_t old_pte, pte_t pte)
 {
-       __ptep_modify_prot_commit(mm, addr, ptep, pte);
+       __ptep_modify_prot_commit(vma, addr, ptep, pte);
 }
 #endif /* __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION */
 #endif /* CONFIG_MMU */
index c28a47cbe355ea8e74e94e72035cdae8d16cb168..f9b02918024123aac03fef8312af8a3a18f19973 100644 (file)
@@ -365,7 +365,7 @@ unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie)
        rcu_read_lock();
 
        /*
-        * Paired with store_release in inode_switch_wb_work_fn() and
+        * Paired with store_release in inode_switch_wbs_work_fn() and
         * ensures that we see the new wb if we see cleared I_WB_SWITCH.
         */
        cookie->locked = smp_load_acquire(&inode->i_state) & I_WB_SWITCH;
index 53051f3d8f2561207c4da0d4e12aa1d7e5a0470b..f111c780ef1df31bf0806d2f76f41b15e94339f3 100644 (file)
@@ -4,15 +4,18 @@
  *
  * Common interface definitions for making balloon pages movable by compaction.
  *
- * Despite being perfectly possible to perform ballooned pages migration, they
- * make a special corner case to compaction scans because balloon pages are not
- * enlisted at any LRU list like the other pages we do compact / migrate.
+ * Balloon page migration makes use of the general non-lru movable page
+ * feature.
+ *
+ * page->private is used to reference the responsible balloon device.
+ * page->mapping is used in context of non-lru page migration to reference
+ * the address space operations for page isolation/migration/compaction.
  *
  * As the page isolation scanning step a compaction thread does is a lockless
  * procedure (from a page standpoint), it might bring some racy situations while
  * performing balloon page compaction. In order to sort out these racy scenarios
  * and safely perform balloon's page compaction and migration we must, always,
- * ensure following these three simple rules:
+ * ensure following these simple rules:
  *
  *   i. when updating a balloon's page ->mapping element, strictly do it under
  *      the following lock order, independently of the far superior
  *           +--spin_lock_irq(&b_dev_info->pages_lock);
  *                 ... page->mapping updates here ...
  *
- *  ii. before isolating or dequeueing a balloon page from the balloon device
- *      pages list, the page reference counter must be raised by one and the
- *      extra refcount must be dropped when the page is enqueued back into
- *      the balloon device page list, thus a balloon page keeps its reference
- *      counter raised only while it is under our special handling;
- *
- * iii. after the lockless scan step have selected a potential balloon page for
- *      isolation, re-test the PageBalloon mark and the PagePrivate flag
- *      under the proper page lock, to ensure isolating a valid balloon page
- *      (not yet isolated, nor under release procedure)
- *
- *  iv. isolation or dequeueing procedure must clear PagePrivate flag under
- *      page lock together with removing page from balloon device page list.
+ *  ii. isolation or dequeueing procedure must remove the page from balloon
+ *      device page list under b_dev_info->pages_lock.
  *
  * The functions provided by this interface are placed to help on coping with
  * the aforementioned balloon page corner case, as well as to ensure the simple
@@ -103,7 +95,7 @@ extern int balloon_page_migrate(struct address_space *mapping,
 static inline void balloon_page_insert(struct balloon_dev_info *balloon,
                                       struct page *page)
 {
-       __SetPageBalloon(page);
+       __SetPageOffline(page);
        __SetPageMovable(page, balloon->inode->i_mapping);
        set_page_private(page, (unsigned long)balloon);
        list_add(&page->lru, &balloon->pages);
@@ -119,7 +111,7 @@ static inline void balloon_page_insert(struct balloon_dev_info *balloon,
  */
 static inline void balloon_page_delete(struct page *page)
 {
-       __ClearPageBalloon(page);
+       __ClearPageOffline(page);
        __ClearPageMovable(page);
        set_page_private(page, 0);
        /*
@@ -149,13 +141,13 @@ static inline gfp_t balloon_mapping_gfp_mask(void)
 static inline void balloon_page_insert(struct balloon_dev_info *balloon,
                                       struct page *page)
 {
-       __SetPageBalloon(page);
+       __SetPageOffline(page);
        list_add(&page->lru, &balloon->pages);
 }
 
 static inline void balloon_page_delete(struct page *page)
 {
-       __ClearPageBalloon(page);
+       __ClearPageOffline(page);
        list_del(&page->lru);
 }
 
index 8fcbae1b8db0f378092ff0c411e54315bee370d5..aad3babef007c37345b9c56bbfd4b238114bc266 100644 (file)
@@ -32,6 +32,7 @@ struct kernfs_node;
 struct kernfs_ops;
 struct kernfs_open_file;
 struct seq_file;
+struct poll_table_struct;
 
 #define MAX_CGROUP_TYPE_NAMELEN 32
 #define MAX_CGROUP_ROOT_NAMELEN 64
@@ -574,6 +575,9 @@ struct cftype {
        ssize_t (*write)(struct kernfs_open_file *of,
                         char *buf, size_t nbytes, loff_t off);
 
+       __poll_t (*poll)(struct kernfs_open_file *of,
+                        struct poll_table_struct *pt);
+
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
        struct lock_class_key   lockdep_key;
 #endif
index 68250a57aace9f017a6cfe3eaf0468a652100535..9569e7c786d3e1c997494874d0224701444bbb75 100644 (file)
@@ -88,14 +88,13 @@ extern int sysctl_compact_memory;
 extern int sysctl_compaction_handler(struct ctl_table *table, int write,
                        void __user *buffer, size_t *length, loff_t *ppos);
 extern int sysctl_extfrag_threshold;
-extern int sysctl_extfrag_handler(struct ctl_table *table, int write,
-                       void __user *buffer, size_t *length, loff_t *ppos);
 extern int sysctl_compact_unevictable_allowed;
 
 extern int fragmentation_index(struct zone *zone, unsigned int order);
 extern enum compact_result try_to_compact_pages(gfp_t gfp_mask,
                unsigned int order, unsigned int alloc_flags,
-               const struct alloc_context *ac, enum compact_priority prio);
+               const struct alloc_context *ac, enum compact_priority prio,
+               struct page **page);
 extern void reset_isolation_suitable(pg_data_t *pgdat);
 extern enum compact_result compaction_suitable(struct zone *zone, int order,
                unsigned int alloc_flags, int classzone_idx);
@@ -227,8 +226,8 @@ static inline void wakeup_kcompactd(pg_data_t *pgdat, int order, int classzone_i
 
 #endif /* CONFIG_COMPACTION */
 
-#if defined(CONFIG_COMPACTION) && defined(CONFIG_SYSFS) && defined(CONFIG_NUMA)
 struct node;
+#if defined(CONFIG_COMPACTION) && defined(CONFIG_SYSFS) && defined(CONFIG_NUMA)
 extern int compaction_register_node(struct node *node);
 extern void compaction_unregister_node(struct node *node);
 
index 6cb4640b6160681f05ad291684c1eaff29df81d9..4d2f13e8c540cd70f0652ba87f56c073bd6331da 100644 (file)
@@ -1095,7 +1095,7 @@ static inline void set_dev_node(struct device *dev, int node)
 #else
 static inline int dev_to_node(struct device *dev)
 {
-       return -1;
+       return NUMA_NO_NODE;
 }
 static inline void set_dev_node(struct device *dev, int node)
 {
index 011965c08b939206fadc0081b3c0c7acc3e065ce..6d775984905b94f9c4498ab3d6dca05a68d3882d 100644 (file)
@@ -7,6 +7,13 @@
 #include <linux/bitops.h>
 #include <linux/jump_label.h>
 
+/*
+ * Return code to denote that requested number of
+ * frontswap pages are unused(moved to page cache).
+ * Used in in shmem_unuse and try_to_unuse.
+ */
+#define FRONTSWAP_PAGES_UNUSED 2
+
 struct frontswap_ops {
        void (*init)(unsigned); /* this swap type was just swapon'ed */
        int (*store)(unsigned, pgoff_t, struct page *); /* store a page */
index fd423fec8d8372172ce7cf266a5fc5d74e4d8e83..08f26046233ee621c4beed40344bde90f22b33cc 100644 (file)
@@ -2091,7 +2091,7 @@ static inline void init_sync_kiocb(struct kiocb *kiocb, struct file *filp)
  * I_WB_SWITCH         Cgroup bdi_writeback switching in progress.  Used to
  *                     synchronize competing switching instances and to tell
  *                     wb stat updates to grab the i_pages lock.  See
- *                     inode_switch_wb_work_fn() for details.
+ *                     inode_switch_wbs_work_fn() for details.
  *
  * I_OVL_INUSE         Used by overlayfs to get exclusive ownership on upper
  *                     and work dirs among overlayfs mounts.
index 5f5e25fd61491173894ea5255e28f5e154b348f7..fdab7de7490dff2ae693c710214023489e6f394f 100644 (file)
@@ -24,21 +24,21 @@ struct vm_area_struct;
 #define ___GFP_HIGH            0x20u
 #define ___GFP_IO              0x40u
 #define ___GFP_FS              0x80u
-#define ___GFP_WRITE           0x100u
-#define ___GFP_NOWARN          0x200u
-#define ___GFP_RETRY_MAYFAIL   0x400u
-#define ___GFP_NOFAIL          0x800u
-#define ___GFP_NORETRY         0x1000u
-#define ___GFP_MEMALLOC                0x2000u
-#define ___GFP_COMP            0x4000u
-#define ___GFP_ZERO            0x8000u
-#define ___GFP_NOMEMALLOC      0x10000u
-#define ___GFP_HARDWALL                0x20000u
-#define ___GFP_THISNODE                0x40000u
-#define ___GFP_ATOMIC          0x80000u
-#define ___GFP_ACCOUNT         0x100000u
-#define ___GFP_DIRECT_RECLAIM  0x200000u
-#define ___GFP_KSWAPD_RECLAIM  0x400000u
+#define ___GFP_ZERO            0x100u
+#define ___GFP_ATOMIC          0x200u
+#define ___GFP_DIRECT_RECLAIM  0x400u
+#define ___GFP_KSWAPD_RECLAIM  0x800u
+#define ___GFP_WRITE           0x1000u
+#define ___GFP_NOWARN          0x2000u
+#define ___GFP_RETRY_MAYFAIL   0x4000u
+#define ___GFP_NOFAIL          0x8000u
+#define ___GFP_NORETRY         0x10000u
+#define ___GFP_MEMALLOC                0x20000u
+#define ___GFP_COMP            0x40000u
+#define ___GFP_NOMEMALLOC      0x80000u
+#define ___GFP_HARDWALL                0x100000u
+#define ___GFP_THISNODE                0x200000u
+#define ___GFP_ACCOUNT         0x400000u
 #ifdef CONFIG_LOCKDEP
 #define ___GFP_NOLOCKDEP       0x800000u
 #else
index 087fd5f48c9128752cf7ff8a872f30afab057381..ea35263eb76b76e796f2f3ffaa3378585b98db82 100644 (file)
@@ -371,6 +371,8 @@ struct page *alloc_huge_page_nodemask(struct hstate *h, int preferred_nid,
                                nodemask_t *nmask);
 struct page *alloc_huge_page_vma(struct hstate *h, struct vm_area_struct *vma,
                                unsigned long address);
+struct page *alloc_migrate_huge_page(struct hstate *h, gfp_t gfp_mask,
+                                    int nid, nodemask_t *nmask);
 int huge_add_to_page_cache(struct page *page, struct address_space *mapping,
                        pgoff_t idx);
 
@@ -493,17 +495,54 @@ static inline pgoff_t basepage_index(struct page *page)
 extern int dissolve_free_huge_page(struct page *page);
 extern int dissolve_free_huge_pages(unsigned long start_pfn,
                                    unsigned long end_pfn);
-static inline bool hugepage_migration_supported(struct hstate *h)
-{
+
 #ifdef CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION
+#ifndef arch_hugetlb_migration_supported
+static inline bool arch_hugetlb_migration_supported(struct hstate *h)
+{
        if ((huge_page_shift(h) == PMD_SHIFT) ||
-               (huge_page_shift(h) == PGDIR_SHIFT))
+               (huge_page_shift(h) == PUD_SHIFT) ||
+                       (huge_page_shift(h) == PGDIR_SHIFT))
                return true;
        else
                return false;
+}
+#endif
 #else
+static inline bool arch_hugetlb_migration_supported(struct hstate *h)
+{
        return false;
+}
 #endif
+
+static inline bool hugepage_migration_supported(struct hstate *h)
+{
+       return arch_hugetlb_migration_supported(h);
+}
+
+/*
+ * Movability check is different as compared to migration check.
+ * It determines whether or not a huge page should be placed on
+ * movable zone or not. Movability of any huge page should be
+ * required only if huge page size is supported for migration.
+ * There wont be any reason for the huge page to be movable if
+ * it is not migratable to start with. Also the size of the huge
+ * page should be large enough to be placed under a movable zone
+ * and still feasible enough to be migratable. Just the presence
+ * in movable zone does not make the migration feasible.
+ *
+ * So even though large huge page sizes like the gigantic ones
+ * are migratable they should not be movable because its not
+ * feasible to migrate them from movable zone.
+ */
+static inline bool hugepage_movable_supported(struct hstate *h)
+{
+       if (!hugepage_migration_supported(h))
+               return false;
+
+       if (hstate_is_gigantic(h))
+               return false;
+       return true;
 }
 
 static inline spinlock_t *huge_pte_lockptr(struct hstate *h,
@@ -543,6 +582,26 @@ static inline void set_huge_swap_pte_at(struct mm_struct *mm, unsigned long addr
        set_huge_pte_at(mm, addr, ptep, pte);
 }
 #endif
+
+#ifndef huge_ptep_modify_prot_start
+#define huge_ptep_modify_prot_start huge_ptep_modify_prot_start
+static inline pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma,
+                                               unsigned long addr, pte_t *ptep)
+{
+       return huge_ptep_get_and_clear(vma->vm_mm, addr, ptep);
+}
+#endif
+
+#ifndef huge_ptep_modify_prot_commit
+#define huge_ptep_modify_prot_commit huge_ptep_modify_prot_commit
+static inline void huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
+                                               unsigned long addr, pte_t *ptep,
+                                               pte_t old_pte, pte_t pte)
+{
+       set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+}
+#endif
+
 #else  /* CONFIG_HUGETLB_PAGE */
 struct hstate {};
 #define alloc_huge_page(v, a, r) NULL
@@ -602,6 +661,11 @@ static inline bool hugepage_migration_supported(struct hstate *h)
        return false;
 }
 
+static inline bool hugepage_movable_supported(struct hstate *h)
+{
+       return false;
+}
+
 static inline spinlock_t *huge_pte_lockptr(struct hstate *h,
                                           struct mm_struct *mm, pte_t *pte)
 {
index d314150658a43f4392026b62d57cd708814e5eb1..a61dc075e2ce962ca85c7d2a4d2afb6cd6b1e3b2 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef _LINUX_KASAN_CHECKS_H
 #define _LINUX_KASAN_CHECKS_H
 
-#ifdef CONFIG_KASAN
+#if defined(__SANITIZE_ADDRESS__) || defined(__KASAN_INTERNAL)
 void kasan_check_read(const volatile void *p, unsigned int size);
 void kasan_check_write(const volatile void *p, unsigned int size);
 #else
index 5b36b1287a5a6c2519d0c8f2cc112d5b1f82ae1a..0cac1207bb00ae4add9a6435da4a15b80702ea40 100644 (file)
@@ -25,6 +25,7 @@ struct seq_file;
 struct vm_area_struct;
 struct super_block;
 struct file_system_type;
+struct poll_table_struct;
 
 struct kernfs_open_node;
 struct kernfs_iattrs;
@@ -261,6 +262,9 @@ struct kernfs_ops {
        ssize_t (*write)(struct kernfs_open_file *of, char *buf, size_t bytes,
                         loff_t off);
 
+       __poll_t (*poll)(struct kernfs_open_file *of,
+                        struct poll_table_struct *pt);
+
        int (*mmap)(struct kernfs_open_file *of, struct vm_area_struct *vma);
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
@@ -350,6 +354,8 @@ int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name,
 int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
                     const char *new_name, const void *new_ns);
 int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr);
+__poll_t kernfs_generic_poll(struct kernfs_open_file *of,
+                            struct poll_table_struct *pt);
 void kernfs_notify(struct kernfs_node *kn);
 
 const void *kernfs_super_ns(struct super_block *sb);
index 161e8164abcf535f30417593b055e3c3c5acf564..e48b1e453ff5109292f7a735b7e4c73a0caf43b9 100644 (file)
@@ -53,6 +53,8 @@ struct page *ksm_might_need_to_copy(struct page *page,
 
 void rmap_walk_ksm(struct page *page, struct rmap_walk_control *rwc);
 void ksm_migrate_page(struct page *newpage, struct page *oldpage);
+bool reuse_ksm_page(struct page *page,
+                       struct vm_area_struct *vma, unsigned long address);
 
 #else  /* !CONFIG_KSM */
 
@@ -86,6 +88,11 @@ static inline void rmap_walk_ksm(struct page *page,
 static inline void ksm_migrate_page(struct page *newpage, struct page *oldpage)
 {
 }
+static inline bool reuse_ksm_page(struct page *page,
+                       struct vm_area_struct *vma, unsigned long address)
+{
+       return false;
+}
 #endif /* CONFIG_MMU */
 #endif /* !CONFIG_KSM */
 
index edb7628e46edafa2c3bbd4dc671923bb3e8b0923..79626b5ab36cce2492a406c3ff4f50023c4c2150 100644 (file)
@@ -206,6 +206,17 @@ static inline void list_bulk_move_tail(struct list_head *head,
        head->prev = last;
 }
 
+/**
+ * list_is_first -- tests whether @ list is the first entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_first(const struct list_head *list,
+                                       const struct list_head *head)
+{
+       return list->prev == head;
+}
+
 /**
  * list_is_last - tests whether @list is the last entry in list @head
  * @list: the entry to test
index 83ae11cbd12c6d0dea58af06f7b71560eec57278..1f3d880b7ca1736057546bc0b98997b6b8a65aea 100644 (file)
@@ -429,6 +429,11 @@ static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg)
 }
 struct mem_cgroup *mem_cgroup_from_id(unsigned short id);
 
+static inline struct mem_cgroup *mem_cgroup_from_seq(struct seq_file *m)
+{
+       return mem_cgroup_from_css(seq_css(m));
+}
+
 static inline struct mem_cgroup *lruvec_memcg(struct lruvec *lruvec)
 {
        struct mem_cgroup_per_node *mz;
@@ -937,6 +942,11 @@ static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id)
        return NULL;
 }
 
+static inline struct mem_cgroup *mem_cgroup_from_seq(struct seq_file *m)
+{
+       return NULL;
+}
+
 static inline struct mem_cgroup *lruvec_memcg(struct lruvec *lruvec)
 {
        return NULL;
@@ -1273,12 +1283,12 @@ static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg)
 
 struct kmem_cache *memcg_kmem_get_cache(struct kmem_cache *cachep);
 void memcg_kmem_put_cache(struct kmem_cache *cachep);
-int memcg_kmem_charge_memcg(struct page *page, gfp_t gfp, int order,
-                           struct mem_cgroup *memcg);
 
 #ifdef CONFIG_MEMCG_KMEM
-int memcg_kmem_charge(struct page *page, gfp_t gfp, int order);
-void memcg_kmem_uncharge(struct page *page, int order);
+int __memcg_kmem_charge(struct page *page, gfp_t gfp, int order);
+void __memcg_kmem_uncharge(struct page *page, int order);
+int __memcg_kmem_charge_memcg(struct page *page, gfp_t gfp, int order,
+                             struct mem_cgroup *memcg);
 
 extern struct static_key_false memcg_kmem_enabled_key;
 extern struct workqueue_struct *memcg_kmem_cache_wq;
@@ -1300,6 +1310,26 @@ static inline bool memcg_kmem_enabled(void)
        return static_branch_unlikely(&memcg_kmem_enabled_key);
 }
 
+static inline int memcg_kmem_charge(struct page *page, gfp_t gfp, int order)
+{
+       if (memcg_kmem_enabled())
+               return __memcg_kmem_charge(page, gfp, order);
+       return 0;
+}
+
+static inline void memcg_kmem_uncharge(struct page *page, int order)
+{
+       if (memcg_kmem_enabled())
+               __memcg_kmem_uncharge(page, order);
+}
+
+static inline int memcg_kmem_charge_memcg(struct page *page, gfp_t gfp,
+                                         int order, struct mem_cgroup *memcg)
+{
+       if (memcg_kmem_enabled())
+               return __memcg_kmem_charge_memcg(page, gfp, order, memcg);
+       return 0;
+}
 /*
  * helper for accessing a memcg's index. It will be used as an index in the
  * child cache array in kmem_cache, and also to derive its name. This function
@@ -1325,6 +1355,15 @@ static inline void memcg_kmem_uncharge(struct page *page, int order)
 {
 }
 
+static inline int __memcg_kmem_charge(struct page *page, gfp_t gfp, int order)
+{
+       return 0;
+}
+
+static inline void __memcg_kmem_uncharge(struct page *page, int order)
+{
+}
+
 #define for_each_memcg_cache_index(_idx)       \
        for (; NULL; )
 
index 368267c1b71b101f3d1d9927197014e2a24efa85..52869d6d38b37307a36280654aa0d289eb773d10 100644 (file)
@@ -89,7 +89,7 @@ extern int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn,
        unsigned long *valid_start, unsigned long *valid_end);
 extern void __offline_isolated_pages(unsigned long, unsigned long);
 
-typedef void (*online_page_callback_t)(struct page *page);
+typedef void (*online_page_callback_t)(struct page *page, unsigned int order);
 
 extern int set_online_page_callback(online_page_callback_t callback);
 extern int restore_online_page_callback(online_page_callback_t callback);
index 80bb6408fe73a8744c733362abf5446b237156ab..20ec56f8e2bbd929e86909c60c644686289f3e5c 100644 (file)
@@ -1536,7 +1536,8 @@ long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
                    unsigned int gup_flags, struct page **pages, int *locked);
 long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
                    struct page **pages, unsigned int gup_flags);
-#ifdef CONFIG_FS_DAX
+
+#if defined(CONFIG_FS_DAX) || defined(CONFIG_CMA)
 long get_user_pages_longterm(unsigned long start, unsigned long nr_pages,
                            unsigned int gup_flags, struct page **pages,
                            struct vm_area_struct **vmas);
index 0a36a22228e75accb3fe635dec149ace301dcf51..ab9b48420200c5990ff34bf4f5389b1a040997b9 100644 (file)
@@ -80,7 +80,7 @@ struct page {
                struct {        /* Page cache and anonymous pages */
                        /**
                         * @lru: Pageout list, eg. active_list protected by
-                        * zone_lru_lock.  Sometimes used as a generic list
+                        * pgdat->lru_lock.  Sometimes used as a generic list
                         * by the page owner.
                         */
                        struct list_head lru;
index 842f9189537bb04d51285c3b237d9263273fc559..fba7741533bec2535ef9552ed9bf07e25ff984f8 100644 (file)
@@ -480,6 +480,8 @@ struct zone {
        unsigned long           compact_cached_free_pfn;
        /* pfn where async and sync compaction migration scanner should start */
        unsigned long           compact_cached_migrate_pfn[2];
+       unsigned long           compact_init_migrate_pfn;
+       unsigned long           compact_init_free_pfn;
 #endif
 
 #ifdef CONFIG_COMPACTION
@@ -728,10 +730,6 @@ typedef struct pglist_data {
 
 #define node_start_pfn(nid)    (NODE_DATA(nid)->node_start_pfn)
 #define node_end_pfn(nid) pgdat_end_pfn(NODE_DATA(nid))
-static inline spinlock_t *zone_lru_lock(struct zone *zone)
-{
-       return &zone->zone_pgdat->lru_lock;
-}
 
 static inline struct lruvec *node_lruvec(struct pglist_data *pgdat)
 {
@@ -1299,7 +1297,7 @@ void memory_present(int nid, unsigned long start, unsigned long end);
 
 /*
  * If it is possible to have holes within a MAX_ORDER_NR_PAGES, then we
- * need to check pfn validility within that MAX_ORDER_NR_PAGES block.
+ * need to check pfn validity within that MAX_ORDER_NR_PAGES block.
  * pfn_valid_within() should be used in this case; we optimise this away
  * when we have no holes within a MAX_ORDER_NR_PAGES block.
  */
index 5a30ad594ccc11d40879ec8438b587f519b5c791..27e7fa36f707fb6307fdd0abd4e3114e2e90ae12 100644 (file)
@@ -444,8 +444,8 @@ static inline int next_memory_node(int nid)
        return next_node(nid, node_states[N_MEMORY]);
 }
 
-extern int nr_node_ids;
-extern int nr_online_nodes;
+extern unsigned int nr_node_ids;
+extern unsigned int nr_online_nodes;
 
 static inline void node_set_online(int nid)
 {
@@ -485,8 +485,8 @@ static inline int num_node_state(enum node_states state)
 #define first_online_node      0
 #define first_memory_node      0
 #define next_online_node(nid)  (MAX_NUMNODES)
-#define nr_node_ids            1
-#define nr_online_nodes                1
+#define nr_node_ids            1U
+#define nr_online_nodes                1U
 
 #define node_set_online(node)     node_set_state((node), N_ONLINE)
 #define node_set_offline(node)    node_clear_state((node), N_ONLINE)
index 39b4494e29f1fa8805cb3f51125576a82de7b816..9f8712a4b1a5b509614ec27157d247d28faa7a0f 100644 (file)
 /*
  * Various page->flags bits:
  *
- * PG_reserved is set for special pages, which can never be swapped out. Some
- * of them might not even exist...
+ * PG_reserved is set for special pages. The "struct page" of such a page
+ * should in general not be touched (e.g. set dirty) except by its owner.
+ * Pages marked as PG_reserved include:
+ * - Pages part of the kernel image (including vDSO) and similar (e.g. BIOS,
+ *   initrd, HW tables)
+ * - Pages reserved or allocated early during boot (before the page allocator
+ *   was initialized). This includes (depending on the architecture) the
+ *   initial vmemmap, initial page tables, crashkernel, elfcorehdr, and much
+ *   much more. Once (if ever) freed, PG_reserved is cleared and they will
+ *   be given to the page allocator.
+ * - Pages falling into physical memory gaps - not IORESOURCE_SYSRAM. Trying
+ *   to read/write these pages might end badly. Don't touch!
+ * - The zero page(s)
+ * - Pages not added to the page allocator when onlining a section because
+ *   they were excluded via the online_page_callback() or because they are
+ *   PG_hwpoison.
+ * - Pages allocated in the context of kexec/kdump (loaded kernel image,
+ *   control pages, vmcoreinfo)
+ * - MMIO/DMA pages. Some architectures don't allow to ioremap pages that are
+ *   not marked PG_reserved (as they might be in use by somebody else who does
+ *   not respect the caching strategy).
+ * - Pages part of an offline section (struct pages of offline sections should
+ *   not be trusted as they will be initialized when first onlined).
+ * - MCA pages on ia64
+ * - Pages holding CPU notes for POWER Firmware Assisted Dump
+ * - Device memory (e.g. PMEM, DAX, HMM)
+ * Some PG_reserved pages will be excluded from the hibernation image.
+ * PG_reserved does in general not hinder anybody from dumping or swapping
+ * and is no longer required for remap_pfn_range(). ioremap might require it.
+ * Consequently, PG_reserved for a page mapped into user space can indicate
+ * the zero page, the vDSO, MMIO pages or device memory.
  *
  * The PG_private bitflag is set on pagecache pages if they contain filesystem
  * specific data (which is normally at page->private). It can be used by
@@ -671,7 +700,7 @@ PAGEFLAG_FALSE(DoubleMap)
 /* Reserve             0x0000007f to catch underflows of page_mapcount */
 #define PAGE_MAPCOUNT_RESERVE  -128
 #define PG_buddy       0x00000080
-#define PG_balloon     0x00000100
+#define PG_offline     0x00000100
 #define PG_kmemcg      0x00000200
 #define PG_table       0x00000400
 
@@ -706,10 +735,13 @@ static __always_inline void __ClearPage##uname(struct page *page) \
 PAGE_TYPE_OPS(Buddy, buddy)
 
 /*
- * PageBalloon() is true for pages that are on the balloon page list
- * (see mm/balloon_compaction.c).
+ * PageOffline() indicates that the page is logically offline although the
+ * containing section is online. (e.g. inflated in a balloon driver or
+ * not onlined when onlining the section).
+ * The content of these pages is effectively stale. Such pages should not
+ * be touched (read/write/dump/save) except by their owner.
  */
-PAGE_TYPE_OPS(Balloon, balloon)
+PAGE_TYPE_OPS(Offline, offline)
 
 /*
  * If kmemcg is enabled, the buddy allocator will set PageKmemcg() on
index e2d7039af6a38b65f13a5a4fd2dfd8bd1b86f489..b477a70cc2e4587fd828ee921ce0b9ec2138775d 100644 (file)
@@ -164,7 +164,7 @@ void release_pages(struct page **pages, int nr);
  * will find the page or it will not. Likewise, the old find_get_page could run
  * either before the insertion or afterwards, depending on timing.
  */
-static inline int page_cache_get_speculative(struct page *page)
+static inline int __page_cache_add_speculative(struct page *page, int count)
 {
 #ifdef CONFIG_TINY_RCU
 # ifdef CONFIG_PREEMPT_COUNT
@@ -180,10 +180,10 @@ static inline int page_cache_get_speculative(struct page *page)
         * SMP requires.
         */
        VM_BUG_ON_PAGE(page_count(page) == 0, page);
-       page_ref_inc(page);
+       page_ref_add(page, count);
 
 #else
-       if (unlikely(!get_page_unless_zero(page))) {
+       if (unlikely(!page_ref_add_unless(page, count, 0))) {
                /*
                 * Either the page has been freed, or will be freed.
                 * In either case, retry here and the caller should
@@ -197,27 +197,14 @@ static inline int page_cache_get_speculative(struct page *page)
        return 1;
 }
 
-/*
- * Same as above, but add instead of inc (could just be merged)
- */
-static inline int page_cache_add_speculative(struct page *page, int count)
+static inline int page_cache_get_speculative(struct page *page)
 {
-       VM_BUG_ON(in_interrupt());
-
-#if !defined(CONFIG_SMP) && defined(CONFIG_TREE_RCU)
-# ifdef CONFIG_PREEMPT_COUNT
-       VM_BUG_ON(!in_atomic() && !irqs_disabled());
-# endif
-       VM_BUG_ON_PAGE(page_count(page) == 0, page);
-       page_ref_add(page, count);
-
-#else
-       if (unlikely(!page_ref_add_unless(page, count, 0)))
-               return 0;
-#endif
-       VM_BUG_ON_PAGE(PageCompound(page) && page != compound_head(page), page);
+       return __page_cache_add_speculative(page, 1);
+}
 
-       return 1;
+static inline int page_cache_add_speculative(struct page *page, int count)
+{
+       return __page_cache_add_speculative(page, count);
 }
 
 #ifdef CONFIG_NUMA
index 15927ebc22f2592468c4134ca7c83afae38186d7..5046bad0c1c5e6c9418d3f10e7d15ff2004abe99 100644 (file)
@@ -30,7 +30,7 @@
  */
 #define TIMER_ENTRY_STATIC     ((void *) 0x300 + POISON_POINTER_DELTA)
 
-/********** mm/debug-pagealloc.c **********/
+/********** mm/page_poison.c **********/
 #ifdef CONFIG_PAGE_POISONING_ZERO
 #define PAGE_POISON 0x00
 #else
index 903ef29b62c3d60b62e33b6850baf5d74297596b..f073bd59df32c9214f70df5a9a2190bafdd064b8 100644 (file)
@@ -48,6 +48,7 @@ struct pid_namespace;
 struct pipe_inode_info;
 struct rcu_node;
 struct reclaim_state;
+struct capture_control;
 struct robust_list_head;
 struct sched_attr;
 struct sched_param;
@@ -950,6 +951,9 @@ struct task_struct {
 
        struct io_context               *io_context;
 
+#ifdef CONFIG_COMPACTION
+       struct capture_control          *capture_control;
+#endif
        /* Ptrace state: */
        unsigned long                   ptrace_message;
        kernel_siginfo_t                *last_siginfo;
@@ -1395,6 +1399,7 @@ extern struct pid *cad_pid;
 #define PF_UMH                 0x02000000      /* I'm an Usermodehelper process */
 #define PF_NO_SETAFFINITY      0x04000000      /* Userland is not allowed to meddle with cpus_allowed */
 #define PF_MCE_EARLY           0x08000000      /* Early kill for mce process policy */
+#define PF_MEMALLOC_NOCMA      0x10000000      /* All allocation request will have _GFP_MOVABLE cleared */
 #define PF_FREEZER_SKIP                0x40000000      /* Freezer should not count it as freezable */
 #define PF_SUSPEND_TASK                0x80000000      /* This thread called freeze_processes() and should not be frozen */
 
index 3bfa6a0cbba4edc7bf0a9e33798e227526633bfa..0cd9f10423fb8e60645685ab5bdbad675d803a51 100644 (file)
@@ -148,17 +148,25 @@ static inline bool in_vfork(struct task_struct *tsk)
  * Applies per-task gfp context to the given allocation flags.
  * PF_MEMALLOC_NOIO implies GFP_NOIO
  * PF_MEMALLOC_NOFS implies GFP_NOFS
+ * PF_MEMALLOC_NOCMA implies no allocation from CMA region.
  */
 static inline gfp_t current_gfp_context(gfp_t flags)
 {
-       /*
-        * NOIO implies both NOIO and NOFS and it is a weaker context
-        * so always make sure it makes precedence
-        */
-       if (unlikely(current->flags & PF_MEMALLOC_NOIO))
-               flags &= ~(__GFP_IO | __GFP_FS);
-       else if (unlikely(current->flags & PF_MEMALLOC_NOFS))
-               flags &= ~__GFP_FS;
+       if (unlikely(current->flags &
+                    (PF_MEMALLOC_NOIO | PF_MEMALLOC_NOFS | PF_MEMALLOC_NOCMA))) {
+               /*
+                * NOIO implies both NOIO and NOFS and it is a weaker context
+                * so always make sure it makes precedence
+                */
+               if (current->flags & PF_MEMALLOC_NOIO)
+                       flags &= ~(__GFP_IO | __GFP_FS);
+               else if (current->flags & PF_MEMALLOC_NOFS)
+                       flags &= ~__GFP_FS;
+#ifdef CONFIG_CMA
+               if (current->flags & PF_MEMALLOC_NOCMA)
+                       flags &= ~__GFP_MOVABLE;
+#endif
+       }
        return flags;
 }
 
@@ -248,6 +256,30 @@ static inline void memalloc_noreclaim_restore(unsigned int flags)
        current->flags = (current->flags & ~PF_MEMALLOC) | flags;
 }
 
+#ifdef CONFIG_CMA
+static inline unsigned int memalloc_nocma_save(void)
+{
+       unsigned int flags = current->flags & PF_MEMALLOC_NOCMA;
+
+       current->flags |= PF_MEMALLOC_NOCMA;
+       return flags;
+}
+
+static inline void memalloc_nocma_restore(unsigned int flags)
+{
+       current->flags = (current->flags & ~PF_MEMALLOC_NOCMA) | flags;
+}
+#else
+static inline unsigned int memalloc_nocma_save(void)
+{
+       return 0;
+}
+
+static inline void memalloc_nocma_restore(unsigned int flags)
+{
+}
+#endif
+
 #ifdef CONFIG_MEMCG
 /**
  * memalloc_use_memcg - Starts the remote memcg charging scope.
index f155dc607112e14420fb0eaf2865fb73b270f886..f3fb1edb3526ddc0c582f0ad32017ab7eaf21dd3 100644 (file)
@@ -72,7 +72,8 @@ extern void shmem_unlock_mapping(struct address_space *mapping);
 extern struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
                                        pgoff_t index, gfp_t gfp_mask);
 extern void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end);
-extern int shmem_unuse(swp_entry_t entry, struct page *page);
+extern int shmem_unuse(unsigned int type, bool frontswap,
+                      unsigned long *fs_pages_to_unuse);
 
 extern unsigned long shmem_swap_usage(struct vm_area_struct *vma);
 extern unsigned long shmem_partial_swap_usage(struct address_space *mapping,
index 3a1a1dbc6f49479f61f4c1a6588e6a672f0b0663..d2153789bd9f91330e43ab5a02f627cf28fd935c 100644 (file)
@@ -81,12 +81,12 @@ struct kmem_cache_order_objects {
  */
 struct kmem_cache {
        struct kmem_cache_cpu __percpu *cpu_slab;
-       /* Used for retriving partial slabs etc */
+       /* Used for retrieving partial slabs, etc. */
        slab_flags_t flags;
        unsigned long min_partial;
-       unsigned int size;      /* The size of an object including meta data */
-       unsigned int object_size;/* The size of an object without meta data */
-       unsigned int offset;    /* Free pointer offset. */
+       unsigned int size;      /* The size of an object including metadata */
+       unsigned int object_size;/* The size of an object without metadata */
+       unsigned int offset;    /* Free pointer offset */
 #ifdef CONFIG_SLUB_CPU_PARTIAL
        /* Number of per cpu partial objects to keep around */
        unsigned int cpu_partial;
@@ -110,7 +110,7 @@ struct kmem_cache {
 #endif
 #ifdef CONFIG_MEMCG
        struct memcg_cache_params memcg_params;
-       /* for propagation, maximum size of a stored attr */
+       /* For propagation, maximum size of a stored attr */
        unsigned int max_attr_size;
 #ifdef CONFIG_SYSFS
        struct kset *memcg_kset;
@@ -151,7 +151,7 @@ struct kmem_cache {
 #else
 #define slub_cpu_partial(s)            (0)
 #define slub_set_cpu_partial(s, n)
-#endif // CONFIG_SLUB_CPU_PARTIAL
+#endif /* CONFIG_SLUB_CPU_PARTIAL */
 
 #ifdef CONFIG_SYSFS
 #define SLAB_SUPPORTS_SYSFS
index 622025ac1461e1d58b8961a1c72df66ecf60efb6..fc50e21b3b88e64a450477f6d595eabb18732522 100644 (file)
@@ -307,7 +307,7 @@ struct vma_swap_readahead {
 };
 
 /* linux/mm/workingset.c */
-void *workingset_eviction(struct address_space *mapping, struct page *page);
+void *workingset_eviction(struct page *page);
 void workingset_refault(struct page *page, void *shadow);
 void workingset_activation(struct page *page);
 
@@ -625,7 +625,7 @@ static inline int mem_cgroup_swappiness(struct mem_cgroup *memcg)
                return vm_swappiness;
 
        /* root ? */
-       if (mem_cgroup_disabled() || !memcg->css.parent)
+       if (mem_cgroup_disabled() || mem_cgroup_is_root(memcg))
                return vm_swappiness;
 
        return memcg->swappiness;
index 6448cdd9a350d3a0c6513c7a76aad29a68689bd4..a2f8658f1c555235de9fb4581acb113339981bdf 100644 (file)
@@ -41,6 +41,7 @@
 #define F_SEAL_SHRINK  0x0002  /* prevent file from shrinking */
 #define F_SEAL_GROW    0x0004  /* prevent file from growing */
 #define F_SEAL_WRITE   0x0008  /* prevent writes */
+#define F_SEAL_FUTURE_WRITE    0x0010  /* prevent future writes while mapped */
 /* (1U << 31) is reserved for signed error codes */
 
 /*
index 21b9113c69da4bb608bf23b58446fde24d682b08..6f2f2720f3ac2697ebcad1e0f963bf350bc14676 100644 (file)
@@ -32,7 +32,7 @@
 
 #define KPF_KSM                        21
 #define KPF_THP                        22
-#define KPF_BALLOON            23
+#define KPF_OFFLINE            23
 #define KPF_ZERO_PAGE          24
 #define KPF_IDLE               25
 #define KPF_PGTABLE            26
index 46dbf546264d20d4aa3263ce9ccaee3890e8c076..df0257c5928c17f31823ebf9bf4eee7e287ff383 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/audit.h>
+#include <linux/numa.h>
 
 #include <asm/pgtable.h>
 #include <linux/uaccess.h>
@@ -154,7 +155,7 @@ struct task_struct init_task
        .vtime.state    = VTIME_SYS,
 #endif
 #ifdef CONFIG_NUMA_BALANCING
-       .numa_preferred_nid = -1,
+       .numa_preferred_nid = NUMA_NO_NODE,
        .numa_group     = NULL,
        .numa_faults    = NULL,
 #endif
index cef98502b124b8fc60c62b39b61f0d53334ce23c..17828333f7c3e015aa3491c6807030e1210fe031 100644 (file)
@@ -3534,6 +3534,16 @@ static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf,
        return ret ?: nbytes;
 }
 
+static __poll_t cgroup_file_poll(struct kernfs_open_file *of, poll_table *pt)
+{
+       struct cftype *cft = of->kn->priv;
+
+       if (cft->poll)
+               return cft->poll(of, pt);
+
+       return kernfs_generic_poll(of, pt);
+}
+
 static void *cgroup_seqfile_start(struct seq_file *seq, loff_t *ppos)
 {
        return seq_cft(seq)->seq_start(seq, ppos);
@@ -3572,6 +3582,7 @@ static struct kernfs_ops cgroup_kf_single_ops = {
        .open                   = cgroup_file_open,
        .release                = cgroup_file_release,
        .write                  = cgroup_file_write,
+       .poll                   = cgroup_file_poll,
        .seq_show               = cgroup_seqfile_show,
 };
 
@@ -3580,6 +3591,7 @@ static struct kernfs_ops cgroup_kf_ops = {
        .open                   = cgroup_file_open,
        .release                = cgroup_file_release,
        .write                  = cgroup_file_write,
+       .poll                   = cgroup_file_poll,
        .seq_start              = cgroup_seqfile_start,
        .seq_next               = cgroup_seqfile_next,
        .seq_stop               = cgroup_seqfile_stop,
index 933cb3e45b987df1ba52d7fa4afc312823d3d745..093c9f917ed0cc8d5c377ca7edb39001f3cc3cc5 100644 (file)
@@ -464,6 +464,8 @@ static int __init crash_save_vmcoreinfo_init(void)
        VMCOREINFO_NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE);
 #ifdef CONFIG_HUGETLB_PAGE
        VMCOREINFO_NUMBER(HUGETLB_PAGE_DTOR);
+#define PAGE_OFFLINE_MAPCOUNT_VALUE    (~PG_offline)
+       VMCOREINFO_NUMBER(PAGE_OFFLINE_MAPCOUNT_VALUE);
 #endif
 
        arch_crash_save_vmcoreinfo();
index 9cf20cc5ebe3e4b56a0e37b4d89f38b95af2cca9..5942eeafb9acfd577768c9e737c91547680449ae 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/freezer.h>
 #include <linux/ptrace.h>
 #include <linux/uaccess.h>
+#include <linux/numa.h>
 #include <trace/events/sched.h>
 
 static DEFINE_SPINLOCK(kthread_create_lock);
@@ -681,7 +682,7 @@ __kthread_create_worker(int cpu, unsigned int flags,
 {
        struct kthread_worker *worker;
        struct task_struct *task;
-       int node = -1;
+       int node = NUMA_NO_NODE;
 
        worker = kzalloc(sizeof(*worker), GFP_KERNEL);
        if (!worker)
index 640b2034edd660da46372b38d8eca7b37bd482fc..4802b039b89f54f60d458405a7db128ff1c09648 100644 (file)
@@ -1215,14 +1215,16 @@ static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn)
        if (!pfn_valid(pfn))
                return NULL;
 
-       page = pfn_to_page(pfn);
-       if (page_zone(page) != zone)
+       page = pfn_to_online_page(pfn);
+       if (!page || page_zone(page) != zone)
                return NULL;
 
        BUG_ON(!PageHighMem(page));
 
-       if (swsusp_page_is_forbidden(page) ||  swsusp_page_is_free(page) ||
-           PageReserved(page))
+       if (swsusp_page_is_forbidden(page) ||  swsusp_page_is_free(page))
+               return NULL;
+
+       if (PageReserved(page) || PageOffline(page))
                return NULL;
 
        if (page_is_guard(page))
@@ -1277,8 +1279,8 @@ static struct page *saveable_page(struct zone *zone, unsigned long pfn)
        if (!pfn_valid(pfn))
                return NULL;
 
-       page = pfn_to_page(pfn);
-       if (page_zone(page) != zone)
+       page = pfn_to_online_page(pfn);
+       if (!page || page_zone(page) != zone)
                return NULL;
 
        BUG_ON(PageHighMem(page));
@@ -1286,6 +1288,9 @@ static struct page *saveable_page(struct zone *zone, unsigned long pfn)
        if (swsusp_page_is_forbidden(page) || swsusp_page_is_free(page))
                return NULL;
 
+       if (PageOffline(page))
+               return NULL;
+
        if (PageReserved(page)
            && (!kernel_page_present(page) || pfn_is_nosave(pfn)))
                return NULL;
index f3901b84d217657ec55f4d265556ad1e5d561bd7..ead464a0f2e5dfc71a0c0df16a9823f3677f847a 100644 (file)
@@ -2220,6 +2220,9 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p)
        INIT_HLIST_HEAD(&p->preempt_notifiers);
 #endif
 
+#ifdef CONFIG_COMPACTION
+       p->capture_control = NULL;
+#endif
        init_numa_balancing(clone_flags, p);
 }
 
index 8213ff6e365d1699e4dae34ce1adfb385d82fec9..ea74d43924b25f7ae98788532d2070152b6cb5fc 100644 (file)
@@ -1173,7 +1173,7 @@ void init_numa_balancing(unsigned long clone_flags, struct task_struct *p)
 
        /* New address space, reset the preferred nid */
        if (!(clone_flags & CLONE_VM)) {
-               p->numa_preferred_nid = -1;
+               p->numa_preferred_nid = NUMA_NO_NODE;
                return;
        }
 
@@ -1193,13 +1193,13 @@ void init_numa_balancing(unsigned long clone_flags, struct task_struct *p)
 
 static void account_numa_enqueue(struct rq *rq, struct task_struct *p)
 {
-       rq->nr_numa_running += (p->numa_preferred_nid != -1);
+       rq->nr_numa_running += (p->numa_preferred_nid != NUMA_NO_NODE);
        rq->nr_preferred_running += (p->numa_preferred_nid == task_node(p));
 }
 
 static void account_numa_dequeue(struct rq *rq, struct task_struct *p)
 {
-       rq->nr_numa_running -= (p->numa_preferred_nid != -1);
+       rq->nr_numa_running -= (p->numa_preferred_nid != NUMA_NO_NODE);
        rq->nr_preferred_running -= (p->numa_preferred_nid == task_node(p));
 }
 
@@ -1413,7 +1413,7 @@ bool should_numa_migrate_memory(struct task_struct *p, struct page * page,
         * two full passes of the "multi-stage node selection" test that is
         * executed below.
         */
-       if ((p->numa_preferred_nid == -1 || p->numa_scan_seq <= 4) &&
+       if ((p->numa_preferred_nid == NUMA_NO_NODE || p->numa_scan_seq <= 4) &&
            (cpupid_pid_unset(last_cpupid) || cpupid_match_pid(p, last_cpupid)))
                return true;
 
@@ -1861,7 +1861,7 @@ static void numa_migrate_preferred(struct task_struct *p)
        unsigned long interval = HZ;
 
        /* This task has no NUMA fault statistics yet */
-       if (unlikely(p->numa_preferred_nid == -1 || !p->numa_faults))
+       if (unlikely(p->numa_preferred_nid == NUMA_NO_NODE || !p->numa_faults))
                return;
 
        /* Periodically retry migrating the task to the preferred node */
@@ -2108,7 +2108,7 @@ static int preferred_group_nid(struct task_struct *p, int nid)
 
 static void task_numa_placement(struct task_struct *p)
 {
-       int seq, nid, max_nid = -1;
+       int seq, nid, max_nid = NUMA_NO_NODE;
        unsigned long max_faults = 0;
        unsigned long fault_types[2] = { 0, 0 };
        unsigned long total_faults;
@@ -2651,7 +2651,8 @@ static void update_scan_period(struct task_struct *p, int new_cpu)
                 * the preferred node.
                 */
                if (dst_nid == p->numa_preferred_nid ||
-                   (p->numa_preferred_nid != -1 && src_nid != p->numa_preferred_nid))
+                   (p->numa_preferred_nid != NUMA_NO_NODE &&
+                       src_nid != p->numa_preferred_nid))
                        return;
        }
 
index 7c2b9bc88ee821c81a8af785b600578a458cd22c..14f30b4a1b64c237a2fa32ce067559e9881faa84 100644 (file)
@@ -1471,7 +1471,7 @@ static struct ctl_table vm_table[] = {
                .data           = &sysctl_extfrag_threshold,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = sysctl_extfrag_handler,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &min_extfrag_threshold,
                .extra2         = &max_extfrag_threshold,
        },
index d4df5b24d75e107061fe8db387948d5dc5c785c4..e6a7b01932e6cd82934242bd2ad287a11d2f683d 100644 (file)
@@ -222,7 +222,6 @@ config ENABLE_MUST_CHECK
 config FRAME_WARN
        int "Warn for stack frames larger than (needs gcc 4.4)"
        range 0 8192
-       default 3072 if KASAN_EXTRA
        default 2048 if GCC_PLUGIN_LATENT_ENTROPY
        default 1280 if (!64BIT && PARISC)
        default 1024 if (!64BIT && !PARISC)
@@ -266,23 +265,6 @@ config UNUSED_SYMBOLS
          you really need it, and what the merge plan to the mainline kernel for
          your module is.
 
-config PAGE_OWNER
-       bool "Track page owner"
-       depends on DEBUG_KERNEL && STACKTRACE_SUPPORT
-       select DEBUG_FS
-       select STACKTRACE
-       select STACKDEPOT
-       select PAGE_EXTENSION
-       help
-         This keeps track of what call chain is the owner of a page, may
-         help to find bare alloc_page(s) leaks. Even if you include this
-         feature on your build, it is disabled in default. You should pass
-         "page_owner=on" to boot parameter in order to enable it. Eats
-         a fair amount of memory if enabled. See tools/vm/page_owner_sort.c
-         for user-space helper.
-
-         If unsure, say N.
-
 config DEBUG_FS
        bool "Debug Filesystem"
        help
@@ -1876,6 +1858,19 @@ config TEST_LKM
 
          If unsure, say N.
 
+config TEST_VMALLOC
+       tristate "Test module for stress/performance analysis of vmalloc allocator"
+       default n
+       depends on MMU
+       depends on m
+       help
+         This builds the "test_vmalloc" module that should be used for
+         stress and performance analysis. So, any new change for vmalloc
+         subsystem can be evaluated from performance and stability point
+         of view.
+
+         If unsure, say N.
+
 config TEST_USER_COPY
        tristate "Test user/kernel boundary protections"
        depends on m
index 9737059ec58bb213fff5f80b0d34d39395c49904..9950b660e62d54ebee6b61ffe9b77e42e7e0f177 100644 (file)
@@ -78,16 +78,6 @@ config KASAN_SW_TAGS
 
 endchoice
 
-config KASAN_EXTRA
-       bool "KASAN: extra checks"
-       depends on KASAN_GENERIC && DEBUG_KERNEL && !COMPILE_TEST
-       help
-         This enables further checks in generic KASAN, for now it only
-         includes the address-use-after-scope check that can lead to
-         excessive kernel stack usage, frame size warnings and longer
-         compile time.
-         See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81715
-
 choice
        prompt "Instrumentation type"
        depends on KASAN
index e1b59da714186e3be67706a8c010c6253ea9500c..cbfacd55aeca732bfb980e2a28520603a5c28dd5 100644 (file)
@@ -60,6 +60,7 @@ UBSAN_SANITIZE_test_ubsan.o := y
 obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
 obj-$(CONFIG_TEST_LIST_SORT) += test_list_sort.o
 obj-$(CONFIG_TEST_LKM) += test_module.o
+obj-$(CONFIG_TEST_VMALLOC) += test_vmalloc.o
 obj-$(CONFIG_TEST_OVERFLOW) += test_overflow.o
 obj-$(CONFIG_TEST_RHASHTABLE) += test_rhashtable.o
 obj-$(CONFIG_TEST_SORT) += test_sort.o
index 8d666ab84b5c38fbcc0df25d7e6b0dbe0e81d68c..087a3e9a0202bd4ee0c6c03afb6137d284d4a671 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/cpumask.h>
 #include <linux/export.h>
 #include <linux/memblock.h>
+#include <linux/numa.h>
 
 /**
  * cpumask_next - get the next cpu in a cpumask
@@ -206,7 +207,7 @@ unsigned int cpumask_local_spread(unsigned int i, int node)
        /* Wrap: we always want a cpu. */
        i %= num_online_cpus();
 
-       if (node == -1) {
+       if (node == NUMA_NO_NODE) {
                for_each_cpu(cpu, cpu_online_mask)
                        if (i-- == 0)
                                return cpu;
index 51b78405bf24b7e4ae62168387f4b659c41bb110..7de2702621dc10ce0fe77617e5e4cd4573c7814f 100644 (file)
@@ -480,29 +480,6 @@ static noinline void __init copy_user_test(void)
        kfree(kmem);
 }
 
-static noinline void __init use_after_scope_test(void)
-{
-       volatile char *volatile p;
-
-       pr_info("use-after-scope on int\n");
-       {
-               int local = 0;
-
-               p = (char *)&local;
-       }
-       p[0] = 1;
-       p[3] = 1;
-
-       pr_info("use-after-scope on array\n");
-       {
-               char local[1024] = {0};
-
-               p = local;
-       }
-       p[0] = 1;
-       p[1023] = 1;
-}
-
 static noinline void __init kasan_alloca_oob_left(void)
 {
        volatile int i = 10;
@@ -682,7 +659,6 @@ static int __init kmalloc_tests_init(void)
        kasan_alloca_oob_right();
        ksize_unpoisons_memory();
        copy_user_test();
-       use_after_scope_test();
        kmem_cache_double_free();
        kmem_cache_invalid_free();
        kasan_memchr();
diff --git a/lib/test_vmalloc.c b/lib/test_vmalloc.c
new file mode 100644 (file)
index 0000000..83cdcaa
--- /dev/null
@@ -0,0 +1,551 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Test module for stress and analyze performance of vmalloc allocator.
+ * (C) 2018 Uladzislau Rezki (Sony) <urezki@gmail.com>
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/random.h>
+#include <linux/kthread.h>
+#include <linux/moduleparam.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/rwsem.h>
+#include <linux/mm.h>
+
+#define __param(type, name, init, msg)         \
+       static type name = init;                                \
+       module_param(name, type, 0444);                 \
+       MODULE_PARM_DESC(name, msg)                             \
+
+__param(bool, single_cpu_test, false,
+       "Use single first online CPU to run tests");
+
+__param(bool, sequential_test_order, false,
+       "Use sequential stress tests order");
+
+__param(int, test_repeat_count, 1,
+       "Set test repeat counter");
+
+__param(int, test_loop_count, 1000000,
+       "Set test loop counter");
+
+__param(int, run_test_mask, INT_MAX,
+       "Set tests specified in the mask.\n\n"
+               "\t\tid: 1,   name: fix_size_alloc_test\n"
+               "\t\tid: 2,   name: full_fit_alloc_test\n"
+               "\t\tid: 4,   name: long_busy_list_alloc_test\n"
+               "\t\tid: 8,   name: random_size_alloc_test\n"
+               "\t\tid: 16,  name: fix_align_alloc_test\n"
+               "\t\tid: 32,  name: random_size_align_alloc_test\n"
+               "\t\tid: 64,  name: align_shift_alloc_test\n"
+               "\t\tid: 128, name: pcpu_alloc_test\n"
+               /* Add a new test case description here. */
+);
+
+/*
+ * Depends on single_cpu_test parameter. If it is true, then
+ * use first online CPU to trigger a test on, otherwise go with
+ * all online CPUs.
+ */
+static cpumask_t cpus_run_test_mask = CPU_MASK_NONE;
+
+/*
+ * Read write semaphore for synchronization of setup
+ * phase that is done in main thread and workers.
+ */
+static DECLARE_RWSEM(prepare_for_test_rwsem);
+
+/*
+ * Completion tracking for worker threads.
+ */
+static DECLARE_COMPLETION(test_all_done_comp);
+static atomic_t test_n_undone = ATOMIC_INIT(0);
+
+static inline void
+test_report_one_done(void)
+{
+       if (atomic_dec_and_test(&test_n_undone))
+               complete(&test_all_done_comp);
+}
+
+static int random_size_align_alloc_test(void)
+{
+       unsigned long size, align, rnd;
+       void *ptr;
+       int i;
+
+       for (i = 0; i < test_loop_count; i++) {
+               get_random_bytes(&rnd, sizeof(rnd));
+
+               /*
+                * Maximum 1024 pages, if PAGE_SIZE is 4096.
+                */
+               align = 1 << (rnd % 23);
+
+               /*
+                * Maximum 10 pages.
+                */
+               size = ((rnd % 10) + 1) * PAGE_SIZE;
+
+               ptr = __vmalloc_node_range(size, align,
+                  VMALLOC_START, VMALLOC_END,
+                  GFP_KERNEL | __GFP_ZERO,
+                  PAGE_KERNEL,
+                  0, 0, __builtin_return_address(0));
+
+               if (!ptr)
+                       return -1;
+
+               vfree(ptr);
+       }
+
+       return 0;
+}
+
+/*
+ * This test case is supposed to be failed.
+ */
+static int align_shift_alloc_test(void)
+{
+       unsigned long align;
+       void *ptr;
+       int i;
+
+       for (i = 0; i < BITS_PER_LONG; i++) {
+               align = ((unsigned long) 1) << i;
+
+               ptr = __vmalloc_node_range(PAGE_SIZE, align,
+                       VMALLOC_START, VMALLOC_END,
+                       GFP_KERNEL | __GFP_ZERO,
+                       PAGE_KERNEL,
+                       0, 0, __builtin_return_address(0));
+
+               if (!ptr)
+                       return -1;
+
+               vfree(ptr);
+       }
+
+       return 0;
+}
+
+static int fix_align_alloc_test(void)
+{
+       void *ptr;
+       int i;
+
+       for (i = 0; i < test_loop_count; i++) {
+               ptr = __vmalloc_node_range(5 * PAGE_SIZE,
+                       THREAD_ALIGN << 1,
+                       VMALLOC_START, VMALLOC_END,
+                       GFP_KERNEL | __GFP_ZERO,
+                       PAGE_KERNEL,
+                       0, 0, __builtin_return_address(0));
+
+               if (!ptr)
+                       return -1;
+
+               vfree(ptr);
+       }
+
+       return 0;
+}
+
+static int random_size_alloc_test(void)
+{
+       unsigned int n;
+       void *p;
+       int i;
+
+       for (i = 0; i < test_loop_count; i++) {
+               get_random_bytes(&n, sizeof(i));
+               n = (n % 100) + 1;
+
+               p = vmalloc(n * PAGE_SIZE);
+
+               if (!p)
+                       return -1;
+
+               *((__u8 *)p) = 1;
+               vfree(p);
+       }
+
+       return 0;
+}
+
+static int long_busy_list_alloc_test(void)
+{
+       void *ptr_1, *ptr_2;
+       void **ptr;
+       int rv = -1;
+       int i;
+
+       ptr = vmalloc(sizeof(void *) * 15000);
+       if (!ptr)
+               return rv;
+
+       for (i = 0; i < 15000; i++)
+               ptr[i] = vmalloc(1 * PAGE_SIZE);
+
+       for (i = 0; i < test_loop_count; i++) {
+               ptr_1 = vmalloc(100 * PAGE_SIZE);
+               if (!ptr_1)
+                       goto leave;
+
+               ptr_2 = vmalloc(1 * PAGE_SIZE);
+               if (!ptr_2) {
+                       vfree(ptr_1);
+                       goto leave;
+               }
+
+               *((__u8 *)ptr_1) = 0;
+               *((__u8 *)ptr_2) = 1;
+
+               vfree(ptr_1);
+               vfree(ptr_2);
+       }
+
+       /*  Success */
+       rv = 0;
+
+leave:
+       for (i = 0; i < 15000; i++)
+               vfree(ptr[i]);
+
+       vfree(ptr);
+       return rv;
+}
+
+static int full_fit_alloc_test(void)
+{
+       void **ptr, **junk_ptr, *tmp;
+       int junk_length;
+       int rv = -1;
+       int i;
+
+       junk_length = fls(num_online_cpus());
+       junk_length *= (32 * 1024 * 1024 / PAGE_SIZE);
+
+       ptr = vmalloc(sizeof(void *) * junk_length);
+       if (!ptr)
+               return rv;
+
+       junk_ptr = vmalloc(sizeof(void *) * junk_length);
+       if (!junk_ptr) {
+               vfree(ptr);
+               return rv;
+       }
+
+       for (i = 0; i < junk_length; i++) {
+               ptr[i] = vmalloc(1 * PAGE_SIZE);
+               junk_ptr[i] = vmalloc(1 * PAGE_SIZE);
+       }
+
+       for (i = 0; i < junk_length; i++)
+               vfree(junk_ptr[i]);
+
+       for (i = 0; i < test_loop_count; i++) {
+               tmp = vmalloc(1 * PAGE_SIZE);
+
+               if (!tmp)
+                       goto error;
+
+               *((__u8 *)tmp) = 1;
+               vfree(tmp);
+       }
+
+       /* Success */
+       rv = 0;
+
+error:
+       for (i = 0; i < junk_length; i++)
+               vfree(ptr[i]);
+
+       vfree(ptr);
+       vfree(junk_ptr);
+
+       return rv;
+}
+
+static int fix_size_alloc_test(void)
+{
+       void *ptr;
+       int i;
+
+       for (i = 0; i < test_loop_count; i++) {
+               ptr = vmalloc(3 * PAGE_SIZE);
+
+               if (!ptr)
+                       return -1;
+
+               *((__u8 *)ptr) = 0;
+
+               vfree(ptr);
+       }
+
+       return 0;
+}
+
+static int
+pcpu_alloc_test(void)
+{
+       int rv = 0;
+#ifndef CONFIG_NEED_PER_CPU_KM
+       void __percpu **pcpu;
+       size_t size, align;
+       int i;
+
+       pcpu = vmalloc(sizeof(void __percpu *) * 35000);
+       if (!pcpu)
+               return -1;
+
+       for (i = 0; i < 35000; i++) {
+               unsigned int r;
+
+               get_random_bytes(&r, sizeof(i));
+               size = (r % (PAGE_SIZE / 4)) + 1;
+
+               /*
+                * Maximum PAGE_SIZE
+                */
+               get_random_bytes(&r, sizeof(i));
+               align = 1 << ((i % 11) + 1);
+
+               pcpu[i] = __alloc_percpu(size, align);
+               if (!pcpu[i])
+                       rv = -1;
+       }
+
+       for (i = 0; i < 35000; i++)
+               free_percpu(pcpu[i]);
+
+       vfree(pcpu);
+#endif
+       return rv;
+}
+
+struct test_case_desc {
+       const char *test_name;
+       int (*test_func)(void);
+};
+
+static struct test_case_desc test_case_array[] = {
+       { "fix_size_alloc_test", fix_size_alloc_test },
+       { "full_fit_alloc_test", full_fit_alloc_test },
+       { "long_busy_list_alloc_test", long_busy_list_alloc_test },
+       { "random_size_alloc_test", random_size_alloc_test },
+       { "fix_align_alloc_test", fix_align_alloc_test },
+       { "random_size_align_alloc_test", random_size_align_alloc_test },
+       { "align_shift_alloc_test", align_shift_alloc_test },
+       { "pcpu_alloc_test", pcpu_alloc_test },
+       /* Add a new test case here. */
+};
+
+struct test_case_data {
+       int test_failed;
+       int test_passed;
+       u64 time;
+};
+
+/* Split it to get rid of: WARNING: line over 80 characters */
+static struct test_case_data
+       per_cpu_test_data[NR_CPUS][ARRAY_SIZE(test_case_array)];
+
+static struct test_driver {
+       struct task_struct *task;
+       unsigned long start;
+       unsigned long stop;
+       int cpu;
+} per_cpu_test_driver[NR_CPUS];
+
+static void shuffle_array(int *arr, int n)
+{
+       unsigned int rnd;
+       int i, j, x;
+
+       for (i = n - 1; i > 0; i--)  {
+               get_random_bytes(&rnd, sizeof(rnd));
+
+               /* Cut the range. */
+               j = rnd % i;
+
+               /* Swap indexes. */
+               x = arr[i];
+               arr[i] = arr[j];
+               arr[j] = x;
+       }
+}
+
+static int test_func(void *private)
+{
+       struct test_driver *t = private;
+       cpumask_t newmask = CPU_MASK_NONE;
+       int random_array[ARRAY_SIZE(test_case_array)];
+       int index, i, j, ret;
+       ktime_t kt;
+       u64 delta;
+
+       cpumask_set_cpu(t->cpu, &newmask);
+       set_cpus_allowed_ptr(current, &newmask);
+
+       for (i = 0; i < ARRAY_SIZE(test_case_array); i++)
+               random_array[i] = i;
+
+       if (!sequential_test_order)
+               shuffle_array(random_array, ARRAY_SIZE(test_case_array));
+
+       /*
+        * Block until initialization is done.
+        */
+       down_read(&prepare_for_test_rwsem);
+
+       t->start = get_cycles();
+       for (i = 0; i < ARRAY_SIZE(test_case_array); i++) {
+               index = random_array[i];
+
+               /*
+                * Skip tests if run_test_mask has been specified.
+                */
+               if (!((run_test_mask & (1 << index)) >> index))
+                       continue;
+
+               kt = ktime_get();
+               for (j = 0; j < test_repeat_count; j++) {
+                       ret = test_case_array[index].test_func();
+                       if (!ret)
+                               per_cpu_test_data[t->cpu][index].test_passed++;
+                       else
+                               per_cpu_test_data[t->cpu][index].test_failed++;
+               }
+
+               /*
+                * Take an average time that test took.
+                */
+               delta = (u64) ktime_us_delta(ktime_get(), kt);
+               do_div(delta, (u32) test_repeat_count);
+
+               per_cpu_test_data[t->cpu][index].time = delta;
+       }
+       t->stop = get_cycles();
+
+       up_read(&prepare_for_test_rwsem);
+       test_report_one_done();
+
+       /*
+        * Wait for the kthread_stop() call.
+        */
+       while (!kthread_should_stop())
+               msleep(10);
+
+       return 0;
+}
+
+static void
+init_test_configurtion(void)
+{
+       /*
+        * Reset all data of all CPUs.
+        */
+       memset(per_cpu_test_data, 0, sizeof(per_cpu_test_data));
+
+       if (single_cpu_test)
+               cpumask_set_cpu(cpumask_first(cpu_online_mask),
+                       &cpus_run_test_mask);
+       else
+               cpumask_and(&cpus_run_test_mask, cpu_online_mask,
+                       cpu_online_mask);
+
+       if (test_repeat_count <= 0)
+               test_repeat_count = 1;
+
+       if (test_loop_count <= 0)
+               test_loop_count = 1;
+}
+
+static void do_concurrent_test(void)
+{
+       int cpu, ret;
+
+       /*
+        * Set some basic configurations plus sanity check.
+        */
+       init_test_configurtion();
+
+       /*
+        * Put on hold all workers.
+        */
+       down_write(&prepare_for_test_rwsem);
+
+       for_each_cpu(cpu, &cpus_run_test_mask) {
+               struct test_driver *t = &per_cpu_test_driver[cpu];
+
+               t->cpu = cpu;
+               t->task = kthread_run(test_func, t, "vmalloc_test/%d", cpu);
+
+               if (!IS_ERR(t->task))
+                       /* Success. */
+                       atomic_inc(&test_n_undone);
+               else
+                       pr_err("Failed to start kthread for %d CPU\n", cpu);
+       }
+
+       /*
+        * Now let the workers do their job.
+        */
+       up_write(&prepare_for_test_rwsem);
+
+       /*
+        * Sleep quiet until all workers are done with 1 second
+        * interval. Since the test can take a lot of time we
+        * can run into a stack trace of the hung task. That is
+        * why we go with completion_timeout and HZ value.
+        */
+       do {
+               ret = wait_for_completion_timeout(&test_all_done_comp, HZ);
+       } while (!ret);
+
+       for_each_cpu(cpu, &cpus_run_test_mask) {
+               struct test_driver *t = &per_cpu_test_driver[cpu];
+               int i;
+
+               if (!IS_ERR(t->task))
+                       kthread_stop(t->task);
+
+               for (i = 0; i < ARRAY_SIZE(test_case_array); i++) {
+                       if (!((run_test_mask & (1 << i)) >> i))
+                               continue;
+
+                       pr_info(
+                               "Summary: %s passed: %d failed: %d repeat: %d loops: %d avg: %llu usec\n",
+                               test_case_array[i].test_name,
+                               per_cpu_test_data[cpu][i].test_passed,
+                               per_cpu_test_data[cpu][i].test_failed,
+                               test_repeat_count, test_loop_count,
+                               per_cpu_test_data[cpu][i].time);
+               }
+
+               pr_info("All test took CPU%d=%lu cycles\n",
+                       cpu, t->stop - t->start);
+       }
+}
+
+static int vmalloc_test_init(void)
+{
+       do_concurrent_test();
+       return -EAGAIN; /* Fail will directly unload the module */
+}
+
+static void vmalloc_test_exit(void)
+{
+}
+
+module_init(vmalloc_test_init)
+module_exit(vmalloc_test_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Uladzislau Rezki");
+MODULE_DESCRIPTION("vmalloc test module");
index 9a7b8b049d04fb42ca02783eabf5e70ef9fe5495..e3df921208c0d81edd6d9a981ffc010bc4eea072 100644 (file)
@@ -39,6 +39,23 @@ config DEBUG_PAGEALLOC_ENABLE_DEFAULT
          Enable debug page memory allocations by default? This value
          can be overridden by debug_pagealloc=off|on.
 
+config PAGE_OWNER
+       bool "Track page owner"
+       depends on DEBUG_KERNEL && STACKTRACE_SUPPORT
+       select DEBUG_FS
+       select STACKTRACE
+       select STACKDEPOT
+       select PAGE_EXTENSION
+       help
+         This keeps track of what call chain is the owner of a page, may
+         help to find bare alloc_page(s) leaks. Even if you include this
+         feature on your build, it is disabled in default. You should pass
+         "page_owner=on" to boot parameter in order to enable it. Eats
+         a fair amount of memory if enabled. See tools/vm/page_owner_sort.c
+         for user-space helper.
+
+         If unsure, say N.
+
 config PAGE_POISONING
        bool "Poison pages after freeing"
        select PAGE_POISONING_NO_SANITY if HIBERNATION
index c7b39dd3b4f65f07e6b3ed5582601b52c9d8393b..f4f3a8a57d8623aa4bdbb71ddb232a33a6493378 100644 (file)
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -353,12 +353,14 @@ int __init cma_declare_contiguous(phys_addr_t base,
 
        ret = cma_init_reserved_mem(base, size, order_per_bit, name, res_cma);
        if (ret)
-               goto err;
+               goto free_mem;
 
        pr_info("Reserved %ld MiB at %pa\n", (unsigned long)size / SZ_1M,
                &base);
        return 0;
 
+free_mem:
+       memblock_free(base, size);
 err:
        pr_err("Failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
        return ret;
index ad6723e9d110a9053c454e6aa3d0717364f9c587..8d7b2fd5222599a4045608e0b9b499eb91deb51f 100644 (file)
@@ -21,8 +21,6 @@ struct cma_mem {
        unsigned long n;
 };
 
-static struct dentry *cma_debugfs_root;
-
 static int cma_debugfs_get(void *data, u64 *val)
 {
        unsigned long *p = data;
@@ -162,7 +160,7 @@ static int cma_alloc_write(void *data, u64 val)
 }
 DEFINE_SIMPLE_ATTRIBUTE(cma_alloc_fops, NULL, cma_alloc_write, "%llu\n");
 
-static void cma_debugfs_add_one(struct cma *cma, int idx)
+static void cma_debugfs_add_one(struct cma *cma, struct dentry *root_dentry)
 {
        struct dentry *tmp;
        char name[16];
@@ -170,7 +168,7 @@ static void cma_debugfs_add_one(struct cma *cma, int idx)
 
        scnprintf(name, sizeof(name), "cma-%s", cma->name);
 
-       tmp = debugfs_create_dir(name, cma_debugfs_root);
+       tmp = debugfs_create_dir(name, root_dentry);
 
        debugfs_create_file("alloc", 0200, tmp, cma, &cma_alloc_fops);
        debugfs_create_file("free", 0200, tmp, cma, &cma_free_fops);
@@ -188,14 +186,13 @@ static void cma_debugfs_add_one(struct cma *cma, int idx)
 
 static int __init cma_debugfs_init(void)
 {
+       struct dentry *cma_debugfs_root;
        int i;
 
        cma_debugfs_root = debugfs_create_dir("cma", NULL);
-       if (!cma_debugfs_root)
-               return -ENOMEM;
 
        for (i = 0; i < cma_area_count; i++)
-               cma_debugfs_add_one(&cma_areas[i], i);
+               cma_debugfs_add_one(&cma_areas[i], cma_debugfs_root);
 
        return 0;
 }
index ef29490b0f462349ec90b8672448f80627ef3af6..f171a83707ced436bb2bd4508060a6cd45a95905 100644 (file)
@@ -66,7 +66,7 @@ static unsigned long release_freepages(struct list_head *freelist)
        return high_pfn;
 }
 
-static void map_pages(struct list_head *list)
+static void split_map_pages(struct list_head *list)
 {
        unsigned int i, order, nr_pages;
        struct page *page, *next;
@@ -237,6 +237,70 @@ static bool pageblock_skip_persistent(struct page *page)
        return false;
 }
 
+static bool
+__reset_isolation_pfn(struct zone *zone, unsigned long pfn, bool check_source,
+                                                       bool check_target)
+{
+       struct page *page = pfn_to_online_page(pfn);
+       struct page *end_page;
+       unsigned long block_pfn;
+
+       if (!page)
+               return false;
+       if (zone != page_zone(page))
+               return false;
+       if (pageblock_skip_persistent(page))
+               return false;
+
+       /*
+        * If skip is already cleared do no further checking once the
+        * restart points have been set.
+        */
+       if (check_source && check_target && !get_pageblock_skip(page))
+               return true;
+
+       /*
+        * If clearing skip for the target scanner, do not select a
+        * non-movable pageblock as the starting point.
+        */
+       if (!check_source && check_target &&
+           get_pageblock_migratetype(page) != MIGRATE_MOVABLE)
+               return false;
+
+       /*
+        * Only clear the hint if a sample indicates there is either a
+        * free page or an LRU page in the block. One or other condition
+        * is necessary for the block to be a migration source/target.
+        */
+       block_pfn = pageblock_start_pfn(pfn);
+       pfn = max(block_pfn, zone->zone_start_pfn);
+       page = pfn_to_page(pfn);
+       if (zone != page_zone(page))
+               return false;
+       pfn = block_pfn + pageblock_nr_pages;
+       pfn = min(pfn, zone_end_pfn(zone));
+       end_page = pfn_to_page(pfn);
+
+       do {
+               if (pfn_valid_within(pfn)) {
+                       if (check_source && PageLRU(page)) {
+                               clear_pageblock_skip(page);
+                               return true;
+                       }
+
+                       if (check_target && PageBuddy(page)) {
+                               clear_pageblock_skip(page);
+                               return true;
+                       }
+               }
+
+               page += (1 << PAGE_ALLOC_COSTLY_ORDER);
+               pfn += (1 << PAGE_ALLOC_COSTLY_ORDER);
+       } while (page < end_page);
+
+       return false;
+}
+
 /*
  * This function is called to clear all cached information on pageblocks that
  * should be skipped for page isolation when the migrate and free page scanner
@@ -244,30 +308,54 @@ static bool pageblock_skip_persistent(struct page *page)
  */
 static void __reset_isolation_suitable(struct zone *zone)
 {
-       unsigned long start_pfn = zone->zone_start_pfn;
-       unsigned long end_pfn = zone_end_pfn(zone);
-       unsigned long pfn;
+       unsigned long migrate_pfn = zone->zone_start_pfn;
+       unsigned long free_pfn = zone_end_pfn(zone);
+       unsigned long reset_migrate = free_pfn;
+       unsigned long reset_free = migrate_pfn;
+       bool source_set = false;
+       bool free_set = false;
+
+       if (!zone->compact_blockskip_flush)
+               return;
 
        zone->compact_blockskip_flush = false;
 
-       /* Walk the zone and mark every pageblock as suitable for isolation */
-       for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
-               struct page *page;
-
+       /*
+        * Walk the zone and update pageblock skip information. Source looks
+        * for PageLRU while target looks for PageBuddy. When the scanner
+        * is found, both PageBuddy and PageLRU are checked as the pageblock
+        * is suitable as both source and target.
+        */
+       for (; migrate_pfn < free_pfn; migrate_pfn += pageblock_nr_pages,
+                                       free_pfn -= pageblock_nr_pages) {
                cond_resched();
 
-               page = pfn_to_online_page(pfn);
-               if (!page)
-                       continue;
-               if (zone != page_zone(page))
-                       continue;
-               if (pageblock_skip_persistent(page))
-                       continue;
+               /* Update the migrate PFN */
+               if (__reset_isolation_pfn(zone, migrate_pfn, true, source_set) &&
+                   migrate_pfn < reset_migrate) {
+                       source_set = true;
+                       reset_migrate = migrate_pfn;
+                       zone->compact_init_migrate_pfn = reset_migrate;
+                       zone->compact_cached_migrate_pfn[0] = reset_migrate;
+                       zone->compact_cached_migrate_pfn[1] = reset_migrate;
+               }
 
-               clear_pageblock_skip(page);
+               /* Update the free PFN */
+               if (__reset_isolation_pfn(zone, free_pfn, free_set, true) &&
+                   free_pfn > reset_free) {
+                       free_set = true;
+                       reset_free = free_pfn;
+                       zone->compact_init_free_pfn = reset_free;
+                       zone->compact_cached_free_pfn = reset_free;
+               }
        }
 
-       reset_cached_positions(zone);
+       /* Leave no distance if no suitable block was reset */
+       if (reset_migrate >= reset_free) {
+               zone->compact_cached_migrate_pfn[0] = migrate_pfn;
+               zone->compact_cached_migrate_pfn[1] = migrate_pfn;
+               zone->compact_cached_free_pfn = free_pfn;
+       }
 }
 
 void reset_isolation_suitable(pg_data_t *pgdat)
@@ -285,16 +373,54 @@ void reset_isolation_suitable(pg_data_t *pgdat)
        }
 }
 
+/*
+ * Sets the pageblock skip bit if it was clear. Note that this is a hint as
+ * locks are not required for read/writers. Returns true if it was already set.
+ */
+static bool test_and_set_skip(struct compact_control *cc, struct page *page,
+                                                       unsigned long pfn)
+{
+       bool skip;
+
+       /* Do no update if skip hint is being ignored */
+       if (cc->ignore_skip_hint)
+               return false;
+
+       if (!IS_ALIGNED(pfn, pageblock_nr_pages))
+               return false;
+
+       skip = get_pageblock_skip(page);
+       if (!skip && !cc->no_set_skip_hint)
+               set_pageblock_skip(page);
+
+       return skip;
+}
+
+static void update_cached_migrate(struct compact_control *cc, unsigned long pfn)
+{
+       struct zone *zone = cc->zone;
+
+       pfn = pageblock_end_pfn(pfn);
+
+       /* Set for isolation rather than compaction */
+       if (cc->no_set_skip_hint)
+               return;
+
+       if (pfn > zone->compact_cached_migrate_pfn[0])
+               zone->compact_cached_migrate_pfn[0] = pfn;
+       if (cc->mode != MIGRATE_ASYNC &&
+           pfn > zone->compact_cached_migrate_pfn[1])
+               zone->compact_cached_migrate_pfn[1] = pfn;
+}
+
 /*
  * If no pages were isolated then mark this pageblock to be skipped in the
  * future. The information is later cleared by __reset_isolation_suitable().
  */
 static void update_pageblock_skip(struct compact_control *cc,
-                       struct page *page, unsigned long nr_isolated,
-                       bool migrate_scanner)
+                       struct page *page, unsigned long pfn)
 {
        struct zone *zone = cc->zone;
-       unsigned long pfn;
 
        if (cc->no_set_skip_hint)
                return;
@@ -302,24 +428,11 @@ static void update_pageblock_skip(struct compact_control *cc,
        if (!page)
                return;
 
-       if (nr_isolated)
-               return;
-
        set_pageblock_skip(page);
 
-       pfn = page_to_pfn(page);
-
        /* Update where async and sync compaction should restart */
-       if (migrate_scanner) {
-               if (pfn > zone->compact_cached_migrate_pfn[0])
-                       zone->compact_cached_migrate_pfn[0] = pfn;
-               if (cc->mode != MIGRATE_ASYNC &&
-                   pfn > zone->compact_cached_migrate_pfn[1])
-                       zone->compact_cached_migrate_pfn[1] = pfn;
-       } else {
-               if (pfn < zone->compact_cached_free_pfn)
-                       zone->compact_cached_free_pfn = pfn;
-       }
+       if (pfn < zone->compact_cached_free_pfn)
+               zone->compact_cached_free_pfn = pfn;
 }
 #else
 static inline bool isolation_suitable(struct compact_control *cc,
@@ -334,32 +447,42 @@ static inline bool pageblock_skip_persistent(struct page *page)
 }
 
 static inline void update_pageblock_skip(struct compact_control *cc,
-                       struct page *page, unsigned long nr_isolated,
-                       bool migrate_scanner)
+                       struct page *page, unsigned long pfn)
+{
+}
+
+static void update_cached_migrate(struct compact_control *cc, unsigned long pfn)
+{
+}
+
+static bool test_and_set_skip(struct compact_control *cc, struct page *page,
+                                                       unsigned long pfn)
 {
+       return false;
 }
 #endif /* CONFIG_COMPACTION */
 
 /*
  * Compaction requires the taking of some coarse locks that are potentially
- * very heavily contended. For async compaction, back out if the lock cannot
- * be taken immediately. For sync compaction, spin on the lock if needed.
+ * very heavily contended. For async compaction, trylock and record if the
+ * lock is contended. The lock will still be acquired but compaction will
+ * abort when the current block is finished regardless of success rate.
+ * Sync compaction acquires the lock.
  *
- * Returns true if the lock is held
- * Returns false if the lock is not held and compaction should abort
+ * Always returns true which makes it easier to track lock state in callers.
  */
-static bool compact_trylock_irqsave(spinlock_t *lock, unsigned long *flags,
+static bool compact_lock_irqsave(spinlock_t *lock, unsigned long *flags,
                                                struct compact_control *cc)
 {
-       if (cc->mode == MIGRATE_ASYNC) {
-               if (!spin_trylock_irqsave(lock, *flags)) {
-                       cc->contended = true;
-                       return false;
-               }
-       } else {
-               spin_lock_irqsave(lock, *flags);
+       /* Track if the lock is contended in async mode */
+       if (cc->mode == MIGRATE_ASYNC && !cc->contended) {
+               if (spin_trylock_irqsave(lock, *flags))
+                       return true;
+
+               cc->contended = true;
        }
 
+       spin_lock_irqsave(lock, *flags);
        return true;
 }
 
@@ -391,37 +514,7 @@ static bool compact_unlock_should_abort(spinlock_t *lock,
                return true;
        }
 
-       if (need_resched()) {
-               if (cc->mode == MIGRATE_ASYNC) {
-                       cc->contended = true;
-                       return true;
-               }
-               cond_resched();
-       }
-
-       return false;
-}
-
-/*
- * Aside from avoiding lock contention, compaction also periodically checks
- * need_resched() and either schedules in sync compaction or aborts async
- * compaction. This is similar to what compact_unlock_should_abort() does, but
- * is used where no lock is concerned.
- *
- * Returns false when no scheduling was needed, or sync compaction scheduled.
- * Returns true when async compaction should abort.
- */
-static inline bool compact_should_abort(struct compact_control *cc)
-{
-       /* async compaction aborts if contended */
-       if (need_resched()) {
-               if (cc->mode == MIGRATE_ASYNC) {
-                       cc->contended = true;
-                       return true;
-               }
-
-               cond_resched();
-       }
+       cond_resched();
 
        return false;
 }
@@ -435,19 +528,24 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
                                unsigned long *start_pfn,
                                unsigned long end_pfn,
                                struct list_head *freelist,
+                               unsigned int stride,
                                bool strict)
 {
        int nr_scanned = 0, total_isolated = 0;
-       struct page *cursor, *valid_page = NULL;
+       struct page *cursor;
        unsigned long flags = 0;
        bool locked = false;
        unsigned long blockpfn = *start_pfn;
        unsigned int order;
 
+       /* Strict mode is for isolation, speed is secondary */
+       if (strict)
+               stride = 1;
+
        cursor = pfn_to_page(blockpfn);
 
        /* Isolate free pages. */
-       for (; blockpfn < end_pfn; blockpfn++, cursor++) {
+       for (; blockpfn < end_pfn; blockpfn += stride, cursor += stride) {
                int isolated;
                struct page *page = cursor;
 
@@ -465,9 +563,6 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
                if (!pfn_valid_within(blockpfn))
                        goto isolate_fail;
 
-               if (!valid_page)
-                       valid_page = page;
-
                /*
                 * For compound pages such as THP and hugetlbfs, we can save
                 * potentially a lot of iterations if we skip them at once.
@@ -495,18 +590,8 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
                 * recheck as well.
                 */
                if (!locked) {
-                       /*
-                        * The zone lock must be held to isolate freepages.
-                        * Unfortunately this is a very coarse lock and can be
-                        * heavily contended if there are parallel allocations
-                        * or parallel compactions. For async compaction do not
-                        * spin on the lock and we acquire the lock as late as
-                        * possible.
-                        */
-                       locked = compact_trylock_irqsave(&cc->zone->lock,
+                       locked = compact_lock_irqsave(&cc->zone->lock,
                                                                &flags, cc);
-                       if (!locked)
-                               break;
 
                        /* Recheck this is a buddy page under lock */
                        if (!PageBuddy(page))
@@ -565,10 +650,6 @@ isolate_fail:
        if (strict && blockpfn < end_pfn)
                total_isolated = 0;
 
-       /* Update the pageblock-skip if the whole pageblock was scanned */
-       if (blockpfn == end_pfn)
-               update_pageblock_skip(cc, valid_page, total_isolated, false);
-
        cc->total_free_scanned += nr_scanned;
        if (total_isolated)
                count_compact_events(COMPACTISOLATED, total_isolated);
@@ -626,7 +707,7 @@ isolate_freepages_range(struct compact_control *cc,
                        break;
 
                isolated = isolate_freepages_block(cc, &isolate_start_pfn,
-                                               block_end_pfn, &freelist, true);
+                                       block_end_pfn, &freelist, 0, true);
 
                /*
                 * In strict mode, isolate_freepages_block() returns 0 if
@@ -644,7 +725,7 @@ isolate_freepages_range(struct compact_control *cc,
        }
 
        /* __isolate_free_page() does not map the pages */
-       map_pages(&freelist);
+       split_map_pages(&freelist);
 
        if (pfn < end_pfn) {
                /* Loop terminated early, cleanup. */
@@ -657,16 +738,16 @@ isolate_freepages_range(struct compact_control *cc,
 }
 
 /* Similar to reclaim, but different enough that they don't share logic */
-static bool too_many_isolated(struct zone *zone)
+static bool too_many_isolated(pg_data_t *pgdat)
 {
        unsigned long active, inactive, isolated;
 
-       inactive = node_page_state(zone->zone_pgdat, NR_INACTIVE_FILE) +
-                       node_page_state(zone->zone_pgdat, NR_INACTIVE_ANON);
-       active = node_page_state(zone->zone_pgdat, NR_ACTIVE_FILE) +
-                       node_page_state(zone->zone_pgdat, NR_ACTIVE_ANON);
-       isolated = node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE) +
-                       node_page_state(zone->zone_pgdat, NR_ISOLATED_ANON);
+       inactive = node_page_state(pgdat, NR_INACTIVE_FILE) +
+                       node_page_state(pgdat, NR_INACTIVE_ANON);
+       active = node_page_state(pgdat, NR_ACTIVE_FILE) +
+                       node_page_state(pgdat, NR_ACTIVE_ANON);
+       isolated = node_page_state(pgdat, NR_ISOLATED_FILE) +
+                       node_page_state(pgdat, NR_ISOLATED_ANON);
 
        return isolated > (inactive + active) / 2;
 }
@@ -693,7 +774,7 @@ static unsigned long
 isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                        unsigned long end_pfn, isolate_mode_t isolate_mode)
 {
-       struct zone *zone = cc->zone;
+       pg_data_t *pgdat = cc->zone->zone_pgdat;
        unsigned long nr_scanned = 0, nr_isolated = 0;
        struct lruvec *lruvec;
        unsigned long flags = 0;
@@ -702,13 +783,14 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
        unsigned long start_pfn = low_pfn;
        bool skip_on_failure = false;
        unsigned long next_skip_pfn = 0;
+       bool skip_updated = false;
 
        /*
         * Ensure that there are not too many pages isolated from the LRU
         * list by either parallel reclaimers or compaction. If there are,
         * delay for some time until fewer pages are isolated
         */
-       while (unlikely(too_many_isolated(zone))) {
+       while (unlikely(too_many_isolated(pgdat))) {
                /* async migration should just abort */
                if (cc->mode == MIGRATE_ASYNC)
                        return 0;
@@ -719,8 +801,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                        return 0;
        }
 
-       if (compact_should_abort(cc))
-               return 0;
+       cond_resched();
 
        if (cc->direct_compaction && (cc->mode == MIGRATE_ASYNC)) {
                skip_on_failure = true;
@@ -758,8 +839,8 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                 * if contended.
                 */
                if (!(low_pfn % SWAP_CLUSTER_MAX)
-                   && compact_unlock_should_abort(zone_lru_lock(zone), flags,
-                                                               &locked, cc))
+                   && compact_unlock_should_abort(&pgdat->lru_lock,
+                                           flags, &locked, cc))
                        break;
 
                if (!pfn_valid_within(low_pfn))
@@ -768,8 +849,19 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
 
                page = pfn_to_page(low_pfn);
 
-               if (!valid_page)
+               /*
+                * Check if the pageblock has already been marked skipped.
+                * Only the aligned PFN is checked as the caller isolates
+                * COMPACT_CLUSTER_MAX at a time so the second call must
+                * not falsely conclude that the block should be skipped.
+                */
+               if (!valid_page && IS_ALIGNED(low_pfn, pageblock_nr_pages)) {
+                       if (!cc->ignore_skip_hint && get_pageblock_skip(page)) {
+                               low_pfn = end_pfn;
+                               goto isolate_abort;
+                       }
                        valid_page = page;
+               }
 
                /*
                 * Skip if free. We read page order here without zone lock
@@ -818,7 +910,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                        if (unlikely(__PageMovable(page)) &&
                                        !PageIsolated(page)) {
                                if (locked) {
-                                       spin_unlock_irqrestore(zone_lru_lock(zone),
+                                       spin_unlock_irqrestore(&pgdat->lru_lock,
                                                                        flags);
                                        locked = false;
                                }
@@ -848,10 +940,15 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
 
                /* If we already hold the lock, we can skip some rechecking */
                if (!locked) {
-                       locked = compact_trylock_irqsave(zone_lru_lock(zone),
+                       locked = compact_lock_irqsave(&pgdat->lru_lock,
                                                                &flags, cc);
-                       if (!locked)
-                               break;
+
+                       /* Try get exclusive access under lock */
+                       if (!skip_updated) {
+                               skip_updated = true;
+                               if (test_and_set_skip(cc, page, low_pfn))
+                                       goto isolate_abort;
+                       }
 
                        /* Recheck PageLRU and PageCompound under lock */
                        if (!PageLRU(page))
@@ -868,7 +965,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                        }
                }
 
-               lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat);
+               lruvec = mem_cgroup_page_lruvec(page, pgdat);
 
                /* Try isolate the page */
                if (__isolate_lru_page(page, isolate_mode) != 0)
@@ -887,16 +984,13 @@ isolate_success:
                nr_isolated++;
 
                /*
-                * Record where we could have freed pages by migration and not
-                * yet flushed them to buddy allocator.
-                * - this is the lowest page that was isolated and likely be
-                * then freed by migration.
+                * Avoid isolating too much unless this block is being
+                * rescanned (e.g. dirty/writeback pages, parallel allocation)
+                * or a lock is contended. For contention, isolate quickly to
+                * potentially remove one source of contention.
                 */
-               if (!cc->last_migrated_pfn)
-                       cc->last_migrated_pfn = low_pfn;
-
-               /* Avoid isolating too much */
-               if (cc->nr_migratepages == COMPACT_CLUSTER_MAX) {
+               if (cc->nr_migratepages == COMPACT_CLUSTER_MAX &&
+                   !cc->rescan && !cc->contended) {
                        ++low_pfn;
                        break;
                }
@@ -913,12 +1007,11 @@ isolate_fail:
                 */
                if (nr_isolated) {
                        if (locked) {
-                               spin_unlock_irqrestore(zone_lru_lock(zone), flags);
+                               spin_unlock_irqrestore(&pgdat->lru_lock, flags);
                                locked = false;
                        }
                        putback_movable_pages(&cc->migratepages);
                        cc->nr_migratepages = 0;
-                       cc->last_migrated_pfn = 0;
                        nr_isolated = 0;
                }
 
@@ -939,15 +1032,23 @@ isolate_fail:
        if (unlikely(low_pfn > end_pfn))
                low_pfn = end_pfn;
 
+isolate_abort:
        if (locked)
-               spin_unlock_irqrestore(zone_lru_lock(zone), flags);
+               spin_unlock_irqrestore(&pgdat->lru_lock, flags);
 
        /*
-        * Update the pageblock-skip information and cached scanner pfn,
-        * if the whole pageblock was scanned without isolating any page.
+        * Updated the cached scanner pfn once the pageblock has been scanned
+        * Pages will either be migrated in which case there is no point
+        * scanning in the near future or migration failed in which case the
+        * failure reason may persist. The block is marked for skipping if
+        * there were no pages isolated in the block or if the block is
+        * rescanned twice in a row.
         */
-       if (low_pfn == end_pfn)
-               update_pageblock_skip(cc, valid_page, nr_isolated, true);
+       if (low_pfn == end_pfn && (!nr_isolated || cc->rescan)) {
+               if (valid_page && !skip_updated)
+                       set_pageblock_skip(valid_page);
+               update_cached_migrate(cc, low_pfn);
+       }
 
        trace_mm_compaction_isolate_migratepages(start_pfn, low_pfn,
                                                nr_scanned, nr_isolated);
@@ -1013,6 +1114,9 @@ static bool suitable_migration_source(struct compact_control *cc,
 {
        int block_mt;
 
+       if (pageblock_skip_persistent(page))
+               return false;
+
        if ((cc->mode != MIGRATE_ASYNC) || !cc->direct_compaction)
                return true;
 
@@ -1050,6 +1154,12 @@ static bool suitable_migration_target(struct compact_control *cc,
        return false;
 }
 
+static inline unsigned int
+freelist_scan_limit(struct compact_control *cc)
+{
+       return (COMPACT_CLUSTER_MAX >> cc->fast_search_fail) + 1;
+}
+
 /*
  * Test whether the free scanner has reached the same or lower pageblock than
  * the migration scanner, and compaction should thus terminate.
@@ -1060,6 +1170,248 @@ static inline bool compact_scanners_met(struct compact_control *cc)
                <= (cc->migrate_pfn >> pageblock_order);
 }
 
+/*
+ * Used when scanning for a suitable migration target which scans freelists
+ * in reverse. Reorders the list such as the unscanned pages are scanned
+ * first on the next iteration of the free scanner
+ */
+static void
+move_freelist_head(struct list_head *freelist, struct page *freepage)
+{
+       LIST_HEAD(sublist);
+
+       if (!list_is_last(freelist, &freepage->lru)) {
+               list_cut_before(&sublist, freelist, &freepage->lru);
+               if (!list_empty(&sublist))
+                       list_splice_tail(&sublist, freelist);
+       }
+}
+
+/*
+ * Similar to move_freelist_head except used by the migration scanner
+ * when scanning forward. It's possible for these list operations to
+ * move against each other if they search the free list exactly in
+ * lockstep.
+ */
+static void
+move_freelist_tail(struct list_head *freelist, struct page *freepage)
+{
+       LIST_HEAD(sublist);
+