UPSTREAM: mm, slub: allocate private object map for debugfs listings

Slub has a static spinlock protected bitmap for marking which objects are on
freelist when it wants to list them, for situations where dynamically
allocating such map can lead to recursion or locking issues, and on-stack
bitmap would be too large.

The handlers of debugfs files alloc_traces and free_traces also currently use this
shared bitmap, but their syscall context makes it straightforward to allocate a
private map before entering locked sections, so switch these processing paths
to use a private bitmap.

Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Acked-by: Christoph Lameter <cl@linux.com>
Acked-by: Mel Gorman <mgorman@techsingularity.net>

Bug: 209932470
(cherry picked from commit b3fd64e1451b5efd94aa0ebc755e02558e6f3ca1)
Change-Id: I5fbf34e0d828d1c8b5e81e3679f81b70ce1fc8bc
Signed-off-by: Yee Lee <yee.lee@mediatek.com>
This commit is contained in:
Vlastimil Babka 2021-05-23 01:28:37 +02:00 committed by Suren Baghdasaryan
parent 1260b47d4f
commit 791f85d16d

View File

@ -433,6 +433,18 @@ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
static unsigned long object_map[BITS_TO_LONGS(MAX_OBJS_PER_PAGE)];
static DEFINE_SPINLOCK(object_map_lock);
static void __fill_map(unsigned long *obj_map, struct kmem_cache *s,
struct page *page)
{
void *addr = page_address(page);
void *p;
bitmap_zero(obj_map, page->objects);
for (p = page->freelist; p; p = get_freepointer(s, p))
set_bit(__obj_to_index(s, addr, p), obj_map);
}
/*
* Determine a map of object in use on a page.
*
@ -442,17 +454,11 @@ static DEFINE_SPINLOCK(object_map_lock);
static unsigned long *get_map(struct kmem_cache *s, struct page *page)
__acquires(&object_map_lock)
{
void *p;
void *addr = page_address(page);
VM_BUG_ON(!irqs_disabled());
spin_lock(&object_map_lock);
bitmap_zero(object_map, page->objects);
for (p = page->freelist; p; p = get_freepointer(s, p))
set_bit(__obj_to_index(s, addr, p), object_map);
__fill_map(object_map, s, page);
return object_map;
}
@ -4778,17 +4784,17 @@ static int add_location(struct loc_track *t, struct kmem_cache *s,
}
static void process_slab(struct loc_track *t, struct kmem_cache *s,
struct page *page, enum track_item alloc)
struct page *page, enum track_item alloc,
unsigned long *obj_map)
{
void *addr = page_address(page);
void *p;
unsigned long *map;
map = get_map(s, page);
__fill_map(obj_map, s, page);
for_each_object(p, s, addr, page->objects)
if (!test_bit(__obj_to_index(s, addr, p), map))
if (!test_bit(__obj_to_index(s, addr, p), obj_map))
add_location(t, s, get_track(s, p, alloc));
put_map(map);
}
#endif /* CONFIG_DEBUG_FS */
#endif /* CONFIG_SLUB_DEBUG */
@ -5783,14 +5789,21 @@ static int slab_debug_trace_open(struct inode *inode, struct file *filep)
struct loc_track *t = __seq_open_private(filep, &slab_debugfs_sops,
sizeof(struct loc_track));
struct kmem_cache *s = file_inode(filep)->i_private;
unsigned long *obj_map;
obj_map = bitmap_alloc(oo_objects(s->oo), GFP_KERNEL);
if (!obj_map)
return -ENOMEM;
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))
if (!alloc_loc_track(t, PAGE_SIZE / sizeof(struct location), GFP_KERNEL)) {
bitmap_free(obj_map);
return -ENOMEM;
}
/* Push back cpu slabs */
flush_all(s);
@ -5804,12 +5817,13 @@ static int slab_debug_trace_open(struct inode *inode, struct file *filep)
spin_lock_irqsave(&n->list_lock, flags);
list_for_each_entry(page, &n->partial, slab_list)
process_slab(t, s, page, alloc);
process_slab(t, s, page, alloc, obj_map);
list_for_each_entry(page, &n->full, slab_list)
process_slab(t, s, page, alloc);
process_slab(t, s, page, alloc, obj_map);
spin_unlock_irqrestore(&n->list_lock, flags);
}
bitmap_free(obj_map);
return 0;
}