summaryrefslogtreecommitdiff
path: root/mm
diff options
context:
space:
mode:
Diffstat (limited to 'mm')
-rw-r--r--mm/Kconfig15
-rw-r--r--mm/Makefile1
-rw-r--r--mm/backing-dev.c6
-rw-r--r--mm/cma.c4
-rw-r--r--mm/compaction.c105
-rw-r--r--mm/damon/core-test.h74
-rw-r--r--mm/damon/core.c62
-rw-r--r--mm/damon/ops-common.c2
-rw-r--r--mm/damon/paddr.c2
-rw-r--r--mm/damon/sysfs-common.h2
-rw-r--r--mm/damon/sysfs-schemes.c107
-rw-r--r--mm/damon/sysfs.c26
-rw-r--r--mm/damon/vaddr.c23
-rw-r--r--mm/debug_vm_pgtable.c18
-rw-r--r--mm/filemap.c19
-rw-r--r--mm/frontswap.c283
-rw-r--r--mm/gup.c90
-rw-r--r--mm/huge_memory.c87
-rw-r--r--mm/hugetlb.c439
-rw-r--r--mm/hugetlb_vmemmap.c34
-rw-r--r--mm/init-mm.c2
-rw-r--r--mm/internal.h61
-rw-r--r--mm/ioremap.c41
-rw-r--r--mm/kfence/core.c123
-rw-r--r--mm/kfence/kfence.h5
-rw-r--r--mm/khugepaged.c476
-rw-r--r--mm/kmemleak.c15
-rw-r--r--mm/kmsan/hooks.c4
-rw-r--r--mm/kmsan/shadow.c8
-rw-r--r--mm/ksm.c44
-rw-r--r--mm/madvise.c11
-rw-r--r--mm/memblock.c5
-rw-r--r--mm/memcontrol.c35
-rw-r--r--mm/memfd.c58
-rw-r--r--mm/memory-failure.c130
-rw-r--r--mm/memory-tiers.c19
-rw-r--r--mm/memory.c233
-rw-r--r--mm/memory_hotplug.c192
-rw-r--r--mm/mempolicy.c15
-rw-r--r--mm/memtest.c22
-rw-r--r--mm/migrate.c5
-rw-r--r--mm/migrate_device.c30
-rw-r--r--mm/mlock.c3
-rw-r--r--mm/mm_init.c37
-rw-r--r--mm/mmap.c255
-rw-r--r--mm/mmu_notifier.c50
-rw-r--r--mm/mprotect.c7
-rw-r--r--mm/mremap.c2
-rw-r--r--mm/nommu.c55
-rw-r--r--mm/oom_kill.c3
-rw-r--r--mm/page_alloc.c150
-rw-r--r--mm/page_ext.c101
-rw-r--r--mm/page_io.c80
-rw-r--r--mm/page_isolation.c8
-rw-r--r--mm/page_owner.c2
-rw-r--r--mm/page_poison.c1
-rw-r--r--mm/page_table_check.c52
-rw-r--r--mm/page_vma_mapped.c12
-rw-r--r--mm/pgtable-generic.c97
-rw-r--r--mm/rmap.c83
-rw-r--r--mm/secretmem.c14
-rw-r--r--mm/shmem.c9
-rw-r--r--mm/show_mem.c10
-rw-r--r--mm/sparse-vmemmap.c3
-rw-r--r--mm/sparse.c3
-rw-r--r--mm/swap_state.c5
-rw-r--r--mm/swapfile.c63
-rw-r--r--mm/truncate.c8
-rw-r--r--mm/userfaultfd.c87
-rw-r--r--mm/util.c6
-rw-r--r--mm/vmscan.c42
-rw-r--r--mm/vmstat.c1
-rw-r--r--mm/z3fold.c27
-rw-r--r--mm/zsmalloc.c79
-rw-r--r--mm/zswap.c393
75 files changed, 2323 insertions, 2358 deletions
diff --git a/mm/Kconfig b/mm/Kconfig
index 09130434e30d..721dc88423c7 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -25,7 +25,6 @@ menuconfig SWAP
config ZSWAP
bool "Compressed cache for swap pages"
depends on SWAP
- select FRONTSWAP
select CRYPTO
select ZPOOL
help
@@ -487,7 +486,10 @@ config SPARSEMEM_VMEMMAP
# Select this config option from the architecture Kconfig, if it is preferred
# to enable the feature of HugeTLB/dev_dax vmemmap optimization.
#
-config ARCH_WANT_OPTIMIZE_VMEMMAP
+config ARCH_WANT_OPTIMIZE_DAX_VMEMMAP
+ bool
+
+config ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP
bool
config HAVE_MEMBLOCK_PHYS_MAP
@@ -569,6 +571,9 @@ config MHP_MEMMAP_ON_MEMORY
endif # MEMORY_HOTPLUG
+config ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE
+ bool
+
# Heavily threaded applications may benefit from splitting the mm-wide
# page_table_lock, so that faults on different parts of the user address
# space can be handled with less contention: split it at this NR_CPUS.
@@ -870,9 +875,6 @@ config USE_PERCPU_NUMA_NODE_ID
config HAVE_SETUP_PER_CPU_AREA
bool
-config FRONTSWAP
- bool
-
config CMA
bool "Contiguous Memory Allocator"
depends on MMU
@@ -1144,6 +1146,9 @@ config KMAP_LOCAL_NON_LINEAR_PTE_ARRAY
config IO_MAPPING
bool
+config MEMFD_CREATE
+ bool "Enable memfd_create() system call" if EXPERT
+
config SECRETMEM
default y
bool "Enable memfd_secret() system call" if EXPERT
diff --git a/mm/Makefile b/mm/Makefile
index 678530a07326..e6d9a1d5e84d 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -72,7 +72,6 @@ ifdef CONFIG_MMU
endif
obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o swap_slots.o
-obj-$(CONFIG_FRONTSWAP) += frontswap.o
obj-$(CONFIG_ZSWAP) += zswap.o
obj-$(CONFIG_HAS_DMA) += dmapool.o
obj-$(CONFIG_HUGETLBFS) += hugetlb.o
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 3ffc3cfa7a14..1e3447bccdb1 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -16,6 +16,7 @@
#include <linux/writeback.h>
#include <linux/device.h>
#include <trace/events/writeback.h>
+#include "internal.h"
struct backing_dev_info noop_backing_dev_info;
EXPORT_SYMBOL_GPL(noop_backing_dev_info);
@@ -34,8 +35,6 @@ LIST_HEAD(bdi_list);
/* bdi_wq serves all asynchronous writeback tasks */
struct workqueue_struct *bdi_wq;
-#define K(x) ((x) << (PAGE_SHIFT - 10))
-
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/seq_file.h>
@@ -733,9 +732,6 @@ struct bdi_writeback *wb_get_create(struct backing_dev_info *bdi,
might_alloc(gfp);
- if (!memcg_css->parent)
- return &bdi->wb;
-
do {
wb = wb_get_lookup(bdi, memcg_css);
} while (!wb && !cgwb_create(bdi, memcg_css, gfp));
diff --git a/mm/cma.c b/mm/cma.c
index a4cfe995e11e..4880f72102fa 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -436,8 +436,8 @@ struct page *cma_alloc(struct cma *cma, unsigned long count,
if (!cma || !cma->count || !cma->bitmap)
goto out;
- pr_debug("%s(cma %p, count %lu, align %d)\n", __func__, (void *)cma,
- count, align);
+ pr_debug("%s(cma %p, name: %s, count %lu, align %d)\n", __func__,
+ (void *)cma, cma->name, count, align);
if (!count)
goto out;
diff --git a/mm/compaction.c b/mm/compaction.c
index eacca2794e47..38c8d216c6a3 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -249,11 +249,36 @@ static unsigned long skip_offline_sections(unsigned long start_pfn)
return 0;
}
+
+/*
+ * If the PFN falls into an offline section, return the end PFN of the
+ * next online section in reverse. If the PFN falls into an online section
+ * or if there is no next online section in reverse, return 0.
+ */
+static unsigned long skip_offline_sections_reverse(unsigned long start_pfn)
+{
+ unsigned long start_nr = pfn_to_section_nr(start_pfn);
+
+ if (!start_nr || online_section_nr(start_nr))
+ return 0;
+
+ while (start_nr-- > 0) {
+ if (online_section_nr(start_nr))
+ return section_nr_to_pfn(start_nr) + PAGES_PER_SECTION;
+ }
+
+ return 0;
+}
#else
static unsigned long skip_offline_sections(unsigned long start_pfn)
{
return 0;
}
+
+static unsigned long skip_offline_sections_reverse(unsigned long start_pfn)
+{
+ return 0;
+}
#endif
/*
@@ -438,12 +463,13 @@ 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;
+ pfn = pageblock_end_pfn(pfn);
+
+ /* Update where async and sync compaction should restart */
if (pfn > zone->compact_cached_migrate_pfn[0])
zone->compact_cached_migrate_pfn[0] = pfn;
if (cc->mode != MIGRATE_ASYNC &&
@@ -465,7 +491,6 @@ static void update_pageblock_skip(struct compact_control *cc,
set_pageblock_skip(page);
- /* Update where async and sync compaction should restart */
if (pfn < zone->compact_cached_free_pfn)
zone->compact_cached_free_pfn = pfn;
}
@@ -564,7 +589,7 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
bool strict)
{
int nr_scanned = 0, total_isolated = 0;
- struct page *cursor;
+ struct page *page;
unsigned long flags = 0;
bool locked = false;
unsigned long blockpfn = *start_pfn;
@@ -574,12 +599,11 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
if (strict)
stride = 1;
- cursor = pfn_to_page(blockpfn);
+ page = pfn_to_page(blockpfn);
/* Isolate free pages. */
- for (; blockpfn < end_pfn; blockpfn += stride, cursor += stride) {
+ for (; blockpfn < end_pfn; blockpfn += stride, page += stride) {
int isolated;
- struct page *page = cursor;
/*
* Periodically drop the lock (if held) regardless of its
@@ -604,7 +628,7 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
if (likely(order <= MAX_ORDER)) {
blockpfn += (1UL << order) - 1;
- cursor += (1UL << order) - 1;
+ page += (1UL << order) - 1;
nr_scanned += (1UL << order) - 1;
}
goto isolate_fail;
@@ -641,14 +665,12 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
}
/* Advance to the end of split page */
blockpfn += isolated - 1;
- cursor += isolated - 1;
+ page += isolated - 1;
continue;
isolate_fail:
if (strict)
break;
- else
- continue;
}
@@ -715,8 +737,6 @@ isolate_freepages_range(struct compact_control *cc,
/* Protect pfn from changing by isolate_freepages_block */
unsigned long isolate_start_pfn = pfn;
- block_end_pfn = min(block_end_pfn, end_pfn);
-
/*
* pfn could pass the block_end_pfn if isolated freepage
* is more than pageblock order. In this case, we adjust
@@ -725,9 +745,10 @@ isolate_freepages_range(struct compact_control *cc,
if (pfn >= block_end_pfn) {
block_start_pfn = pageblock_start_pfn(pfn);
block_end_pfn = pageblock_end_pfn(pfn);
- block_end_pfn = min(block_end_pfn, end_pfn);
}
+ block_end_pfn = min(block_end_pfn, end_pfn);
+
if (!pageblock_pfn_to_page(block_start_pfn,
block_end_pfn, cc->zone))
break;
@@ -1076,13 +1097,13 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
bool migrate_dirty;
/*
- * Only pages without mappings or that have a
- * ->migrate_folio callback are possible to migrate
- * without blocking. However, we can be racing with
- * truncation so it's necessary to lock the page
- * to stabilise the mapping as truncation holds
- * the page lock until after the page is removed
- * from the page cache.
+ * Only folios without mappings or that have
+ * a ->migrate_folio callback are possible to
+ * migrate without blocking. However, we may
+ * be racing with truncation, which can free
+ * the mapping. Truncation holds the folio lock
+ * until after the folio is removed from the page
+ * cache so holding it ourselves is sufficient.
*/
if (!folio_trylock(folio))
goto isolate_fail_put;
@@ -1120,6 +1141,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
skip_updated = true;
if (test_and_set_skip(cc, valid_page) &&
!cc->finish_pageblock) {
+ low_pfn = end_pfn;
goto isolate_abort;
}
}
@@ -1421,10 +1443,8 @@ fast_isolate_around(struct compact_control *cc, unsigned long pfn)
isolate_freepages_block(cc, &start_pfn, end_pfn, &cc->freepages, 1, false);
/* Skip this pageblock in the future as it's full or nearly full */
- if (start_pfn == end_pfn)
+ if (start_pfn == end_pfn && !cc->no_set_skip_hint)
set_pageblock_skip(page);
-
- return;
}
/* Search orders in round-robin fashion */
@@ -1501,7 +1521,7 @@ static void fast_isolate_freepages(struct compact_control *cc)
spin_lock_irqsave(&cc->zone->lock, flags);
freelist = &area->free_list[MIGRATE_MOVABLE];
- list_for_each_entry_reverse(freepage, freelist, lru) {
+ list_for_each_entry_reverse(freepage, freelist, buddy_list) {
unsigned long pfn;
order_scanned++;
@@ -1530,7 +1550,7 @@ static void fast_isolate_freepages(struct compact_control *cc)
break;
}
- /* Use a minimum pfn if a preferred one was not found */
+ /* Use a maximum candidate pfn if a preferred one was not found */
if (!page && high_pfn) {
page = pfn_to_page(high_pfn);
@@ -1669,8 +1689,15 @@ static void isolate_freepages(struct compact_control *cc)
page = pageblock_pfn_to_page(block_start_pfn, block_end_pfn,
zone);
- if (!page)
+ if (!page) {
+ unsigned long next_pfn;
+
+ next_pfn = skip_offline_sections_reverse(block_start_pfn);
+ if (next_pfn)
+ block_start_pfn = max(next_pfn, low_pfn);
+
continue;
+ }
/* Check the block is suitable for migration */
if (!suitable_migration_target(cc, page))
@@ -1686,7 +1713,8 @@ static void isolate_freepages(struct compact_control *cc)
/* Update the skip hint if the full pageblock was scanned */
if (isolate_start_pfn == block_end_pfn)
- update_pageblock_skip(cc, page, block_start_pfn);
+ update_pageblock_skip(cc, page, block_start_pfn -
+ pageblock_nr_pages);
/* Are enough freepages isolated? */
if (cc->nr_freepages >= cc->nr_migratepages) {
@@ -1884,7 +1912,7 @@ static unsigned long fast_find_migrateblock(struct compact_control *cc)
spin_lock_irqsave(&cc->zone->lock, flags);
freelist = &area->free_list[MIGRATE_MOVABLE];
- list_for_each_entry(freepage, freelist, lru) {
+ list_for_each_entry(freepage, freelist, buddy_list) {
unsigned long free_pfn;
if (nr_scanned++ >= limit) {
@@ -1958,9 +1986,9 @@ static isolate_migrate_t isolate_migratepages(struct compact_control *cc)
block_start_pfn = cc->zone->zone_start_pfn;
/*
- * fast_find_migrateblock marks a pageblock skipped so to avoid
- * the isolation_suitable check below, check whether the fast
- * search was successful.
+ * fast_find_migrateblock() has already ensured the pageblock is not
+ * set with a skipped flag, so to avoid the isolation_suitable check
+ * below again, check whether the fast search was successful.
*/
fast_find_block = low_pfn != cc->migrate_pfn && !cc->fast_search_fail;
@@ -2114,7 +2142,7 @@ static unsigned int fragmentation_score_node(pg_data_t *pgdat)
return score;
}
-static unsigned int fragmentation_score_wmark(pg_data_t *pgdat, bool low)
+static unsigned int fragmentation_score_wmark(bool low)
{
unsigned int wmark_low;
@@ -2134,7 +2162,7 @@ static bool should_proactive_compact_node(pg_data_t *pgdat)
if (!sysctl_compaction_proactiveness || kswapd_is_running(pgdat))
return false;
- wmark_high = fragmentation_score_wmark(pgdat, false);
+ wmark_high = fragmentation_score_wmark(false);
return fragmentation_score_node(pgdat) > wmark_high;
}
@@ -2173,7 +2201,7 @@ static enum compact_result __compact_finished(struct compact_control *cc)
return COMPACT_PARTIAL_SKIPPED;
score = fragmentation_score_zone(cc->zone);
- wmark_low = fragmentation_score_wmark(pgdat, true);
+ wmark_low = fragmentation_score_wmark(true);
if (score > wmark_low)
ret = COMPACT_CONTINUE;
@@ -2480,7 +2508,8 @@ rescan:
goto check_drain;
case ISOLATE_SUCCESS:
update_cached = false;
- last_migrated_pfn = iteration_start_pfn;
+ last_migrated_pfn = max(cc->zone->zone_start_pfn,
+ pageblock_start_pfn(cc->migrate_pfn - 1));
}
err = migrate_pages(&cc->migratepages, compaction_alloc,
@@ -2503,7 +2532,7 @@ rescan:
}
/*
* If an ASYNC or SYNC_LIGHT fails to migrate a page
- * within the current order-aligned block and
+ * within the pageblock_order-aligned block and
* fast_find_migrateblock may be used then scan the
* remainder of the pageblock. This will mark the
* pageblock "skip" to avoid rescanning in the near
@@ -2869,7 +2898,7 @@ int compaction_register_node(struct node *node)
void compaction_unregister_node(struct node *node)
{
- return device_remove_file(&node->dev, &dev_attr_compact);
+ device_remove_file(&node->dev, &dev_attr_compact);
}
#endif /* CONFIG_SYSFS && CONFIG_NUMA */
diff --git a/mm/damon/core-test.h b/mm/damon/core-test.h
index bb07721909e1..6cc8b245586d 100644
--- a/mm/damon/core-test.h
+++ b/mm/damon/core-test.h
@@ -341,6 +341,78 @@ static void damon_test_set_attrs(struct kunit *test)
KUNIT_EXPECT_EQ(test, damon_set_attrs(c, &invalid_attrs), -EINVAL);
}
+static void damos_test_new_filter(struct kunit *test)
+{
+ struct damos_filter *filter;
+
+ filter = damos_new_filter(DAMOS_FILTER_TYPE_ANON, true);
+ KUNIT_EXPECT_EQ(test, filter->type, DAMOS_FILTER_TYPE_ANON);
+ KUNIT_EXPECT_EQ(test, filter->matching, true);
+ KUNIT_EXPECT_PTR_EQ(test, filter->list.prev, &filter->list);
+ KUNIT_EXPECT_PTR_EQ(test, filter->list.next, &filter->list);
+ damos_destroy_filter(filter);
+}
+
+static void damos_test_filter_out(struct kunit *test)
+{
+ struct damon_target *t;
+ struct damon_region *r, *r2;
+ struct damos_filter *f;
+
+ f = damos_new_filter(DAMOS_FILTER_TYPE_ADDR, true);
+ f->addr_range = (struct damon_addr_range){
+ .start = DAMON_MIN_REGION * 2, .end = DAMON_MIN_REGION * 6};
+
+ t = damon_new_target();
+ r = damon_new_region(DAMON_MIN_REGION * 3, DAMON_MIN_REGION * 5);
+ damon_add_region(r, t);
+
+ /* region in the range */
+ KUNIT_EXPECT_TRUE(test, __damos_filter_out(NULL, t, r, f));
+ KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1);
+
+ /* region before the range */
+ r->ar.start = DAMON_MIN_REGION * 1;
+ r->ar.end = DAMON_MIN_REGION * 2;
+ KUNIT_EXPECT_FALSE(test, __damos_filter_out(NULL, t, r, f));
+ KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1);
+
+ /* region after the range */
+ r->ar.start = DAMON_MIN_REGION * 6;
+ r->ar.end = DAMON_MIN_REGION * 8;
+ KUNIT_EXPECT_FALSE(test, __damos_filter_out(NULL, t, r, f));
+ KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1);
+
+ /* region started before the range */
+ r->ar.start = DAMON_MIN_REGION * 1;
+ r->ar.end = DAMON_MIN_REGION * 4;
+ KUNIT_EXPECT_FALSE(test, __damos_filter_out(NULL, t, r, f));
+ /* filter should have split the region */
+