diff mbox series
Message ID | 1623115958-732-1-git-send-email-faiyazm@codeaurora.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v11] mm: slub: move sysfs slab alloc/free interfaces to debugfs | expand |
Commit Message
Faiyaz Mohammed June 8, 2021, 1:32 a.m. UTC
alloc_calls and free_calls implementation in sysfs have two issues,one is PAGE_SIZE limitation of sysfs and other is it does not adhereto "one value per file" rule.To overcome this issues, move the alloc_calls and free_callsimplementation to debugfs.Debugfs cache will be created if SLAB_STORE_USER flag is set.Rename the alloc_calls/free_calls to alloc_traces/free_traces,to be inline with what it does.Signed-off-by: Faiyaz Mohammed <faiyazm@codeaurora.org>---changes in v11:- slab_debug_trace_release updated with seq_release_private. changes in v10:- https://lore.kernel.org/linux-mm/1622996045-25826-1-git-send-email-faiyazm@codeaurora.org/changes in v9:- https://lore.kernel.org/linux-mm/1622556633-29785-1-git-send-email-faiyazm@codeaurora.org/changes in v8:- https://lore.kernel.org/linux-mm/1622542057-14632-1-git-send-email-faiyazm@codeaurora.org/changes in V7:- https://lore.kernel.org/linux-mm/1621928285-751-1-git-send-email-faiyazm@codeaurora.org/changes in v6:- https://lore.kernel.org/linux-mm/1621341949-26762-1-git-send-email-faiyazm@codeaurora.org/changes in v5:- https://lore.kernel.org/linux-mm/1620296523-21922-1-git-send-email-faiyazm@codeaurora.org/changes in v4:- https://lore.kernel.org/linux-mm/1618583239-18124-1-git-send-email-faiyazm@codeaurora.org/changes in v3:- https://lore.kernel.org/linux-mm/1617712064-12264-1-git-send-email-faiyazm@codeaurora.org/changes in v2:- https://lore.kernel.org/linux-mm/3ac1d3e6-6207-96ad-16a1-0f5139d8b2b5@codeaurora.org/changes in v1- https://lore.kernel.org/linux-mm/1610443287-23933-1-git-send-email-faiyazm@codeaurora.org/ mm/slab.h | 6 ++ mm/slab_common.c | 2 + mm/slub.c | 282 +++++++++++++++++++++++++++++++++++++------------------ 3 files changed, 197 insertions(+), 93 deletions(-)
Comments
kernel test robot June 8, 2021, 7:28 a.m. UTC | #1
Hi Faiyaz,Thank you for the patch! Yet something to improve:[auto build test ERROR on v5.13-rc5][cannot apply to hnaz-linux-mm/master next-20210607][If your patch is applied to the wrong git tree, kindly drop us a note.And when submitting patch, we suggest to use '--base' as documented inhttps://git-scm.com/docs/git-format-patch]url: https://github.com/0day-ci/linux/commits/Faiyaz-Mohammed/mm-slub-move-sysfs-slab-alloc-free-interfaces-to-debugfs/20210608-093347base: 614124bea77e452aa6df7a8714e8bc820b489922config: ia64-randconfig-r032-20210607 (attached as .config)compiler: ia64-linux-gcc (GCC) 9.3.0reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/bc5e268c4852dc56a0d1c7a8ded8557db36b871b git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Faiyaz-Mohammed/mm-slub-move-sysfs-slab-alloc-free-interfaces-to-debugfs/20210608-093347 git checkout bc5e268c4852dc56a0d1c7a8ded8557db36b871b # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=ia64 If you fix the issue, kindly add following tag as appropriateReported-by: kernel test robot <lkp@intel.com>All errors (new ones prefixed by >>): In file included from arch/ia64/include/asm/pgtable.h:154, from include/linux/pgtable.h:6, from include/linux/mm.h:33, from mm/slub.c:13: arch/ia64/include/asm/mmu_context.h: In function 'reload_context': arch/ia64/include/asm/mmu_context.h:127:41: warning: variable 'old_rr4' set but not used [-Wunused-but-set-variable] 127 | unsigned long rr0, rr1, rr2, rr3, rr4, old_rr4; | ^~~~~~~ mm/slub.c: In function 'slab_debug_trace_release':>> mm/slub.c:5868:24: error: 'seq' undeclared (first use in this function); did you mean 'rseq'? 5868 | struct loc_track *t = seq->private; | ^~~ | rseq mm/slub.c:5868:24: note: each undeclared identifier is reported only once for each function it appears invim +5868 mm/slub.c 5865 5866static int slab_debug_trace_release(struct inode *inode, struct file *file) 5867{> 5868struct loc_track *t = seq->private; 5869 5870free_loc_track(t); 5871return seq_release_private(inode, file); 5872} 5873---0-DAY CI Kernel Test Service, Intel Corporationhttps://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Faiyaz Mohammed June 8, 2021, 7:35 a.m. UTC | #2
On 6/8/2021 7:02 AM, Faiyaz Mohammed wrote:> alloc_calls and free_calls implementation in sysfs have two issues,> one is PAGE_SIZE limitation of sysfs and other is it does not adhere> to "one value per file" rule.> > To overcome this issues, move the alloc_calls and free_calls> implementation to debugfs.> > Debugfs cache will be created if SLAB_STORE_USER flag is set.> > Rename the alloc_calls/free_calls to alloc_traces/free_traces,> to be inline with what it does.> > Signed-off-by: Faiyaz Mohammed <faiyazm@codeaurora.org>> ---> changes in v11:> - slab_debug_trace_release updated with seq_release_private. > > changes in v10:> - https://lore.kernel.org/linux-mm/1622996045-25826-1-git-send-email-faiyazm@codeaurora.org/> > changes in v9:> - https://lore.kernel.org/linux-mm/1622556633-29785-1-git-send-email-faiyazm@codeaurora.org/> > changes in v8:> - https://lore.kernel.org/linux-mm/1622542057-14632-1-git-send-email-faiyazm@codeaurora.org/> > changes in V7:> - https://lore.kernel.org/linux-mm/1621928285-751-1-git-send-email-faiyazm@codeaurora.org/> > changes in v6:> - https://lore.kernel.org/linux-mm/1621341949-26762-1-git-send-email-faiyazm@codeaurora.org/> > changes in v5:> - https://lore.kernel.org/linux-mm/1620296523-21922-1-git-send-email-faiyazm@codeaurora.org/> > changes in v4:> - https://lore.kernel.org/linux-mm/1618583239-18124-1-git-send-email-faiyazm@codeaurora.org/> > changes in v3:> - https://lore.kernel.org/linux-mm/1617712064-12264-1-git-send-email-faiyazm@codeaurora.org/> > changes in v2:> - https://lore.kernel.org/linux-mm/3ac1d3e6-6207-96ad-16a1-0f5139d8b2b5@codeaurora.org/> > changes in v1> - https://lore.kernel.org/linux-mm/1610443287-23933-1-git-send-email-faiyazm@codeaurora.org/> > mm/slab.h | 6 ++> mm/slab_common.c | 2 +> mm/slub.c | 282 +++++++++++++++++++++++++++++++++++++------------------> 3 files changed, 197 insertions(+), 93 deletions(-)> > diff --git a/mm/slab.h b/mm/slab.h> index 18c1927..60d4f4b 100644> --- a/mm/slab.h> +++ b/mm/slab.h> @@ -630,6 +630,12 @@ static inline bool slab_want_init_on_free(struct kmem_cache *c)> return false;> }> > +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_SLUB_DEBUG)> +void debugfs_slab_release(struct kmem_cache *);> +#else> +static inline void debugfs_slab_release(struct kmem_cache *s) { }> +#endif> +> #ifdef CONFIG_PRINTK> #define KS_ADDRS_COUNT 16> struct kmem_obj_info {> diff --git a/mm/slab_common.c b/mm/slab_common.c> index a4a5714..ee5456f 100644> --- a/mm/slab_common.c> +++ b/mm/slab_common.c> @@ -449,6 +449,7 @@ static void slab_caches_to_rcu_destroy_workfn(struct work_struct *work)> rcu_barrier();> > list_for_each_entry_safe(s, s2, &to_destroy, list) {> +debugfs_slab_release(s);> kfence_shutdown_cache(s);> #ifdef SLAB_SUPPORTS_SYSFS> sysfs_slab_release(s);> @@ -476,6 +477,7 @@ static int shutdown_cache(struct kmem_cache *s)> schedule_work(&slab_caches_to_rcu_destroy_work);> } else {> kfence_shutdown_cache(s);> +debugfs_slab_release(s);> #ifdef SLAB_SUPPORTS_SYSFS> sysfs_slab_unlink(s);> sysfs_slab_release(s);> diff --git a/mm/slub.c b/mm/slub.c> index 3f96e09..09f93ce 100644> --- a/mm/slub.c> +++ b/mm/slub.c> @@ -36,6 +36,7 @@> #include <linux/memcontrol.h>> #include <linux/random.h>> > +#include <linux/debugfs.h>> #include <trace/events/kmem.h>> > #include "internal.h"> @@ -225,6 +226,12 @@ static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p)> { return 0; }> #endif> > +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_SLUB_DEBUG)> +static void debugfs_slab_add(struct kmem_cache *);> +#else> +static inline void debugfs_slab_add(struct kmem_cache *s) { }> +#endif> +> static inline void stat(const struct kmem_cache *s, enum stat_item si)> {> #ifdef CONFIG_SLUB_STATS> @@ -4546,6 +4553,9 @@ int __kmem_cache_create(struct kmem_cache *s, slab_flags_t flags)> if (err)> __kmem_cache_release(s);> > +if (s->flags & SLAB_STORE_USER)> +debugfs_slab_add(s);> +> return err;> }> > @@ -4686,6 +4696,8 @@ static long validate_slab_cache(struct kmem_cache *s)> > return count;> }> +> +#ifdef CONFIG_DEBUG_FS> /*> * Generate lists of code addresses where slabcache objects are allocated> * and freed.> @@ -4709,6 +4721,8 @@ struct loc_track {> struct location *loc;> };> > +static struct dentry *slab_debugfs_root;> +> static void free_loc_track(struct loc_track *t)> {> if (t->max)> @@ -4825,82 +4839,7 @@ static void process_slab(struct loc_track *t, struct kmem_cache *s,> add_location(t, s, get_track(s, p, alloc));> put_map(map);> }> -> -static int list_locations(struct kmem_cache *s, char *buf,> - enum track_item alloc)> -{> -int len = 0;> -unsigned long i;> -struct loc_track t = { 0, 0, NULL };> -int node;> -struct kmem_cache_node *n;> -> -if (!alloc_loc_track(&t, PAGE_SIZE / sizeof(struct location),> - GFP_KERNEL)) {> -return sysfs_emit(buf, "Out of memory\n");> -}> -/* 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, slab_list)> -process_slab(&t, s, page, alloc);> -list_for_each_entry(page, &n->full, slab_list)> -process_slab(&t, s, page, alloc);> -spin_unlock_irqrestore(&n->list_lock, flags);> -}> -> -for (i = 0; i < t.count; i++) {> -struct location *l = &t.loc[i];> -> -len += sysfs_emit_at(buf, len, "%7ld ", l->count);> -> -if (l->addr)> -len += sysfs_emit_at(buf, len, "%pS", (void *)l->addr);> -else> -len += sysfs_emit_at(buf, len, "<not-available>");> -> -if (l->sum_time != l->min_time)> -len += sysfs_emit_at(buf, len, " age=%ld/%ld/%ld",> - l->min_time,> - (long)div_u64(l->sum_time,> - l->count),> - l->max_time);> -else> -len += sysfs_emit_at(buf, len, " age=%ld", l->min_time);> -> -if (l->min_pid != l->max_pid)> -len += sysfs_emit_at(buf, len, " pid=%ld-%ld",> - l->min_pid, l->max_pid);> -else> -len += sysfs_emit_at(buf, len, " pid=%ld",> - l->min_pid);> -> -if (num_online_cpus() > 1 &&> - !cpumask_empty(to_cpumask(l->cpus)))> -len += sysfs_emit_at(buf, len, " cpus=%*pbl",> - cpumask_pr_args(to_cpumask(l->cpus)));> -> -if (nr_online_nodes > 1 && !nodes_empty(l->nodes))> -len += sysfs_emit_at(buf, len, " nodes=%*pbl",> - nodemask_pr_args(&l->nodes));> -> -len += sysfs_emit_at(buf, len, "\n");> -}> -> -free_loc_track(&t);> -if (!t.count)> -len += sysfs_emit_at(buf, len, "No data\n");> -> -return len;> -}> +#endif /* CONFIG_DEBUG_FS */> #endif/* CONFIG_SLUB_DEBUG */> > #ifdef SLUB_RESILIENCY_TEST> @@ -5350,21 +5289,6 @@ static ssize_t validate_store(struct kmem_cache *s,> }> SLAB_ATTR(validate);> > -static ssize_t alloc_calls_show(struct kmem_cache *s, char *buf)> -{> -if (!(s->flags & SLAB_STORE_USER))> -return -ENOSYS;> -return list_locations(s, buf, TRACK_ALLOC);> -}> -SLAB_ATTR_RO(alloc_calls);> -> -static ssize_t free_calls_show(struct kmem_cache *s, char *buf)> -{> -if (!(s->flags & SLAB_STORE_USER))> -return -ENOSYS;> -return list_locations(s, buf, TRACK_FREE);> -}> -SLAB_ATTR_RO(free_calls);> #endif /* CONFIG_SLUB_DEBUG */> > #ifdef CONFIG_FAILSLAB> @@ -5528,8 +5452,6 @@ static struct attribute *slab_attrs[] = {> &poison_attr.attr,> &store_user_attr.attr,> &validate_attr.attr,> -&alloc_calls_attr.attr,> -&free_calls_attr.attr,> #endif> #ifdef CONFIG_ZONE_DMA> &cache_dma_attr.attr,> @@ -5818,6 +5740,180 @@ static int __init slab_sysfs_init(void)> __initcall(slab_sysfs_init);> #endif /* CONFIG_SYSFS */> > +#if defined(CONFIG_SLUB_DEBUG) && defined(CONFIG_DEBUG_FS)> +static int slab_debugfs_show(struct seq_file *seq, void *v)> +{> +> +struct location *l;> +unsigned int idx = *(unsigned int *)v;> +struct loc_track *t = seq->private;> +> +if (idx < t->count) {> +l = &t->loc[idx];> +> +seq_printf(seq, "%7ld ", l->count);> +> +if (l->addr)> +seq_printf(seq, "%pS", (void *)l->addr);> +else> +seq_puts(seq, "<not-available>");> +> +if (l->sum_time != l->min_time) {> +seq_printf(seq, " age=%ld/%llu/%ld",> +l->min_time, div_u64(l->sum_time, l->count),> +l->max_time);> +} else> +seq_printf(seq, " age=%ld", l->min_time);> +> +if (l->min_pid != l->max_pid)> +seq_printf(seq, " pid=%ld-%ld", l->min_pid, l->max_pid);> +else> +seq_printf(seq, " pid=%ld",> +l->min_pid);> +> +if (num_online_cpus() > 1 && !cpumask_empty(to_cpumask(l->cpus)))> +seq_printf(seq, " cpus=%*pbl",> + cpumask_pr_args(to_cpumask(l->cpus)));> +> +if (nr_online_nodes > 1 && !nodes_empty(l->nodes))> +seq_printf(seq, " nodes=%*pbl",> + nodemask_pr_args(&l->nodes));> +> +seq_puts(seq, "\n");> +}> +> +if (!idx && !t->count)> +seq_puts(seq, "No data\n");> +> +return 0;> +}> +> +static void slab_debugfs_stop(struct seq_file *seq, void *v)> +{> +kfree(v);> +}> +> +static void *slab_debugfs_next(struct seq_file *seq, void *v, loff_t *ppos)> +{> +loff_t *spos = v;> +struct loc_track *t = seq->private;> +> +if (*ppos < t->count) {> +*ppos = ++*spos;> +return spos;> +}> +*ppos = ++*spos;> +return NULL;> +}> +> +static void *slab_debugfs_start(struct seq_file *seq, loff_t *ppos)> +{> +loff_t *spos = kmalloc(sizeof(loff_t), GFP_KERNEL);> +> +if (!spos)> +return NULL;> +> +*spos = *ppos;> +return spos;> +}> +> +static const struct seq_operations slab_debugfs_sops = {> +.start = slab_debugfs_start,> +.next = slab_debugfs_next,> +.stop = slab_debugfs_stop,> +.show = slab_debugfs_show,> +};> +> +static int slab_debug_trace_open(struct inode *inode, struct file *filep)> +{> +> +struct kmem_cache_node *n;> +enum track_item alloc;> +int node;> +struct loc_track *t = __seq_open_private(filep, &slab_debugfs_sops,> +sizeof(struct loc_track));> +struct kmem_cache *s = file_inode(filep)->i_private;> +> +if (strcmp(filep->f_path.dentry->d_name.name, "alloc_traces") == 0)> +alloc = TRACK_ALLOC;> +else> +alloc = TRACK_FREE;> +> +if (!alloc_loc_track(t, PAGE_SIZE / sizeof(struct location), GFP_KERNEL))> +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, slab_list)> +process_slab(t, s, page, alloc);> +list_for_each_entry(page, &n->full, slab_list)> +process_slab(t, s, page, alloc);> +spin_unlock_irqrestore(&n->list_lock, flags);> +}> +> +return 0;> +}> +> +static int slab_debug_trace_release(struct inode *inode, struct file *file)> +{Please ignore this patch, while doing clean up I missed the "structseq_file *seq = file->private_data;"I will push the patch with same patch version.> +struct loc_track *t = seq->private;> +> +free_loc_track(t);> +return seq_release_private(inode, file);> +}> +> +static const struct file_operations slab_debugfs_fops = {> +.open = slab_debug_trace_open,> +.read = seq_read,> +.llseek = seq_lseek,> +.release = slab_debug_trace_release,> +};> +> +static void debugfs_slab_add(struct kmem_cache *s)> +{> +struct dentry *slab_cache_dir;> +> +if (unlikely(!slab_debugfs_root))> +return;> +> +slab_cache_dir = debugfs_create_dir(s->name, slab_debugfs_root);> +> +debugfs_create_file("alloc_traces", 0400,> +slab_cache_dir, s, &slab_debugfs_fops);> +> +debugfs_create_file("free_traces", 0400,> +slab_cache_dir, s, &slab_debugfs_fops);> +}> +> +void debugfs_slab_release(struct kmem_cache *s)> +{> +debugfs_remove_recursive(debugfs_lookup(s->name, slab_debugfs_root));> +}> +> +static int __init slab_debugfs_init(void)> +{> +struct kmem_cache *s;> +> +slab_debugfs_root = debugfs_create_dir("slab", NULL);> +> +list_for_each_entry(s, &slab_caches, list)> +if (s->flags & SLAB_STORE_USER)> +debugfs_slab_add(s);> +> +return 0;> +> +}> +__initcall(slab_debugfs_init);> +#endif> /*> * The /proc/slabinfo ABI> */> Thanks and regards,Mohammed Faiyaz
kernel test robot June 8, 2021, 1:19 p.m. UTC | #3
Hi Faiyaz,Thank you for the patch! Yet something to improve:[auto build test ERROR on v5.13-rc5][cannot apply to hnaz-linux-mm/master next-20210607][If your patch is applied to the wrong git tree, kindly drop us a note.And when submitting patch, we suggest to use '--base' as documented inhttps://git-scm.com/docs/git-format-patch]url: https://github.com/0day-ci/linux/commits/Faiyaz-Mohammed/mm-slub-move-sysfs-slab-alloc-free-interfaces-to-debugfs/20210608-093347base: 614124bea77e452aa6df7a8714e8bc820b489922config: x86_64-randconfig-r033-20210607 (attached as .config)compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project d32cc150feb72f315a5bbd34f92e7beca21a50da)reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # install x86_64 cross compiling tool for clang build # apt-get install binutils-x86-64-linux-gnu # https://github.com/0day-ci/linux/commit/bc5e268c4852dc56a0d1c7a8ded8557db36b871b git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Faiyaz-Mohammed/mm-slub-move-sysfs-slab-alloc-free-interfaces-to-debugfs/20210608-093347 git checkout bc5e268c4852dc56a0d1c7a8ded8557db36b871b # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 If you fix the issue, kindly add following tag as appropriateReported-by: kernel test robot <lkp@intel.com>All errors (new ones prefixed by >>):>> mm/slub.c:5868:24: error: use of undeclared identifier 'seq' struct loc_track *t = seq->private; ^ 1 error generated.vim +/seq +5868 mm/slub.c 5865 5866static int slab_debug_trace_release(struct inode *inode, struct file *file) 5867{> 5868struct loc_track *t = seq->private; 5869 5870free_loc_track(t); 5871return seq_release_private(inode, file); 5872} 5873---0-DAY CI Kernel Test Service, Intel Corporationhttps://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series
Patch
diff --git a/mm/slab.h b/mm/slab.hindex 18c1927..60d4f4b 100644--- a/mm/slab.h+++ b/mm/slab.h@@ -630,6 +630,12 @@ static inline bool slab_want_init_on_free(struct kmem_cache *c) return false; } +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_SLUB_DEBUG)+void debugfs_slab_release(struct kmem_cache *);+#else+static inline void debugfs_slab_release(struct kmem_cache *s) { }+#endif+ #ifdef CONFIG_PRINTK #define KS_ADDRS_COUNT 16 struct kmem_obj_info {diff --git a/mm/slab_common.c b/mm/slab_common.cindex a4a5714..ee5456f 100644--- a/mm/slab_common.c+++ b/mm/slab_common.c@@ -449,6 +449,7 @@ static void slab_caches_to_rcu_destroy_workfn(struct work_struct *work) rcu_barrier(); list_for_each_entry_safe(s, s2, &to_destroy, list) {+debugfs_slab_release(s); kfence_shutdown_cache(s); #ifdef SLAB_SUPPORTS_SYSFS sysfs_slab_release(s);@@ -476,6 +477,7 @@ static int shutdown_cache(struct kmem_cache *s) schedule_work(&slab_caches_to_rcu_destroy_work); } else { kfence_shutdown_cache(s);+debugfs_slab_release(s); #ifdef SLAB_SUPPORTS_SYSFS sysfs_slab_unlink(s); sysfs_slab_release(s);diff --git a/mm/slub.c b/mm/slub.cindex 3f96e09..09f93ce 100644--- a/mm/slub.c+++ b/mm/slub.c@@ -36,6 +36,7 @@ #include <linux/memcontrol.h> #include <linux/random.h> +#include <linux/debugfs.h> #include <trace/events/kmem.h> #include "internal.h"@@ -225,6 +226,12 @@ static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p) { return 0; } #endif +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_SLUB_DEBUG)+static void debugfs_slab_add(struct kmem_cache *);+#else+static inline void debugfs_slab_add(struct kmem_cache *s) { }+#endif+ static inline void stat(const struct kmem_cache *s, enum stat_item si) { #ifdef CONFIG_SLUB_STATS@@ -4546,6 +4553,9 @@ int __kmem_cache_create(struct kmem_cache *s, slab_flags_t flags) if (err) __kmem_cache_release(s); +if (s->flags & SLAB_STORE_USER)+debugfs_slab_add(s);+ return err; } @@ -4686,6 +4696,8 @@ static long validate_slab_cache(struct kmem_cache *s) return count; }++#ifdef CONFIG_DEBUG_FS /* * Generate lists of code addresses where slabcache objects are allocated * and freed.@@ -4709,6 +4721,8 @@ struct loc_track { struct location *loc; }; +static struct dentry *slab_debugfs_root;+ static void free_loc_track(struct loc_track *t) { if (t->max)@@ -4825,82 +4839,7 @@ static void process_slab(struct loc_track *t, struct kmem_cache *s, add_location(t, s, get_track(s, p, alloc)); put_map(map); }--static int list_locations(struct kmem_cache *s, char *buf,- enum track_item alloc)-{-int len = 0;-unsigned long i;-struct loc_track t = { 0, 0, NULL };-int node;-struct kmem_cache_node *n;--if (!alloc_loc_track(&t, PAGE_SIZE / sizeof(struct location),- GFP_KERNEL)) {-return sysfs_emit(buf, "Out of memory\n");-}-/* 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, slab_list)-process_slab(&t, s, page, alloc);-list_for_each_entry(page, &n->full, slab_list)-process_slab(&t, s, page, alloc);-spin_unlock_irqrestore(&n->list_lock, flags);-}--for (i = 0; i < t.count; i++) {-struct location *l = &t.loc[i];--len += sysfs_emit_at(buf, len, "%7ld ", l->count);--if (l->addr)-len += sysfs_emit_at(buf, len, "%pS", (void *)l->addr);-else-len += sysfs_emit_at(buf, len, "<not-available>");--if (l->sum_time != l->min_time)-len += sysfs_emit_at(buf, len, " age=%ld/%ld/%ld",- l->min_time,- (long)div_u64(l->sum_time,- l->count),- l->max_time);-else-len += sysfs_emit_at(buf, len, " age=%ld", l->min_time);--if (l->min_pid != l->max_pid)-len += sysfs_emit_at(buf, len, " pid=%ld-%ld",- l->min_pid, l->max_pid);-else-len += sysfs_emit_at(buf, len, " pid=%ld",- l->min_pid);--if (num_online_cpus() > 1 &&- !cpumask_empty(to_cpumask(l->cpus)))-len += sysfs_emit_at(buf, len, " cpus=%*pbl",- cpumask_pr_args(to_cpumask(l->cpus)));--if (nr_online_nodes > 1 && !nodes_empty(l->nodes))-len += sysfs_emit_at(buf, len, " nodes=%*pbl",- nodemask_pr_args(&l->nodes));--len += sysfs_emit_at(buf, len, "\n");-}--free_loc_track(&t);-if (!t.count)-len += sysfs_emit_at(buf, len, "No data\n");--return len;-}+#endif /* CONFIG_DEBUG_FS */ #endif/* CONFIG_SLUB_DEBUG */ #ifdef SLUB_RESILIENCY_TEST@@ -5350,21 +5289,6 @@ static ssize_t validate_store(struct kmem_cache *s, } SLAB_ATTR(validate); -static ssize_t alloc_calls_show(struct kmem_cache *s, char *buf)-{-if (!(s->flags & SLAB_STORE_USER))-return -ENOSYS;-return list_locations(s, buf, TRACK_ALLOC);-}-SLAB_ATTR_RO(alloc_calls);--static ssize_t free_calls_show(struct kmem_cache *s, char *buf)-{-if (!(s->flags & SLAB_STORE_USER))-return -ENOSYS;-return list_locations(s, buf, TRACK_FREE);-}-SLAB_ATTR_RO(free_calls); #endif /* CONFIG_SLUB_DEBUG */ #ifdef CONFIG_FAILSLAB@@ -5528,8 +5452,6 @@ static struct attribute *slab_attrs[] = { &poison_attr.attr, &store_user_attr.attr, &validate_attr.attr,-&alloc_calls_attr.attr,-&free_calls_attr.attr, #endif #ifdef CONFIG_ZONE_DMA &cache_dma_attr.attr,@@ -5818,6 +5740,180 @@ static int __init slab_sysfs_init(void) __initcall(slab_sysfs_init); #endif /* CONFIG_SYSFS */ +#if defined(CONFIG_SLUB_DEBUG) && defined(CONFIG_DEBUG_FS)+static int slab_debugfs_show(struct seq_file *seq, void *v)+{++struct location *l;+unsigned int idx = *(unsigned int *)v;+struct loc_track *t = seq->private;++if (idx < t->count) {+l = &t->loc[idx];++seq_printf(seq, "%7ld ", l->count);++if (l->addr)+seq_printf(seq, "%pS", (void *)l->addr);+else+seq_puts(seq, "<not-available>");++if (l->sum_time != l->min_time) {+seq_printf(seq, " age=%ld/%llu/%ld",+l->min_time, div_u64(l->sum_time, l->count),+l->max_time);+} else+seq_printf(seq, " age=%ld", l->min_time);++if (l->min_pid != l->max_pid)+seq_printf(seq, " pid=%ld-%ld", l->min_pid, l->max_pid);+else+seq_printf(seq, " pid=%ld",+l->min_pid);++if (num_online_cpus() > 1 && !cpumask_empty(to_cpumask(l->cpus)))+seq_printf(seq, " cpus=%*pbl",+ cpumask_pr_args(to_cpumask(l->cpus)));++if (nr_online_nodes > 1 && !nodes_empty(l->nodes))+seq_printf(seq, " nodes=%*pbl",+ nodemask_pr_args(&l->nodes));++seq_puts(seq, "\n");+}++if (!idx && !t->count)+seq_puts(seq, "No data\n");++return 0;+}++static void slab_debugfs_stop(struct seq_file *seq, void *v)+{+kfree(v);+}++static void *slab_debugfs_next(struct seq_file *seq, void *v, loff_t *ppos)+{+loff_t *spos = v;+struct loc_track *t = seq->private;++if (*ppos < t->count) {+*ppos = ++*spos;+return spos;+}+*ppos = ++*spos;+return NULL;+}++static void *slab_debugfs_start(struct seq_file *seq, loff_t *ppos)+{+loff_t *spos = kmalloc(sizeof(loff_t), GFP_KERNEL);++if (!spos)+return NULL;++*spos = *ppos;+return spos;+}++static const struct seq_operations slab_debugfs_sops = {+.start = slab_debugfs_start,+.next = slab_debugfs_next,+.stop = slab_debugfs_stop,+.show = slab_debugfs_show,+};++static int slab_debug_trace_open(struct inode *inode, struct file *filep)+{++struct kmem_cache_node *n;+enum track_item alloc;+int node;+struct loc_track *t = __seq_open_private(filep, &slab_debugfs_sops,+sizeof(struct loc_track));+struct kmem_cache *s = file_inode(filep)->i_private;++if (strcmp(filep->f_path.dentry->d_name.name, "alloc_traces") == 0)+alloc = TRACK_ALLOC;+else+alloc = TRACK_FREE;++if (!alloc_loc_track(t, PAGE_SIZE / sizeof(struct location), GFP_KERNEL))+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, slab_list)+process_slab(t, s, page, alloc);+list_for_each_entry(page, &n->full, slab_list)+process_slab(t, s, page, alloc);+spin_unlock_irqrestore(&n->list_lock, flags);+}++return 0;+}++static int slab_debug_trace_release(struct inode *inode, struct file *file)+{+struct loc_track *t = seq->private;++free_loc_track(t);+return seq_release_private(inode, file);+}++static const struct file_operations slab_debugfs_fops = {+.open = slab_debug_trace_open,+.read = seq_read,+.llseek = seq_lseek,+.release = slab_debug_trace_release,+};++static void debugfs_slab_add(struct kmem_cache *s)+{+struct dentry *slab_cache_dir;++if (unlikely(!slab_debugfs_root))+return;++slab_cache_dir = debugfs_create_dir(s->name, slab_debugfs_root);++debugfs_create_file("alloc_traces", 0400,+slab_cache_dir, s, &slab_debugfs_fops);++debugfs_create_file("free_traces", 0400,+slab_cache_dir, s, &slab_debugfs_fops);+}++void debugfs_slab_release(struct kmem_cache *s)+{+debugfs_remove_recursive(debugfs_lookup(s->name, slab_debugfs_root));+}++static int __init slab_debugfs_init(void)+{+struct kmem_cache *s;++slab_debugfs_root = debugfs_create_dir("slab", NULL);++list_for_each_entry(s, &slab_caches, list)+if (s->flags & SLAB_STORE_USER)+debugfs_slab_add(s);++return 0;++}+__initcall(slab_debugfs_init);+#endif /* * The /proc/slabinfo ABI */