All of lore.kernel.org
 help / color / mirror / Atom feed
* [merged mm-hotfixes-stable] remove-old-lib-alloc_tagc.patch removed from -mm tree
@ 2026-09-05 18:48 Andrew Morton
  0 siblings, 0 replies; only message in thread
From: Andrew Morton @ 2026-09-05 18:48 UTC (permalink / raw)
  To: mm-commits, surenb, ljs, akpm, akpm


The quilt patch titled
     Subject: remove old lib/alloc_tag.c
has been removed from the -mm tree.  Its filename was
     remove-old-lib-alloc_tagc.patch

This patch was dropped because it was merged into the mm-hotfixes-stable branch
of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

------------------------------------------------------
From: Andrew Morton <akpm@linux-foundation.org>
Subject: remove old lib/alloc_tag.c
Date: Tue Sep  1 01:09:29 PM PDT 2026

This was moved into mm/, but the original lib/ file somehow remained. 
Remove it.

Reported-by: Suren Baghdasaryan <surenb@google.com>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---

 lib/alloc_tag.c | 1029 ----------------------------------------------
 1 file changed, 1029 deletions(-)

diff --git a/lib/alloc_tag.c a/lib/alloc_tag.c
deleted file mode 100644
--- a/lib/alloc_tag.c
+++ /dev/null
@@ -1,1029 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#include <linux/alloc_tag.h>
-#include <linux/execmem.h>
-#include <linux/fs.h>
-#include <linux/gfp.h>
-#include <linux/kallsyms.h>
-#include <linux/module.h>
-#include <linux/page_ext.h>
-#include <linux/pgalloc_tag.h>
-#include <linux/proc_fs.h>
-#include <linux/rcupdate.h>
-#include <linux/seq_buf.h>
-#include <linux/seq_file.h>
-#include <linux/string_choices.h>
-#include <linux/vmalloc.h>
-#include <linux/kmemleak.h>
-
-#define ALLOCINFO_FILE_NAME		"allocinfo"
-#define MODULE_ALLOC_TAG_VMAP_SIZE	(100000UL * sizeof(struct alloc_tag))
-#define SECTION_START(NAME)		(CODETAG_SECTION_START_PREFIX NAME)
-#define SECTION_STOP(NAME)		(CODETAG_SECTION_STOP_PREFIX NAME)
-
-#ifdef CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT
-static bool mem_profiling_support = true;
-#else
-static bool mem_profiling_support;
-#endif
-
-/*
- * Memory allocation profiling is permanently disabled and cannot be enabled.
- * Must be called after setup_early_mem_profiling().
- */
-bool mem_alloc_profiling_permanently_disabled(void)
-{
-	return !mem_profiling_support;
-}
-
-static struct codetag_type *alloc_tag_cttype;
-
-#ifdef CONFIG_ARCH_MODULE_NEEDS_WEAK_PER_CPU
-DEFINE_PER_CPU(struct alloc_tag_counters, _shared_alloc_tag);
-EXPORT_SYMBOL(_shared_alloc_tag);
-#endif
-
-DEFINE_STATIC_KEY_MAYBE(CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT,
-			mem_alloc_profiling_key);
-EXPORT_SYMBOL(mem_alloc_profiling_key);
-
-DEFINE_STATIC_KEY_FALSE(mem_profiling_compressed);
-
-struct alloc_tag_kernel_section kernel_tags = { NULL, 0 };
-unsigned long alloc_tag_ref_mask;
-int alloc_tag_ref_offs;
-
-struct allocinfo_private {
-	struct codetag_iterator iter;
-	struct codetag_iterator reported_iter;
-	bool print_header;
-};
-
-static void *allocinfo_start(struct seq_file *m, loff_t *pos)
-{
-	struct allocinfo_private *priv;
-	loff_t node = *pos;
-
-	priv = (struct allocinfo_private *)m->private;
-	codetag_lock_module_list(alloc_tag_cttype);
-	if (node == 0) {
-		priv->print_header = true;
-		priv->iter = codetag_get_ct_iter(alloc_tag_cttype);
-	} else {
-		priv->iter = priv->reported_iter;
-	}
-	codetag_next_ct(&priv->iter);
-	return priv->iter.ct ? priv : NULL;
-}
-
-static void *allocinfo_next(struct seq_file *m, void *arg, loff_t *pos)
-{
-	struct allocinfo_private *priv = (struct allocinfo_private *)arg;
-	struct codetag *ct;
-
-	priv->reported_iter = priv->iter;
-	ct = codetag_next_ct(&priv->iter);
-	(*pos)++;
-	if (!ct)
-		return NULL;
-
-	return priv;
-}
-
-static void allocinfo_stop(struct seq_file *m, void *arg)
-{
-	codetag_unlock_module_list(alloc_tag_cttype);
-}
-
-static void print_allocinfo_header(struct seq_buf *buf)
-{
-	/* Output format version, so we can change it. */
-	seq_buf_printf(buf, "allocinfo - version: 2.0\n");
-	seq_buf_printf(buf, "#     <size>  <calls> <tag info>\n");
-}
-
-static void alloc_tag_to_text(struct seq_buf *out, struct codetag *ct)
-{
-	struct alloc_tag *tag = ct_to_alloc_tag(ct);
-	struct alloc_tag_counters counter = alloc_tag_read(tag);
-	s64 bytes = counter.bytes;
-
-	seq_buf_printf(out, "%12lli %8llu ", bytes, counter.calls);
-	codetag_to_text(out, ct);
-	if (unlikely(alloc_tag_is_inaccurate(tag)))
-		seq_buf_printf(out, " accurate:no");
-	seq_buf_putc(out, ' ');
-	seq_buf_putc(out, '\n');
-}
-
-static int allocinfo_show(struct seq_file *m, void *arg)
-{
-	struct allocinfo_private *priv = (struct allocinfo_private *)arg;
-	char *bufp;
-	size_t n = seq_get_buf(m, &bufp);
-	struct seq_buf buf;
-
-	seq_buf_init(&buf, bufp, n);
-	if (priv->print_header) {
-		print_allocinfo_header(&buf);
-		priv->print_header = false;
-	}
-	alloc_tag_to_text(&buf, priv->iter.ct);
-	seq_commit(m, seq_buf_used(&buf));
-	return 0;
-}
-
-static const struct seq_operations allocinfo_seq_op = {
-	.start	= allocinfo_start,
-	.next	= allocinfo_next,
-	.stop	= allocinfo_stop,
-	.show	= allocinfo_show,
-};
-
-size_t alloc_tag_top_users(struct codetag_bytes *tags, size_t count, bool can_sleep)
-{
-	struct codetag_iterator iter;
-	struct codetag *ct;
-	struct codetag_bytes n;
-	unsigned int i, nr = 0;
-
-	if (IS_ERR_OR_NULL(alloc_tag_cttype))
-		return 0;
-
-	if (can_sleep)
-		codetag_lock_module_list(alloc_tag_cttype);
-	else if (!codetag_trylock_module_list(alloc_tag_cttype))
-		return 0;
-
-	iter = codetag_get_ct_iter(alloc_tag_cttype);
-	while ((ct = codetag_next_ct(&iter))) {
-		struct alloc_tag_counters counter = alloc_tag_read(ct_to_alloc_tag(ct));
-
-		n.ct	= ct;
-		n.bytes = counter.bytes;
-
-		for (i = 0; i < nr; i++)
-			if (n.bytes > tags[i].bytes)
-				break;
-
-		if (i < count) {
-			nr -= nr == count;
-			memmove(&tags[i + 1],
-				&tags[i],
-				sizeof(tags[0]) * (nr - i));
-			nr++;
-			tags[i] = n;
-		}
-	}
-
-	codetag_unlock_module_list(alloc_tag_cttype);
-
-	return nr;
-}
-
-void pgalloc_tag_split(struct folio *folio, int old_order, int new_order)
-{
-	int i;
-	struct alloc_tag *tag;
-	unsigned int nr_pages = 1 << new_order;
-
-	if (!mem_alloc_profiling_enabled())
-		return;
-
-	tag = __pgalloc_tag_get(&folio->page);
-	if (!tag)
-		return;
-
-	for (i = nr_pages; i < (1 << old_order); i += nr_pages) {
-		union pgtag_ref_handle handle;
-		union codetag_ref ref;
-
-		if (get_page_tag_ref(folio_page(folio, i), &ref, &handle)) {
-			/* Set new reference to point to the original tag */
-			alloc_tag_ref_set(&ref, tag);
-			update_page_tag_ref(handle, &ref);
-			put_page_tag_ref(handle);
-		}
-	}
-}
-
-void pgalloc_tag_swap(struct folio *new, struct folio *old)
-{
-	union pgtag_ref_handle handle_old, handle_new;
-	union codetag_ref ref_old, ref_new;
-	struct alloc_tag *tag_old, *tag_new;
-
-	if (!mem_alloc_profiling_enabled())
-		return;
-
-	tag_old = __pgalloc_tag_get(&old->page);
-	if (!tag_old)
-		return;
-	tag_new = __pgalloc_tag_get(&new->page);
-	if (!tag_new)
-		return;
-
-	if (!get_page_tag_ref(&old->page, &ref_old, &handle_old))
-		return;
-	if (!get_page_tag_ref(&new->page, &ref_new, &handle_new)) {
-		put_page_tag_ref(handle_old);
-		return;
-	}
-
-	/*
-	 * Clear tag references to avoid debug warning when using
-	 * __alloc_tag_ref_set() with non-empty reference.
-	 */
-	set_codetag_empty(&ref_old);
-	set_codetag_empty(&ref_new);
-
-	/* swap tags */
-	__alloc_tag_ref_set(&ref_old, tag_new);
-	update_page_tag_ref(handle_old, &ref_old);
-	__alloc_tag_ref_set(&ref_new, tag_old);
-	update_page_tag_ref(handle_new, &ref_new);
-
-	put_page_tag_ref(handle_old);
-	put_page_tag_ref(handle_new);
-}
-
-static void shutdown_mem_profiling(bool remove_file)
-{
-	if (mem_alloc_profiling_enabled())
-		static_branch_disable(&mem_alloc_profiling_key);
-
-	if (!mem_profiling_support)
-		return;
-
-	if (remove_file)
-		remove_proc_entry(ALLOCINFO_FILE_NAME, NULL);
-	mem_profiling_support = false;
-}
-
-void __init alloc_tag_sec_init(void)
-{
-	struct alloc_tag *last_codetag;
-
-	if (!mem_profiling_support)
-		return;
-
-	if (!static_key_enabled(&mem_profiling_compressed))
-		return;
-
-	kernel_tags.first_tag = (struct alloc_tag *)kallsyms_lookup_name(
-					SECTION_START(ALLOC_TAG_SECTION_NAME));
-	last_codetag = (struct alloc_tag *)kallsyms_lookup_name(
-					SECTION_STOP(ALLOC_TAG_SECTION_NAME));
-	kernel_tags.count = last_codetag - kernel_tags.first_tag;
-
-	/* Check if kernel tags fit into page flags */
-	if (kernel_tags.count > (1UL << NR_UNUSED_PAGEFLAG_BITS)) {
-		shutdown_mem_profiling(false); /* allocinfo file does not exist yet */
-		pr_err("%lu allocation tags cannot be references using %d available page flag bits. Memory allocation profiling is disabled!\n",
-			kernel_tags.count, NR_UNUSED_PAGEFLAG_BITS);
-		return;
-	}
-
-	alloc_tag_ref_offs = (LRU_REFS_PGOFF - NR_UNUSED_PAGEFLAG_BITS);
-	alloc_tag_ref_mask = ((1UL << NR_UNUSED_PAGEFLAG_BITS) - 1);
-	pr_debug("Memory allocation profiling compression is using %d page flag bits!\n",
-		 NR_UNUSED_PAGEFLAG_BITS);
-}
-
-#ifdef CONFIG_MODULES
-
-static struct maple_tree mod_area_mt = MTREE_INIT(mod_area_mt, MT_FLAGS_ALLOC_RANGE);
-static struct vm_struct *vm_module_tags;
-/* A dummy object used to indicate an unloaded module */
-static struct module unloaded_mod;
-/* A dummy object used to indicate a module prepended area */
-static struct module prepend_mod;
-
-struct alloc_tag_module_section module_tags;
-
-static inline unsigned long alloc_tag_align(unsigned long val)
-{
-	if (!static_key_enabled(&mem_profiling_compressed)) {
-		/* No alignment requirements when we are not indexing the tags */
-		return val;
-	}
-
-	if (val % sizeof(struct alloc_tag) == 0)
-		return val;
-	return ((val / sizeof(struct alloc_tag)) + 1) * sizeof(struct alloc_tag);
-}
-
-static bool ensure_alignment(unsigned long align, unsigned int *prepend)
-{
-	if (!static_key_enabled(&mem_profiling_compressed)) {
-		/* No alignment requirements when we are not indexing the tags */
-		return true;
-	}
-
-	/*
-	 * If alloc_tag size is not a multiple of required alignment, tag
-	 * indexing does not work.
-	 */
-	if (!IS_ALIGNED(sizeof(struct alloc_tag), align))
-		return false;
-
-	/* Ensure prepend consumes multiple of alloc_tag-sized blocks */
-	if (*prepend)
-		*prepend = alloc_tag_align(*prepend);
-
-	return true;
-}
-
-static inline bool tags_addressable(void)
-{
-	unsigned long tag_idx_count;
-
-	if (!static_key_enabled(&mem_profiling_compressed))
-		return true; /* with page_ext tags are always addressable */
-
-	tag_idx_count = CODETAG_ID_FIRST + kernel_tags.count +
-			module_tags.size / sizeof(struct alloc_tag);
-
-	return tag_idx_count < (1UL << NR_UNUSED_PAGEFLAG_BITS);
-}
-
-static bool needs_section_mem(struct module *mod, unsigned long size)
-{
-	if (!mem_profiling_support)
-		return false;
-
-	return size >= sizeof(struct alloc_tag);
-}
-
-static bool clean_unused_counters(struct alloc_tag *start_tag,
-				  struct alloc_tag *end_tag)
-{
-	struct alloc_tag *tag;
-	bool ret = true;
-
-	for (tag = start_tag; tag <= end_tag; tag++) {
-		struct alloc_tag_counters counter;
-
-		if (!tag->counters)
-			continue;
-
-		counter = alloc_tag_read(tag);
-		if (!counter.bytes) {
-			free_percpu(tag->counters);
-			tag->counters = NULL;
-		} else {
-			ret = false;
-		}
-	}
-
-	return ret;
-}
-
-/* Called with mod_area_mt locked */
-static void clean_unused_module_areas_locked(void)
-{
-	MA_STATE(mas, &mod_area_mt, 0, module_tags.size);
-	struct module *val;
-
-	mas_for_each(&mas, val, module_tags.size) {
-		struct alloc_tag *start_tag;
-		struct alloc_tag *end_tag;
-
-		if (val != &unloaded_mod)
-			continue;
-
-		/* Release area if all tags are unused */
-		start_tag = (struct alloc_tag *)(module_tags.start_addr + mas.index);
-		end_tag = (struct alloc_tag *)(module_tags.start_addr + mas.last);
-		if (clean_unused_counters(start_tag, end_tag))
-			mas_erase(&mas);
-	}
-}
-
-/* Called with mod_area_mt locked */
-static bool find_aligned_area(struct ma_state *mas, unsigned long section_size,
-			      unsigned long size, unsigned int prepend, unsigned long align)
-{
-	bool cleanup_done = false;
-
-repeat:
-	/* Try finding exact size and hope the start is aligned */
-	if (!mas_empty_area(mas, 0, section_size - 1, prepend + size)) {
-		if (IS_ALIGNED(mas->index + prepend, align))
-			return true;
-
-		/* Try finding larger area to align later */
-		mas_reset(mas);
-		if (!mas_empty_area(mas, 0, section_size - 1,
-				    size + prepend + align - 1))
-			return true;
-	}
-
-	/* No free area, try cleanup stale data and repeat the search once */
-	if (!cleanup_done) {
-		clean_unused_module_areas_locked();
-		cleanup_done = true;
-		mas_reset(mas);
-		goto repeat;
-	}
-
-	return false;
-}
-
-static int vm_module_tags_populate(void)
-{
-	unsigned long phys_end = ALIGN_DOWN(module_tags.start_addr, PAGE_SIZE) +
-				 (vm_module_tags->nr_pages << PAGE_SHIFT);
-	unsigned long new_end = module_tags.start_addr + module_tags.size;
-
-	if (phys_end < new_end) {
-		struct page **next_page = vm_module_tags->pages + vm_module_tags->nr_pages;
-		unsigned long old_shadow_end = ALIGN(phys_end, MODULE_ALIGN);
-		unsigned long new_shadow_end = ALIGN(new_end, MODULE_ALIGN);
-		unsigned long more_pages;
-		unsigned long nr = 0;
-
-		more_pages = ALIGN(new_end - phys_end, PAGE_SIZE) >> PAGE_SHIFT;
-		while (nr < more_pages) {
-			unsigned long allocated;
-
-			allocated = alloc_pages_bulk_node(GFP_KERNEL | __GFP_NOWARN,
-				NUMA_NO_NODE, more_pages - nr, next_page + nr);
-
-			if (!allocated)
-				break;
-			nr += allocated;
-		}
-
-		if (nr < more_pages ||
-		    vmap_pages_range(phys_end, phys_end + (nr << PAGE_SHIFT), PAGE_KERNEL,
-				     next_page, PAGE_SHIFT) < 0) {
-			release_pages_arg arg = { .pages = next_page };
-
-			/* Clean up and error out */
-			release_pages(arg, nr);
-			return -ENOMEM;
-		}
-
-		vm_module_tags->nr_pages += nr;
-
-		/*
-		 * Kasan allocates 1 byte of shadow for every 8 bytes of data.
-		 * When kasan_alloc_module_shadow allocates shadow memory,
-		 * its unit of allocation is a page.
-		 * Therefore, here we need to align to MODULE_ALIGN.
-		 */
-		if (old_shadow_end < new_shadow_end)
-			kasan_alloc_module_shadow((void *)old_shadow_end,
-						  new_shadow_end - old_shadow_end,
-						  GFP_KERNEL);
-	}
-
-	/*
-	 * Mark the pages as accessible, now that they are mapped.
-	 * With hardware tag-based KASAN, marking is skipped for
-	 * non-VM_ALLOC mappings, see __kasan_unpoison_vmalloc().
-	 */
-	kasan_unpoison_vmalloc((void *)module_tags.start_addr,
-				new_end - module_tags.start_addr,
-				KASAN_VMALLOC_PROT_NORMAL);
-
-	return 0;
-}
-
-static void *reserve_module_tags(struct module *mod, unsigned long size,
-				 unsigned int prepend, unsigned long align)
-{
-	unsigned long section_size = module_tags.end_addr - module_tags.start_addr;
-	MA_STATE(mas, &mod_area_mt, 0, section_size - 1);
-	unsigned long offset;
-	void *ret = NULL;
-
-	/* If no tags return error */
-	if (size < sizeof(struct alloc_tag))
-		return ERR_PTR(-EINVAL);
-
-	/*
-	 * align is always power of 2, so we can use IS_ALIGNED and ALIGN.
-	 * align 0 or 1 means no alignment, to simplify set to 1.
-	 */
-	if (!align)
-		align = 1;
-
-	if (!ensure_alignment(align, &prepend)) {
-		shutdown_mem_profiling(true);
-		pr_err("%s: alignment %lu is incompatible with allocation tag indexing. Memory allocation profiling is disabled!\n",
-			mod->name, align);
-		return ERR_PTR(-EINVAL);
-	}
-
-	mas_lock(&mas);
-	if (!find_aligned_area(&mas, section_size, size, prepend, align)) {
-		ret = ERR_PTR(-ENOMEM);
-		goto unlock;
-	}
-
-	/* Mark found area as reserved */
-	offset = mas.index;
-	offset += prepend;
-	offset = ALIGN(offset, align);
-	if (offset != mas.index) {
-		unsigned long pad_start = mas.index;
-
-		mas.last = offset - 1;
-		mas_store(&mas, &prepend_mod);
-		if (mas_is_err(&mas)) {
-			ret = ERR_PTR(xa_err(mas.node));
-			goto unlock;
-		}
-		mas.index = offset;
-		mas.last = offset + size - 1;
-		mas_store(&mas, mod);
-		if (mas_is_err(&mas)) {
-			mas.index = pad_start;
-			mas_erase(&mas);
-			ret = ERR_PTR(xa_err(mas.node));
-		}
-	} else {
-		mas.last = offset + size - 1;
-		mas_store(&mas, mod);
-		if (mas_is_err(&mas))
-			ret = ERR_PTR(xa_err(mas.node));
-	}
-unlock:
-	mas_unlock(&mas);
-
-	if (IS_ERR(ret))
-		return ret;
-
-	if (module_tags.size < offset + size) {
-		int grow_res;
-
-		module_tags.size = offset + size;
-		if (mem_alloc_profiling_enabled() && !tags_addressable()) {
-			shutdown_mem_profiling(true);
-			pr_warn("With module %s there are too many tags to fit in %d page flag bits. Memory allocation profiling is disabled!\n",
-				mod->name, NR_UNUSED_PAGEFLAG_BITS);
-		}
-
-		grow_res = vm_module_tags_populate();
-		if (grow_res) {
-			shutdown_mem_profiling(true);
-			pr_err("Failed to allocate memory for allocation tags in the module %s. Memory allocation profiling is disabled!\n",
-			       mod->name);
-			return ERR_PTR(grow_res);
-		}
-	}
-
-	return (struct alloc_tag *)(module_tags.start_addr + offset);
-}
-
-static void release_module_tags(struct module *mod, bool used)
-{
-	MA_STATE(mas, &mod_area_mt, module_tags.size, module_tags.size);
-	struct alloc_tag *start_tag;
-	struct alloc_tag *end_tag;
-	struct module *val;
-
-	mas_lock(&mas);
-	mas_for_each_rev(&mas, val, 0)
-		if (val == mod)
-			break;
-
-	if (!val) /* module not found */
-		goto out;
-
-	if (!used)
-		goto release_area;
-
-	start_tag = (struct alloc_tag *)(module_tags.start_addr + mas.index);
-	end_tag = (struct alloc_tag *)(module_tags.start_addr + mas.last);
-	if (!clean_unused_counters(start_tag, end_tag)) {
-		struct alloc_tag *tag;
-
-		for (tag = start_tag; tag <= end_tag; tag++) {
-			struct alloc_tag_counters counter;
-
-			if (!tag->counters)
-				continue;
-
-			counter = alloc_tag_read(tag);
-			pr_info("%s:%u module %s func:%s has %llu allocated at module unload\n",
-				tag->ct.filename, tag->ct.lineno, tag->ct.modname,
-				tag->ct.function, counter.bytes);
-		}
-	} else {
-		used = false;
-	}
-release_area:
-	mas_store(&mas, used ? &unloaded_mod : NULL);
-	val = mas_prev_range(&mas, 0);
-	if (val == &prepend_mod)
-		mas_store(&mas, NULL);
-out:
-	mas_unlock(&mas);
-}
-
-static int load_module(struct module *mod, struct codetag *start, struct codetag *stop)
-{
-	/* Allocate module alloc_tag percpu counters */
-	struct alloc_tag *start_tag;
-	struct alloc_tag *stop_tag;
-	struct alloc_tag *tag;
-
-	/* percpu counters for core allocations are already statically allocated */
-	if (!mod)
-		return 0;
-
-	start_tag = ct_to_alloc_tag(start);
-	stop_tag = ct_to_alloc_tag(stop);
-	for (tag = start_tag; tag < stop_tag; tag++) {
-		WARN_ON(tag->counters);
-		tag->counters = alloc_percpu(struct alloc_tag_counters);
-		if (!tag->counters) {
-			while (--tag >= start_tag) {
-				free_percpu(tag->counters);
-				tag->counters = NULL;
-			}
-			pr_err("Failed to allocate memory for allocation tag percpu counters in the module %s\n",
-			       mod->name);
-			return -ENOMEM;
-		}
-
-		/*
-		 * Avoid a kmemleak false positive. The pointer to the counters is stored
-		 * in the alloc_tag section of the module and cannot be directly accessed.
-		 */
-		kmemleak_ignore_percpu(tag->counters);
-	}
-	return 0;
-}
-
-static void replace_module(struct module *mod, struct module *new_mod)
-{
-	MA_STATE(mas, &mod_area_mt, 0, module_tags.size);
-	struct module *val;
-
-	mas_lock(&mas);
-	mas_for_each(&mas, val, module_tags.size) {
-		if (val != mod)
-			continue;
-
-		mas_store_gfp(&mas, new_mod, GFP_KERNEL);
-		break;
-	}
-	mas_unlock(&mas);
-}
-
-static int __init alloc_mod_tags_mem(void)
-{
-	/* Map space to copy allocation tags */
-	vm_module_tags = execmem_vmap(MODULE_ALLOC_TAG_VMAP_SIZE);
-	if (!vm_module_tags) {
-		pr_err("Failed to map %lu bytes for module allocation tags\n",
-			MODULE_ALLOC_TAG_VMAP_SIZE);
-		module_tags.start_addr = 0;
-		return -ENOMEM;
-	}
-
-	vm_module_tags->pages = kmalloc_objs(struct page *,
-					     get_vm_area_size(vm_module_tags) >> PAGE_SHIFT,
-					     GFP_KERNEL | __GFP_ZERO);
-	if (!vm_module_tags->pages) {
-		free_vm_area(vm_module_tags);
-		return -ENOMEM;
-	}
-
-	module_tags.start_addr = (unsigned long)vm_module_tags->addr;
-	module_tags.end_addr = module_tags.start_addr + MODULE_ALLOC_TAG_VMAP_SIZE;
-	/* Ensure the base is alloc_tag aligned when required for indexing */
-	module_tags.start_addr = alloc_tag_align(module_tags.start_addr);
-
-	return 0;
-}
-
-static void __init free_mod_tags_mem(void)
-{
-	release_pages_arg arg = { .pages = vm_module_tags->pages };
-
-	module_tags.start_addr = 0;
-	release_pages(arg, vm_module_tags->nr_pages);
-	kfree(vm_module_tags->pages);
-	free_vm_area(vm_module_tags);
-}
-
-#else /* CONFIG_MODULES */
-
-static inline int alloc_mod_tags_mem(void) { return 0; }
-static inline void free_mod_tags_mem(void) {}
-
-#endif /* CONFIG_MODULES */
-
-/* See: Documentation/mm/allocation-profiling.rst */
-static int __init setup_early_mem_profiling(char *str)
-{
-	bool compressed = false;
-	bool enable;
-
-	if (!str || !str[0])
-		return -EINVAL;
-
-	if (!strncmp(str, "never", 5)) {
-		enable = false;
-		mem_profiling_support = false;
-		pr_info("Memory allocation profiling is disabled!\n");
-	} else {
-		char *token = strsep(&str, ",");
-
-		if (kstrtobool(token, &enable))
-			return -EINVAL;
-
-		if (str) {
-
-			if (strcmp(str, "compressed"))
-				return -EINVAL;
-
-			compressed = true;
-		}
-		mem_profiling_support = true;
-		pr_info("Memory allocation profiling is enabled %s compression and is turned %s!\n",
-			compressed ? "with" : "without", str_on_off(enable));
-	}
-
-	if (enable != mem_alloc_profiling_enabled()) {
-		if (enable)
-			static_branch_enable(&mem_alloc_profiling_key);
-		else
-			static_branch_disable(&mem_alloc_profiling_key);
-	}
-	if (compressed != static_key_enabled(&mem_profiling_compressed)) {
-		if (compressed)
-			static_branch_enable(&mem_profiling_compressed);
-		else
-			static_branch_disable(&mem_profiling_compressed);
-	}
-
-	return 0;
-}
-early_param("sysctl.vm.mem_profiling", setup_early_mem_profiling);
-
-static __init bool need_page_alloc_tagging(void)
-{
-	if (static_key_enabled(&mem_profiling_compressed))
-		return false;
-
-	return mem_profiling_support;
-}
-
-#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG
-/*
- * Track page allocations before page_ext is initialized.
- * Some pages are allocated before page_ext becomes available, leaving
- * their codetag uninitialized. Track these early PFNs so we can clear
- * their codetag refs later to avoid warnings when they are freed.
- *
- * Each page is cast to a pfn_pool: the first few bytes hold metadata
- * (next pointer and slot count), the remainder stores PFNs.
- */
-struct pfn_pool {
-	struct pfn_pool *next;
-	atomic_t count;
-	unsigned long pfns[];
-};
-
-#define PFN_POOL_SIZE			((PAGE_SIZE - offsetof(struct pfn_pool, pfns)) / \
-					 sizeof(unsigned long))
-
-/*
- * Skip early PFN recording for a page allocation.  Reuses the
- * %__GFP_NO_OBJ_EXT bit.  Used by __alloc_tag_add_early_pfn() to avoid
- * recursion when allocating pages for the early PFN tracking list
- * itself.
- *
- * Codetags of the pages allocated with __GFP_NO_CODETAG should be
- * cleared (via clear_page_tag_ref()) before freeing the pages to prevent
- * alloc_tag_sub_check() from triggering a warning.
- */
-#define __GFP_NO_CODETAG		__GFP_NO_OBJ_EXT
-
-static struct pfn_pool *current_pfn_pool __initdata;
-
-static void __init __alloc_tag_add_early_pfn(unsigned long pfn)
-{
-	struct pfn_pool *pool;
-	int idx;
-
-	do {
-		pool = READ_ONCE(current_pfn_pool);
-		if (!pool || atomic_read(&pool->count) >= PFN_POOL_SIZE) {
-			struct page *new_page = alloc_page(__GFP_HIGH | __GFP_NO_CODETAG);
-			struct pfn_pool *new;
-
-			if (!new_page) {
-				pr_warn_once("early PFN tracking page allocation failed\n");
-				return;
-			}
-			new = page_address(new_page);
-			new->next = pool;
-			atomic_set(&new->count, 0);
-			if (cmpxchg(&current_pfn_pool, pool, new) != pool) {
-				clear_page_tag_ref(new_page);
-				__free_page(new_page);
-				continue;
-			}
-			pool = new;
-		}
-		idx = atomic_read(&pool->count);
-		if (idx >= PFN_POOL_SIZE)
-			continue;
-		if (atomic_cmpxchg(&pool->count, idx, idx + 1) == idx)
-			break;
-	} while (1);
-
-	pool->pfns[idx] = pfn;
-}
-
-typedef void alloc_tag_add_func(unsigned long pfn);
-static alloc_tag_add_func __rcu *alloc_tag_add_early_pfn_ptr __refdata =
-	RCU_INITIALIZER(__alloc_tag_add_early_pfn);
-
-void alloc_tag_add_early_pfn(unsigned long pfn, gfp_t gfp_flags)
-{
-	alloc_tag_add_func *alloc_tag_add;
-
-	if (static_key_enabled(&mem_profiling_compressed))
-		return;
-
-	/* Skip allocations for the tracking list itself to avoid recursion. */
-	if (gfp_flags & __GFP_NO_CODETAG)
-		return;
-
-	rcu_read_lock();
-	alloc_tag_add = rcu_dereference(alloc_tag_add_early_pfn_ptr);
-	if (alloc_tag_add)
-		alloc_tag_add(pfn);
-	rcu_read_unlock();
-}
-
-static void __init clear_early_alloc_pfn_tag_refs(void)
-{
-	struct pfn_pool *pool, *next;
-	struct page *page;
-	int i;
-
-	if (static_key_enabled(&mem_profiling_compressed))
-		return;
-
-	rcu_assign_pointer(alloc_tag_add_early_pfn_ptr, NULL);
-	/* Make sure we are not racing with __alloc_tag_add_early_pfn() */
-	synchronize_rcu();
-
-	for (pool = current_pfn_pool; pool; pool = next) {
-		int nr_pfns = atomic_read(&pool->count);
-
-		for (i = 0; i < nr_pfns; i++) {
-			unsigned long pfn = pool->pfns[i];
-
-			if (pfn_valid(pfn)) {
-				union pgtag_ref_handle handle;
-				union codetag_ref ref;
-
-				if (get_page_tag_ref(pfn_to_page(pfn), &ref, &handle)) {
-					/*
-					 * An early-allocated page could be freed and reallocated
-					 * after its page_ext is initialized but before we clear it.
-					 * In that case, it already has a valid tag set.
-					 * We should not overwrite that valid tag
-					 * with CODETAG_EMPTY.
-					 *
-					 * Note: there is still a small race window between checking
-					 * ref.ct and calling set_codetag_empty(). We accept this
-					 * race as it's unlikely and the extra complexity of atomic
-					 * cmpxchg is not worth it for this debug-only code path.
-					 */
-					if (ref.ct) {
-						put_page_tag_ref(handle);
-						continue;
-					}
-
-					set_codetag_empty(&ref);
-					update_page_tag_ref(handle, &ref);
-					put_page_tag_ref(handle);
-				}
-			}
-		}
-
-		next = pool->next;
-		page = virt_to_page(pool);
-		clear_page_tag_ref(page);
-		__free_page(page);
-	}
-}
-#else /* !CONFIG_MEM_ALLOC_PROFILING_DEBUG */
-static inline void __init clear_early_alloc_pfn_tag_refs(void) {}
-#endif /* CONFIG_MEM_ALLOC_PROFILING_DEBUG */
-
-static __init void init_page_alloc_tagging(void)
-{
-	clear_early_alloc_pfn_tag_refs();
-}
-
-struct page_ext_operations page_alloc_tagging_ops = {
-	.size = sizeof(union codetag_ref),
-	.need = need_page_alloc_tagging,
-	.init = init_page_alloc_tagging,
-};
-EXPORT_SYMBOL(page_alloc_tagging_ops);
-
-#ifdef CONFIG_SYSCTL
-/*
- * Not using proc_do_static_key() directly to prevent enabling profiling
- * after it was shut down.
- */
-static int proc_mem_profiling_handler(const struct ctl_table *table, int write,
-				      void *buffer, size_t *lenp, loff_t *ppos)
-{
-	if (write) {
-		/*
-		 * Call from do_sysctl_args() which is a no-op since the same
-		 * value was already set by setup_early_mem_profiling.
-		 * Return success to avoid warnings from do_sysctl_args().
-		 */
-		if (!current->mm)
-			return 0;
-
-#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG
-		/* User can't toggle profiling while debugging */
-		return -EACCES;
-#endif
-		if (!mem_profiling_support)
-			return -EINVAL;
-	}
-
-	return proc_do_static_key(table, write, buffer, lenp, ppos);
-}
-
-
-static const struct ctl_table memory_allocation_profiling_sysctls[] = {
-	{
-		.procname	= "mem_profiling",
-		.data		= &mem_alloc_profiling_key,
-		.mode		= 0644,
-		.proc_handler	= proc_mem_profiling_handler,
-	},
-};
-
-static void __init sysctl_init(void)
-{
-	register_sysctl_init("vm", memory_allocation_profiling_sysctls);
-}
-#else /* CONFIG_SYSCTL */
-static inline void sysctl_init(void) {}
-#endif /* CONFIG_SYSCTL */
-
-static int __init alloc_tag_init(void)
-{
-	const struct codetag_type_desc desc = {
-		.section		= ALLOC_TAG_SECTION_NAME,
-		.tag_size		= sizeof(struct alloc_tag),
-#ifdef CONFIG_MODULES
-		.needs_section_mem	= needs_section_mem,
-		.alloc_section_mem	= reserve_module_tags,
-		.free_section_mem	= release_module_tags,
-		.module_load		= load_module,
-		.module_replaced	= replace_module,
-#endif
-	};
-	int res;
-
-	sysctl_init();
-
-	if (!mem_profiling_support) {
-		pr_info("Memory allocation profiling is not supported!\n");
-		return 0;
-	}
-
-	if (!proc_create_seq_private(ALLOCINFO_FILE_NAME, 0400, NULL, &allocinfo_seq_op,
-				     sizeof(struct allocinfo_private), NULL)) {
-		pr_err("Failed to create %s file\n", ALLOCINFO_FILE_NAME);
-		shutdown_mem_profiling(false);
-		return -ENOMEM;
-	}
-
-	res = alloc_mod_tags_mem();
-	if (res) {
-		pr_err("Failed to reserve address space for module tags, errno = %d\n", res);
-		shutdown_mem_profiling(true);
-		return res;
-	}
-
-	alloc_tag_cttype = codetag_register_type(&desc);
-	if (IS_ERR(alloc_tag_cttype)) {
-		pr_err("Allocation tags registration failed, errno = %pe\n", alloc_tag_cttype);
-		free_mod_tags_mem();
-		shutdown_mem_profiling(true);
-		return PTR_ERR(alloc_tag_cttype);
-	}
-
-	return 0;
-}
-module_init(alloc_tag_init);
_

Patches currently in -mm which might be from akpm@linux-foundation.org are

mm-memory_hotplug-factor-out-node_is_memoryless-fix.patch
mm-hugetlb-dont-lock-private-resv_map-during-final-unmap.patch
drivers-media-v4l2-core-v4l2-vp9c-reduce-inlining.patch


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-05 18:48 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-05 18:48 [merged mm-hotfixes-stable] remove-old-lib-alloc_tagc.patch removed from -mm tree Andrew Morton

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.