diff --git a/mm/slab.h b/mm/slab.h index f9977d6613d6..cf44a6cdbd9b 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -91,6 +91,24 @@ struct kmem_cache *kmalloc_slab(size_t, gfp_t); gfp_t kmalloc_fix_flags(gfp_t flags); +#ifdef CONFIG_SLUB +/* + * Tracking user of a slab. + */ +#define TRACK_ADDRS_COUNT 16 +struct track { + unsigned long addr; /* Called from address */ +#ifdef CONFIG_STACKTRACE + unsigned long addrs[TRACK_ADDRS_COUNT]; /* Called from address */ +#endif + int cpu; /* Was running on cpu */ + int pid; /* Pid context */ + unsigned long when; /* When did the operation occur */ +}; + +enum track_item { TRACK_ALLOC, TRACK_FREE }; +#endif + /* Functions provided by the slab allocators */ int __kmem_cache_create(struct kmem_cache *, slab_flags_t flags); @@ -217,10 +235,21 @@ DECLARE_STATIC_KEY_TRUE(slub_debug_enabled); DECLARE_STATIC_KEY_FALSE(slub_debug_enabled); #endif extern void print_tracking(struct kmem_cache *s, void *object); +extern unsigned long get_each_object_track(struct kmem_cache *s, + struct page *page, enum track_item alloc, + int (*fn)(const struct kmem_cache *, const void *, + const struct track *, void *), void *private); #else static inline void print_tracking(struct kmem_cache *s, void *object) { } +static inline unsigned long get_each_object_track(struct kmem_cache *s, + struct page *page, enum track_item alloc, + int (*fn)(const struct kmem_cache *, const void *, + const struct track *, void *), void *private) +{ + return 0; +} #endif /* diff --git a/mm/slub.c b/mm/slub.c index 23208b529014..e08e75f8b104 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -200,22 +200,6 @@ static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s) /* Use cmpxchg_double */ #define __CMPXCHG_DOUBLE ((slab_flags_t __force)0x40000000U) -/* - * Tracking user of a slab. - */ -#define TRACK_ADDRS_COUNT 16 -struct track { - unsigned long addr; /* Called from address */ -#ifdef CONFIG_STACKTRACE - unsigned long addrs[TRACK_ADDRS_COUNT]; /* Called from address */ -#endif - int cpu; /* Was running on cpu */ - int pid; /* Pid context */ - unsigned long when; /* When did the operation occur */ -}; - -enum track_item { TRACK_ALLOC, TRACK_FREE }; - #ifdef CONFIG_SYSFS static int sysfs_slab_add(struct kmem_cache *); static int sysfs_slab_alias(struct kmem_cache *, const char *); @@ -576,6 +560,39 @@ static struct track *get_track(struct kmem_cache *s, void *object, return kasan_reset_tag(p + alloc); } +/* + * This function will be used to loop through all the slab objects in + * a page to give track structure for each object, the function fn will + * be using this track structure and extract required info into its private + * data, the return value will be the number of track structures that are + * processed. + */ +unsigned long get_each_object_track(struct kmem_cache *s, + struct page *page, enum track_item alloc, + int (*fn)(const struct kmem_cache *, const void *, + const struct track *, void *), void *private) +{ + void *p; + struct track *t; + int ret; + unsigned long num_track = 0; + + if (!slub_debug || !(s->flags & SLAB_STORE_USER)) + return 0; + + slab_lock(page); + for_each_object(p, s, page_address(page), page->objects) { + t = get_track(s, p, alloc); + ret = fn(s, p, t, private); + if (ret < 0) + break; + num_track += 1; + } + slab_unlock(page); + return num_track; +} +EXPORT_SYMBOL_GPL(get_each_object_track); + static void set_track(struct kmem_cache *s, void *object, enum track_item alloc, unsigned long addr) {