Commit 68f285e2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull slab fixes from Vlastimil Babka:

 - Stable fix to make slub_debug code not access invalid pointers in the
   process of reporting issues (Li Qiong)

 - Stable fix to make object tracking pass gfp flags to stackdepot to
   avoid deadlock in contexts that can't even wake up kswapd due to e.g.
   timers debugging enabled (yangshiguang)

* tag 'slab-for-6.17-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab:
  mm: slub: avoid wake up kswapd in set_track_prepare
  mm/slub: avoid accessing metadata when pointer is invalid in object_err()
parents 08b06c30 850470a8
Loading
Loading
Loading
Loading
+26 −11
Original line number Diff line number Diff line
@@ -962,19 +962,19 @@ static struct track *get_track(struct kmem_cache *s, void *object,
}

#ifdef CONFIG_STACKDEPOT
static noinline depot_stack_handle_t set_track_prepare(void)
static noinline depot_stack_handle_t set_track_prepare(gfp_t gfp_flags)
{
	depot_stack_handle_t handle;
	unsigned long entries[TRACK_ADDRS_COUNT];
	unsigned int nr_entries;

	nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 3);
	handle = stack_depot_save(entries, nr_entries, GFP_NOWAIT);
	handle = stack_depot_save(entries, nr_entries, gfp_flags);

	return handle;
}
#else
static inline depot_stack_handle_t set_track_prepare(void)
static inline depot_stack_handle_t set_track_prepare(gfp_t gfp_flags)
{
	return 0;
}
@@ -996,9 +996,9 @@ static void set_track_update(struct kmem_cache *s, void *object,
}

static __always_inline void set_track(struct kmem_cache *s, void *object,
				      enum track_item alloc, unsigned long addr)
				      enum track_item alloc, unsigned long addr, gfp_t gfp_flags)
{
	depot_stack_handle_t handle = set_track_prepare();
	depot_stack_handle_t handle = set_track_prepare(gfp_flags);

	set_track_update(s, object, alloc, addr, handle);
}
@@ -1140,7 +1140,12 @@ static void object_err(struct kmem_cache *s, struct slab *slab,
		return;

	slab_bug(s, reason);
	if (!object || !check_valid_pointer(s, slab, object)) {
		print_slab_info(slab);
		pr_err("Invalid pointer 0x%p\n", object);
	} else {
		print_trailer(s, slab, object);
	}
	add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);

	WARN_ON(1);
@@ -1921,9 +1926,9 @@ static inline bool free_debug_processing(struct kmem_cache *s,
static inline void slab_pad_check(struct kmem_cache *s, struct slab *slab) {}
static inline int check_object(struct kmem_cache *s, struct slab *slab,
			void *object, u8 val) { return 1; }
static inline depot_stack_handle_t set_track_prepare(void) { return 0; }
static inline depot_stack_handle_t set_track_prepare(gfp_t gfp_flags) { return 0; }
static inline void set_track(struct kmem_cache *s, void *object,
			     enum track_item alloc, unsigned long addr) {}
			     enum track_item alloc, unsigned long addr, gfp_t gfp_flags) {}
static inline void add_full(struct kmem_cache *s, struct kmem_cache_node *n,
					struct slab *slab) {}
static inline void remove_full(struct kmem_cache *s, struct kmem_cache_node *n,
@@ -3876,9 +3881,14 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
			 * For debug caches here we had to go through
			 * alloc_single_from_partial() so just store the
			 * tracking info and return the object.
			 *
			 * Due to disabled preemption we need to disallow
			 * blocking. The flags are further adjusted by
			 * gfp_nested_mask() in stack_depot itself.
			 */
			if (s->flags & SLAB_STORE_USER)
				set_track(s, freelist, TRACK_ALLOC, addr);
				set_track(s, freelist, TRACK_ALLOC, addr,
					  gfpflags & ~(__GFP_DIRECT_RECLAIM));

			return freelist;
		}
@@ -3910,7 +3920,8 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
			goto new_objects;

		if (s->flags & SLAB_STORE_USER)
			set_track(s, freelist, TRACK_ALLOC, addr);
			set_track(s, freelist, TRACK_ALLOC, addr,
				  gfpflags & ~(__GFP_DIRECT_RECLAIM));

		return freelist;
	}
@@ -4421,8 +4432,12 @@ static noinline void free_to_partial_list(
	unsigned long flags;
	depot_stack_handle_t handle = 0;

	/*
	 * We cannot use GFP_NOWAIT as there are callsites where waking up
	 * kswapd could deadlock
	 */
	if (s->flags & SLAB_STORE_USER)
		handle = set_track_prepare();
		handle = set_track_prepare(__GFP_NOWARN);

	spin_lock_irqsave(&n->list_lock, flags);