Commit c0694456 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'mm-hotfixes-stable-2025-06-22-18-52' of...

Merge tag 'mm-hotfixes-stable-2025-06-22-18-52' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull misc fixes from Andrew Morton:
 "20 hotfixes. 7 are cc:stable and the remainder address post-6.15
  issues or aren't considered necessary for -stable kernels. Only 4 are
  for MM.

   - The series `Revert "bcache: update min_heap_callbacks to use
     default builtin swap"' from Kuan-Wei Chiu backs out the author's
     recent min_heap changes due to a performance regression.

     A fix for this regression has been developed but we felt it best to
     go back to the known-good version to give the new code more bake
     time.

   - A lot of MAINTAINERS maintenance.

     I like to get these changes upstreamed promptly because they can't
     break things and more accurate/complete MAINTAINERS info hopefully
     improves the speed and accuracy of our responses to submitters and
     reporters"

* tag 'mm-hotfixes-stable-2025-06-22-18-52' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm:
  MAINTAINERS: add additional mmap-related files to mmap section
  MAINTAINERS: add memfd, shmem quota files to shmem section
  MAINTAINERS: add stray rmap file to mm rmap section
  MAINTAINERS: add hugetlb_cgroup.c to hugetlb section
  MAINTAINERS: add further init files to mm init block
  MAINTAINERS: update maintainers for HugeTLB
  maple_tree: fix MA_STATE_PREALLOC flag in mas_preallocate()
  MAINTAINERS: add missing test files to mm gup section
  MAINTAINERS: add missing mm/workingset.c file to mm reclaim section
  selftests/mm: skip uprobe vma merge test if uprobes are not enabled
  bcache: remove unnecessary select MIN_HEAP
  Revert "bcache: remove heap-related macros and switch to generic min_heap"
  Revert "bcache: update min_heap_callbacks to use default builtin swap"
  selftests/mm: add configs to fix testcase failure
  kho: initialize tail pages for higher order folios properly
  MAINTAINERS: add linux-mm@ list to Kexec Handover
  mm: userfaultfd: fix race of userfaultfd_move and swap cache
  mm/gup: revert "mm: gup: fix infinite loop within __get_longterm_locked"
  selftests/mm: increase timeout from 180 to 900 seconds
  mm/shmem, swap: fix softlockup with mTHP swapin
parents 86731a2a c742d127
Loading
Loading
Loading
Loading
+19 −2
Original line number Diff line number Diff line
@@ -11155,7 +11155,8 @@ F: include/linux/platform_data/huawei-gaokun-ec.h
HUGETLB SUBSYSTEM
M:	Muchun Song <muchun.song@linux.dev>
R:	Oscar Salvador <osalvador@suse.de>
M:	Oscar Salvador <osalvador@suse.de>
R:	David Hildenbrand <david@redhat.com>
L:	linux-mm@kvack.org
S:	Maintained
F:	Documentation/ABI/testing/sysfs-kernel-mm-hugepages
@@ -11166,6 +11167,7 @@ F: fs/hugetlbfs/
F:	include/linux/hugetlb.h
F:	include/trace/events/hugetlbfs.h
F:	mm/hugetlb.c
F:	mm/hugetlb_cgroup.c
F:	mm/hugetlb_cma.c
F:	mm/hugetlb_cma.h
F:	mm/hugetlb_vmemmap.c
@@ -13345,6 +13347,7 @@ M: Alexander Graf <graf@amazon.com>
M:	Mike Rapoport <rppt@kernel.org>
M:	Changyuan Lyu <changyuanl@google.com>
L:	kexec@lists.infradead.org
L:	linux-mm@kvack.org
S:	Maintained
F:	Documentation/admin-guide/mm/kho.rst
F:	Documentation/core-api/kho/*
@@ -15676,8 +15679,11 @@ S: Maintained
F:	Documentation/core-api/boot-time-mm.rst
F:	Documentation/core-api/kho/bindings/memblock/*
F:	include/linux/memblock.h
F:	mm/bootmem_info.c
F:	mm/memblock.c
F:	mm/memtest.c
F:	mm/mm_init.c
F:	mm/rodata_test.c
F:	tools/testing/memblock/
MEMORY ALLOCATION PROFILING
@@ -15732,7 +15738,6 @@ F: Documentation/admin-guide/mm/
F:	Documentation/mm/
F:	include/linux/gfp.h
F:	include/linux/gfp_types.h
F:	include/linux/memfd.h
F:	include/linux/memory_hotplug.h
F:	include/linux/memory-tiers.h
F:	include/linux/mempolicy.h
@@ -15792,6 +15797,10 @@ S: Maintained
W:	http://www.linux-mm.org
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
F:	mm/gup.c
F:	mm/gup_test.c
F:	mm/gup_test.h
F:	tools/testing/selftests/mm/gup_longterm.c
F:	tools/testing/selftests/mm/gup_test.c
MEMORY MANAGEMENT - KSM (Kernel Samepage Merging)
M:	Andrew Morton <akpm@linux-foundation.org>
@@ -15868,6 +15877,7 @@ L: linux-mm@kvack.org
S:	Maintained
F:	mm/pt_reclaim.c
F:	mm/vmscan.c
F:	mm/workingset.c
MEMORY MANAGEMENT - RMAP (REVERSE MAPPING)
M:	Andrew Morton <akpm@linux-foundation.org>
@@ -15880,6 +15890,7 @@ R: Harry Yoo <harry.yoo@oracle.com>
L:	linux-mm@kvack.org
S:	Maintained
F:	include/linux/rmap.h
F:	mm/page_vma_mapped.c
F:	mm/rmap.c
MEMORY MANAGEMENT - SECRETMEM
@@ -15972,11 +15983,14 @@ S: Maintained
W:	http://www.linux-mm.org
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
F:	include/trace/events/mmap.h
F:	mm/mincore.c
F:	mm/mlock.c
F:	mm/mmap.c
F:	mm/mprotect.c
F:	mm/mremap.c
F:	mm/mseal.c
F:	mm/msync.c
F:	mm/nommu.c
F:	mm/vma.c
F:	mm/vma.h
F:	mm/vma_exec.c
@@ -25027,8 +25041,11 @@ M: Hugh Dickins <hughd@google.com>
R:	Baolin Wang <baolin.wang@linux.alibaba.com>
L:	linux-mm@kvack.org
S:	Maintained
F:	include/linux/memfd.h
F:	include/linux/shmem_fs.h
F:	mm/memfd.c
F:	mm/shmem.c
F:	mm/shmem_quota.c
TOMOYO SECURITY MODULE
M:	Kentaro Takeda <takedakn@nttdata.co.jp>
+0 −1
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@ config BCACHE
	select BLOCK_HOLDER_DEPRECATED if SYSFS
	select CRC64
	select CLOSURES
	select MIN_HEAP
	help
	Allows a block device to be used as cache for other devices; uses
	a btree for indexing and the layout is optimized for SSDs.
+17 −40
Original line number Diff line number Diff line
@@ -164,61 +164,40 @@ static void bch_invalidate_one_bucket(struct cache *ca, struct bucket *b)
 * prio is worth 1/8th of what INITIAL_PRIO is worth.
 */

static inline unsigned int new_bucket_prio(struct cache *ca, struct bucket *b)
{
	unsigned int min_prio = (INITIAL_PRIO - ca->set->min_prio) / 8;

	return (b->prio - ca->set->min_prio + min_prio) * GC_SECTORS_USED(b);
}

static inline bool new_bucket_max_cmp(const void *l, const void *r, void *args)
{
	struct bucket **lhs = (struct bucket **)l;
	struct bucket **rhs = (struct bucket **)r;
	struct cache *ca = args;

	return new_bucket_prio(ca, *lhs) > new_bucket_prio(ca, *rhs);
}

static inline bool new_bucket_min_cmp(const void *l, const void *r, void *args)
{
	struct bucket **lhs = (struct bucket **)l;
	struct bucket **rhs = (struct bucket **)r;
	struct cache *ca = args;
#define bucket_prio(b)							\
({									\
	unsigned int min_prio = (INITIAL_PRIO - ca->set->min_prio) / 8;	\
									\
	(b->prio - ca->set->min_prio + min_prio) * GC_SECTORS_USED(b);	\
})

	return new_bucket_prio(ca, *lhs) < new_bucket_prio(ca, *rhs);
}
#define bucket_max_cmp(l, r)	(bucket_prio(l) < bucket_prio(r))
#define bucket_min_cmp(l, r)	(bucket_prio(l) > bucket_prio(r))

static void invalidate_buckets_lru(struct cache *ca)
{
	struct bucket *b;
	const struct min_heap_callbacks bucket_max_cmp_callback = {
		.less = new_bucket_max_cmp,
		.swp = NULL,
	};
	const struct min_heap_callbacks bucket_min_cmp_callback = {
		.less = new_bucket_min_cmp,
		.swp = NULL,
	};
	ssize_t i;

	ca->heap.nr = 0;
	ca->heap.used = 0;

	for_each_bucket(b, ca) {
		if (!bch_can_invalidate_bucket(ca, b))
			continue;

		if (!min_heap_full(&ca->heap))
			min_heap_push(&ca->heap, &b, &bucket_max_cmp_callback, ca);
		else if (!new_bucket_max_cmp(&b, min_heap_peek(&ca->heap), ca)) {
		if (!heap_full(&ca->heap))
			heap_add(&ca->heap, b, bucket_max_cmp);
		else if (bucket_max_cmp(b, heap_peek(&ca->heap))) {
			ca->heap.data[0] = b;
			min_heap_sift_down(&ca->heap, 0, &bucket_max_cmp_callback, ca);
			heap_sift(&ca->heap, 0, bucket_max_cmp);
		}
	}

	min_heapify_all(&ca->heap, &bucket_min_cmp_callback, ca);
	for (i = ca->heap.used / 2 - 1; i >= 0; --i)
		heap_sift(&ca->heap, i, bucket_min_cmp);

	while (!fifo_full(&ca->free_inc)) {
		if (!ca->heap.nr) {
		if (!heap_pop(&ca->heap, b, bucket_min_cmp)) {
			/*
			 * We don't want to be calling invalidate_buckets()
			 * multiple times when it can't do anything
@@ -227,8 +206,6 @@ static void invalidate_buckets_lru(struct cache *ca)
			wake_up_gc(ca->set);
			return;
		}
		b = min_heap_peek(&ca->heap)[0];
		min_heap_pop(&ca->heap, &bucket_min_cmp_callback, ca);

		bch_invalidate_one_bucket(ca, b);
	}
+1 −1
Original line number Diff line number Diff line
@@ -458,7 +458,7 @@ struct cache {
	/* Allocation stuff: */
	struct bucket		*buckets;

	DEFINE_MIN_HEAP(struct bucket *, cache_heap) heap;
	DECLARE_HEAP(struct bucket *, heap);

	/*
	 * If nonzero, we know we aren't going to find any buckets to invalidate
+45 −71
Original line number Diff line number Diff line
@@ -54,11 +54,9 @@ void bch_dump_bucket(struct btree_keys *b)
int __bch_count_data(struct btree_keys *b)
{
	unsigned int ret = 0;
	struct btree_iter iter;
	struct btree_iter_stack iter;
	struct bkey *k;

	min_heap_init(&iter.heap, NULL, MAX_BSETS);

	if (b->ops->is_extents)
		for_each_key(b, k, &iter)
			ret += KEY_SIZE(k);
@@ -69,11 +67,9 @@ void __bch_check_keys(struct btree_keys *b, const char *fmt, ...)
{
	va_list args;
	struct bkey *k, *p = NULL;
	struct btree_iter iter;
	struct btree_iter_stack iter;
	const char *err;

	min_heap_init(&iter.heap, NULL, MAX_BSETS);

	for_each_key(b, k, &iter) {
		if (b->ops->is_extents) {
			err = "Keys out of order";
@@ -114,9 +110,9 @@ void __bch_check_keys(struct btree_keys *b, const char *fmt, ...)

static void bch_btree_iter_next_check(struct btree_iter *iter)
{
	struct bkey *k = iter->heap.data->k, *next = bkey_next(k);
	struct bkey *k = iter->data->k, *next = bkey_next(k);

	if (next < iter->heap.data->end &&
	if (next < iter->data->end &&
	    bkey_cmp(k, iter->b->ops->is_extents ?
		     &START_KEY(next) : next) > 0) {
		bch_dump_bucket(iter->b);
@@ -883,14 +879,12 @@ unsigned int bch_btree_insert_key(struct btree_keys *b, struct bkey *k,
	unsigned int status = BTREE_INSERT_STATUS_NO_INSERT;
	struct bset *i = bset_tree_last(b)->data;
	struct bkey *m, *prev = NULL;
	struct btree_iter iter;
	struct btree_iter_stack iter;
	struct bkey preceding_key_on_stack = ZERO_KEY;
	struct bkey *preceding_key_p = &preceding_key_on_stack;

	BUG_ON(b->ops->is_extents && !KEY_SIZE(k));

	min_heap_init(&iter.heap, NULL, MAX_BSETS);

	/*
	 * If k has preceding key, preceding_key_p will be set to address
	 *  of k's preceding key; otherwise preceding_key_p will be set
@@ -901,9 +895,9 @@ unsigned int bch_btree_insert_key(struct btree_keys *b, struct bkey *k,
	else
		preceding_key(k, &preceding_key_p);

	m = bch_btree_iter_init(b, &iter, preceding_key_p);
	m = bch_btree_iter_stack_init(b, &iter, preceding_key_p);

	if (b->ops->insert_fixup(b, k, &iter, replace_key))
	if (b->ops->insert_fixup(b, k, &iter.iter, replace_key))
		return status;

	status = BTREE_INSERT_STATUS_INSERT;
@@ -1083,94 +1077,79 @@ struct bkey *__bch_bset_search(struct btree_keys *b, struct bset_tree *t,

/* Btree iterator */

typedef bool (new_btree_iter_cmp_fn)(const void *, const void *, void *);
typedef bool (btree_iter_cmp_fn)(struct btree_iter_set,
				 struct btree_iter_set);

static inline bool new_btree_iter_cmp(const void *l, const void *r, void __always_unused *args)
static inline bool btree_iter_cmp(struct btree_iter_set l,
				  struct btree_iter_set r)
{
	const struct btree_iter_set *_l = l;
	const struct btree_iter_set *_r = r;

	return bkey_cmp(_l->k, _r->k) <= 0;
	return bkey_cmp(l.k, r.k) > 0;
}

static inline bool btree_iter_end(struct btree_iter *iter)
{
	return !iter->heap.nr;
	return !iter->used;
}

void bch_btree_iter_push(struct btree_iter *iter, struct bkey *k,
			 struct bkey *end)
{
	const struct min_heap_callbacks callbacks = {
		.less = new_btree_iter_cmp,
		.swp = NULL,
	};

	if (k != end)
		BUG_ON(!min_heap_push(&iter->heap,
				 &((struct btree_iter_set) { k, end }),
				 &callbacks,
				 NULL));
		BUG_ON(!heap_add(iter,
				 ((struct btree_iter_set) { k, end }),
				 btree_iter_cmp));
}

static struct bkey *__bch_btree_iter_init(struct btree_keys *b,
					  struct btree_iter *iter,
static struct bkey *__bch_btree_iter_stack_init(struct btree_keys *b,
						struct btree_iter_stack *iter,
						struct bkey *search,
						struct bset_tree *start)
{
	struct bkey *ret = NULL;

	iter->heap.size = ARRAY_SIZE(iter->heap.preallocated);
	iter->heap.nr = 0;
	iter->iter.size = ARRAY_SIZE(iter->stack_data);
	iter->iter.used = 0;

#ifdef CONFIG_BCACHE_DEBUG
	iter->b = b;
	iter->iter.b = b;
#endif

	for (; start <= bset_tree_last(b); start++) {
		ret = bch_bset_search(b, start, search);
		bch_btree_iter_push(iter, ret, bset_bkey_last(start->data));
		bch_btree_iter_push(&iter->iter, ret, bset_bkey_last(start->data));
	}

	return ret;
}

struct bkey *bch_btree_iter_init(struct btree_keys *b,
				 struct btree_iter *iter,
struct bkey *bch_btree_iter_stack_init(struct btree_keys *b,
				 struct btree_iter_stack *iter,
				 struct bkey *search)
{
	return __bch_btree_iter_init(b, iter, search, b->set);
	return __bch_btree_iter_stack_init(b, iter, search, b->set);
}

static inline struct bkey *__bch_btree_iter_next(struct btree_iter *iter,
						 new_btree_iter_cmp_fn *cmp)
						 btree_iter_cmp_fn *cmp)
{
	struct btree_iter_set b __maybe_unused;
	struct bkey *ret = NULL;
	const struct min_heap_callbacks callbacks = {
		.less = cmp,
		.swp = NULL,
	};

	if (!btree_iter_end(iter)) {
		bch_btree_iter_next_check(iter);

		ret = iter->heap.data->k;
		iter->heap.data->k = bkey_next(iter->heap.data->k);
		ret = iter->data->k;
		iter->data->k = bkey_next(iter->data->k);

		if (iter->heap.data->k > iter->heap.data->end) {
		if (iter->data->k > iter->data->end) {
			WARN_ONCE(1, "bset was corrupt!\n");
			iter->heap.data->k = iter->heap.data->end;
			iter->data->k = iter->data->end;
		}

		if (iter->heap.data->k == iter->heap.data->end) {
			if (iter->heap.nr) {
				b = min_heap_peek(&iter->heap)[0];
				min_heap_pop(&iter->heap, &callbacks, NULL);
			}
		}
		if (iter->data->k == iter->data->end)
			heap_pop(iter, b, cmp);
		else
			min_heap_sift_down(&iter->heap, 0, &callbacks, NULL);
			heap_sift(iter, 0, cmp);
	}

	return ret;
@@ -1178,7 +1157,7 @@ static inline struct bkey *__bch_btree_iter_next(struct btree_iter *iter,

struct bkey *bch_btree_iter_next(struct btree_iter *iter)
{
	return __bch_btree_iter_next(iter, new_btree_iter_cmp);
	return __bch_btree_iter_next(iter, btree_iter_cmp);

}

@@ -1216,18 +1195,16 @@ static void btree_mergesort(struct btree_keys *b, struct bset *out,
			    struct btree_iter *iter,
			    bool fixup, bool remove_stale)
{
	int i;
	struct bkey *k, *last = NULL;
	BKEY_PADDED(k) tmp;
	bool (*bad)(struct btree_keys *, const struct bkey *) = remove_stale
		? bch_ptr_bad
		: bch_ptr_invalid;
	const struct min_heap_callbacks callbacks = {
		.less = b->ops->sort_cmp,
		.swp = NULL,
	};

	/* Heapify the iterator, using our comparison function */
	min_heapify_all(&iter->heap, &callbacks, NULL);
	for (i = iter->used / 2 - 1; i >= 0; --i)
		heap_sift(iter, i, b->ops->sort_cmp);

	while (!btree_iter_end(iter)) {
		if (b->ops->sort_fixup && fixup)
@@ -1316,11 +1293,10 @@ void bch_btree_sort_partial(struct btree_keys *b, unsigned int start,
			    struct bset_sort_state *state)
{
	size_t order = b->page_order, keys = 0;
	struct btree_iter iter;
	struct btree_iter_stack iter;
	int oldsize = bch_count_data(b);

	min_heap_init(&iter.heap, NULL, MAX_BSETS);
	__bch_btree_iter_init(b, &iter, NULL, &b->set[start]);
	__bch_btree_iter_stack_init(b, &iter, NULL, &b->set[start]);

	if (start) {
		unsigned int i;
@@ -1331,7 +1307,7 @@ void bch_btree_sort_partial(struct btree_keys *b, unsigned int start,
		order = get_order(__set_bytes(b->set->data, keys));
	}

	__btree_sort(b, &iter, start, order, false, state);
	__btree_sort(b, &iter.iter, start, order, false, state);

	EBUG_ON(oldsize >= 0 && bch_count_data(b) != oldsize);
}
@@ -1347,13 +1323,11 @@ void bch_btree_sort_into(struct btree_keys *b, struct btree_keys *new,
			 struct bset_sort_state *state)
{
	uint64_t start_time = local_clock();
	struct btree_iter iter;

	min_heap_init(&iter.heap, NULL, MAX_BSETS);
	struct btree_iter_stack iter;

	bch_btree_iter_init(b, &iter, NULL);
	bch_btree_iter_stack_init(b, &iter, NULL);

	btree_mergesort(b, new->set->data, &iter, false, true);
	btree_mergesort(b, new->set->data, &iter.iter, false, true);

	bch_time_stats_update(&state->time, start_time);

Loading