Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b3635ac authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "mm: slub: Add debugfs interface to capture slub allocs owner"

parents 3bd5b143 0414f5d0
Loading
Loading
Loading
Loading
+99 −0
Original line number Diff line number Diff line
@@ -41,6 +41,10 @@
#include <linux/jhash.h>
#endif

#ifdef CONFIG_SLUB_DEBUG
#include <linux/debugfs.h>
#endif

#include "internal.h"

/*
@@ -6084,6 +6088,85 @@ struct saved_alias {

static struct saved_alias *alias_list;

#ifdef CONFIG_SLUB_DEBUG
static struct dentry *slab_debugfs_top;

static int alloc_trace_locations(struct seq_file *seq, struct kmem_cache *s,
			enum track_item alloc)
{
	unsigned long i;
	struct loc_track t = { 0, 0, NULL };
	int node;
	unsigned long *map = kmalloc(BITS_TO_LONGS(oo_objects(s->max)) *
			sizeof(unsigned long), GFP_KERNEL);
	struct kmem_cache_node *n;

	if (!map || !alloc_loc_track(&t, PAGE_SIZE / sizeof(struct location),
			GFP_KERNEL)) {
		kfree(map);
		return -ENOMEM;
	}
	/* Push back cpu slabs */
	flush_all(s);

	for_each_kmem_cache_node(s, node, n) {
		unsigned long flags;
		struct page *page;

		if (!atomic_long_read(&n->nr_slabs))
			continue;

		spin_lock_irqsave(&n->list_lock, flags);
		list_for_each_entry(page, &n->partial, lru)
			process_slab(&t, s, page, alloc, map);
		list_for_each_entry(page, &n->full, lru)
			process_slab(&t, s, page, alloc, map);
		spin_unlock_irqrestore(&n->list_lock, flags);
	}

	for (i = 0; i < t.count; i++) {
		struct location *l = &t.loc[i];

		seq_printf(seq,
		"alloc_list: call_site=%pS count=%zu object_size=%zu slab_size=%zu slab_name=%s\n",
			l->addr, l->count, s->object_size, s->size, s->name);
	}

	free_loc_track(&t);
	kfree(map);
	return 0;
}

static int slab_debug_alloc_trace(struct seq_file *seq,
					void *ignored)
{

	struct kmem_cache *slab;

	list_for_each_entry(slab, &slab_caches, list) {
		if (!(slab->flags & SLAB_STORE_USER))
			continue;
		alloc_trace_locations(seq, slab, TRACK_ALLOC);
	}

	return 0;
}

static int slab_debug_alloc_trace_open(struct inode *inode,
					struct file *file)
{
	return single_open(file, slab_debug_alloc_trace,
					inode->i_private);
}

static const struct file_operations slab_debug_alloc_fops = {
	.open    = slab_debug_alloc_trace_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.release = single_release,
};
#endif

static int sysfs_slab_alias(struct kmem_cache *s, const char *name)
{
	struct saved_alias *al;
@@ -6213,6 +6296,22 @@ static int __init slab_sysfs_init(void)
			       s->name);
	}

#ifdef CONFIG_SLUB_DEBUG
	if (slub_debug) {
		slab_debugfs_top = debugfs_create_dir("slab", NULL);
		if (!slab_debugfs_top) {
			pr_err("Couldn't create slab debugfs directory\n");
			return -ENODEV;
		}

		if (!debugfs_create_file("alloc_trace", 0400, slab_debugfs_top,
					NULL, &slab_debug_alloc_fops)) {
			pr_err("Couldn't create slab/tests debugfs directory\n");
			return -ENODEV;
		}
	}
#endif

	while (alias_list) {
		struct saved_alias *al = alias_list;