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

Commit 82202b6f authored by Isaac J. Manjarres's avatar Isaac J. Manjarres
Browse files

mm/memory_hotplug: Fix deadlock in try_online_one_block()



There is a possible scenario where the system can deadlock
itself when it is low on memory, and attempts to online
a memory block. Consider the following scenario:

 -A thread in userspace onlines a memory block through sysfs-
 state_store() /* Acquires the device_hotplug_lock */
 device_online()
 memory_subsys_online()
 memory_block_change_state()
 memory_block_action()
 online_pages()
 memory_notify(MEM_GOING_ONLINE, ...)
 online_page_ext()
 alloc_page_ext()
 __alloc_pages_nodemask(GFP_KERNEL, ...)
 /* System enters into a critically low memory state */
 out_of_memory()
 try_online_one_block() /* Invokes lock_device_hotplug() and deadlocks */

Fix deadlock by introducing and using trylock_device_hotplug()
instead of lock_device_hotplug().

Change-Id: I52bc8075ae713c50e3c381216f3616ce8366cf31
Signed-off-by: default avatarIsaac J. Manjarres <isaacm@codeaurora.org>
parent c322899f
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -1321,6 +1321,11 @@ int lock_device_hotplug_sysfs(void)
	return restart_syscall();
}

int trylock_device_hotplug(void)
{
	return mutex_trylock(&device_hotplug_lock);
}

#ifdef CONFIG_SCHED_WALT
void lock_device_hotplug_assert(void)
{
+1 −0
Original line number Diff line number Diff line
@@ -1592,6 +1592,7 @@ static inline bool device_supports_offline(struct device *dev)
extern void lock_device_hotplug(void);
extern void unlock_device_hotplug(void);
extern int lock_device_hotplug_sysfs(void);
extern int trylock_device_hotplug(void);
#ifdef CONFIG_SCHED_WALT
extern void lock_device_hotplug_assert(void);
#endif
+2 −1
Original line number Diff line number Diff line
@@ -1025,7 +1025,8 @@ bool try_online_one_block(int nid)
	unsigned long zone_start, zone_size;
	bool onlined_block = false;

	lock_device_hotplug();
	if (!trylock_device_hotplug())
		return false;

	zone_start = PFN_PHYS(zone->zone_start_pfn);
	zone_size = zone->spanned_pages << PAGE_SHIFT;