Merge android16-6.12 into android16-6.12-lts
This merges the android16-6.12 branch into the -lts branch, catching it up with the latest changes in there. Resolves merge conflicts in: kernel/sched/core.c It contains the following commits: *2bd1f36314ANDROID: gunyah: Add new VM status to handle reset failure *e740e8d9eaANDROID: Sync proxy-exec logic to v19 (from v18) *7d6f7afb0dUPSTREAM: perf/core: Clean up perf_try_init_event() *3f5de81785ANDROID: GKI: Update xiaomi symbol list. *5d3d6f75d5BACKPORT: hung_task: show the blocker task if the task is hung on mutex *6b4fffd5b2FROMGIT: pinmux: fix race causing mux_owner NULL with active mux_usecount *9f514cf3d9ANDROID: GKI: add GKI symbol list for Exynosauto SoC Change-Id: I26e0399d7c0a55ff40ea1e915b41ce8320bff30b Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -236,6 +236,15 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin,
|
|||||||
if (desc->mux_usecount)
|
if (desc->mux_usecount)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gpio_range) {
|
||||||
|
owner = desc->gpio_owner;
|
||||||
|
desc->gpio_owner = NULL;
|
||||||
|
} else {
|
||||||
|
owner = desc->mux_owner;
|
||||||
|
desc->mux_owner = NULL;
|
||||||
|
desc->mux_setting = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -247,17 +256,6 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin,
|
|||||||
else if (ops->free)
|
else if (ops->free)
|
||||||
ops->free(pctldev, pin);
|
ops->free(pctldev, pin);
|
||||||
|
|
||||||
scoped_guard(mutex, &desc->mux_lock) {
|
|
||||||
if (gpio_range) {
|
|
||||||
owner = desc->gpio_owner;
|
|
||||||
desc->gpio_owner = NULL;
|
|
||||||
} else {
|
|
||||||
owner = desc->mux_owner;
|
|
||||||
desc->mux_owner = NULL;
|
|
||||||
desc->mux_setting = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module_put(pctldev->owner);
|
module_put(pctldev->owner);
|
||||||
|
|
||||||
return owner;
|
return owner;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <linux/gunyah.h>
|
#include <linux/gunyah.h>
|
||||||
#include <linux/notifier.h>
|
#include <linux/notifier.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <linux/android_kabi.h>
|
||||||
|
|
||||||
#define GUNYAH_VMID_INVAL U16_MAX
|
#define GUNYAH_VMID_INVAL U16_MAX
|
||||||
#define GUNYAH_MEM_HANDLE_INVAL U32_MAX
|
#define GUNYAH_MEM_HANDLE_INVAL U32_MAX
|
||||||
@@ -48,8 +49,10 @@ enum gunyah_rm_vm_status {
|
|||||||
GUNYAH_RM_VM_STATUS_EXITED = 9,
|
GUNYAH_RM_VM_STATUS_EXITED = 9,
|
||||||
GUNYAH_RM_VM_STATUS_RESETTING = 10,
|
GUNYAH_RM_VM_STATUS_RESETTING = 10,
|
||||||
GUNYAH_RM_VM_STATUS_RESET = 11,
|
GUNYAH_RM_VM_STATUS_RESET = 11,
|
||||||
|
GUNYAH_RM_VM_STATUS_RESET_FAILED = 12,
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
};
|
};
|
||||||
|
ANDROID_KABI_ENUMERATOR_IGNORE(gunyah_rm_vm_status, GUNYAH_RM_VM_STATUS_RESET_FAILED);
|
||||||
|
|
||||||
struct gunyah_rm_vm_status_payload {
|
struct gunyah_rm_vm_status_payload {
|
||||||
__le16 vmid;
|
__le16 vmid;
|
||||||
|
|||||||
@@ -583,11 +583,19 @@ static int gunyah_vm_rm_notification_status(struct gunyah_vm *ghvm, void *data)
|
|||||||
return NOTIFY_OK;
|
return NOTIFY_OK;
|
||||||
|
|
||||||
/* All other state transitions are synchronous to a corresponding RM call */
|
/* All other state transitions are synchronous to a corresponding RM call */
|
||||||
if (payload->vm_status == GUNYAH_RM_VM_STATUS_RESET) {
|
switch (payload->vm_status) {
|
||||||
|
case GUNYAH_RM_VM_STATUS_RESET_FAILED:
|
||||||
|
dev_warn(ghvm->parent, "VM: %u RESET failed with status %u\n",
|
||||||
|
ghvm->vmid, payload->vm_status);
|
||||||
|
fallthrough;
|
||||||
|
case GUNYAH_RM_VM_STATUS_RESET:
|
||||||
down_write(&ghvm->status_lock);
|
down_write(&ghvm->status_lock);
|
||||||
ghvm->vm_status = payload->vm_status;
|
ghvm->vm_status = payload->vm_status;
|
||||||
up_write(&ghvm->status_lock);
|
up_write(&ghvm->status_lock);
|
||||||
wake_up(&ghvm->vm_status_wait);
|
wake_up(&ghvm->vm_status_wait);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
@@ -1147,7 +1155,8 @@ static void _gunyah_vm_put(struct kref *kref)
|
|||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
if (!ret)
|
if (!ret)
|
||||||
wait_event(ghvm->vm_status_wait,
|
wait_event(ghvm->vm_status_wait,
|
||||||
ghvm->vm_status == GUNYAH_RM_VM_STATUS_RESET);
|
(ghvm->vm_status == GUNYAH_RM_VM_STATUS_RESET) ||
|
||||||
|
(ghvm->vm_status == GUNYAH_RM_VM_STATUS_RESET_FAILED));
|
||||||
else
|
else
|
||||||
dev_err(ghvm->parent, "Failed to reset the vm: %d\n", ret);
|
dev_err(ghvm->parent, "Failed to reset the vm: %d\n", ret);
|
||||||
|
|
||||||
|
|||||||
@@ -357070,6 +357070,10 @@ enumeration {
|
|||||||
name: "GUNYAH_RM_VM_STATUS_RESET"
|
name: "GUNYAH_RM_VM_STATUS_RESET"
|
||||||
value: 11
|
value: 11
|
||||||
}
|
}
|
||||||
|
enumerator {
|
||||||
|
name: "GUNYAH_RM_VM_STATUS_RESET_FAILED"
|
||||||
|
value: 12
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enumeration {
|
enumeration {
|
||||||
@@ -378677,6 +378681,14 @@ function {
|
|||||||
parameter_id: 0x1ad7b8dd
|
parameter_id: 0x1ad7b8dd
|
||||||
parameter_id: 0x01222f7d
|
parameter_id: 0x01222f7d
|
||||||
}
|
}
|
||||||
|
function {
|
||||||
|
id: 0x1782373c
|
||||||
|
return_type_id: 0x48b5725f
|
||||||
|
parameter_id: 0x17a37c1c
|
||||||
|
parameter_id: 0xbdd18903
|
||||||
|
parameter_id: 0x18bd6530
|
||||||
|
parameter_id: 0xf435685e
|
||||||
|
}
|
||||||
function {
|
function {
|
||||||
id: 0x1784717f
|
id: 0x1784717f
|
||||||
return_type_id: 0x48b5725f
|
return_type_id: 0x48b5725f
|
||||||
@@ -388582,6 +388594,13 @@ function {
|
|||||||
return_type_id: 0x18bd6530
|
return_type_id: 0x18bd6530
|
||||||
parameter_id: 0x140c6eab
|
parameter_id: 0x140c6eab
|
||||||
}
|
}
|
||||||
|
function {
|
||||||
|
id: 0x53d4f2c3
|
||||||
|
return_type_id: 0x18bd6530
|
||||||
|
parameter_id: 0x17a37c1c
|
||||||
|
parameter_id: 0x25e45be7
|
||||||
|
parameter_id: 0xf435685e
|
||||||
|
}
|
||||||
function {
|
function {
|
||||||
id: 0x53d7cb1d
|
id: 0x53d7cb1d
|
||||||
return_type_id: 0x0930c6d9
|
return_type_id: 0x0930c6d9
|
||||||
@@ -480448,6 +480467,42 @@ elf_symbol {
|
|||||||
type_id: 0x15708e94
|
type_id: 0x15708e94
|
||||||
full_name: "pci_epc_init_notify"
|
full_name: "pci_epc_init_notify"
|
||||||
}
|
}
|
||||||
|
elf_symbol {
|
||||||
|
id: 0xb862467e
|
||||||
|
name: "pci_epc_mem_alloc_addr"
|
||||||
|
is_defined: true
|
||||||
|
symbol_type: FUNCTION
|
||||||
|
crc: 0xb9fa0d06
|
||||||
|
type_id: 0x53d4f2c3
|
||||||
|
full_name: "pci_epc_mem_alloc_addr"
|
||||||
|
}
|
||||||
|
elf_symbol {
|
||||||
|
id: 0xffb38889
|
||||||
|
name: "pci_epc_mem_free_addr"
|
||||||
|
is_defined: true
|
||||||
|
symbol_type: FUNCTION
|
||||||
|
crc: 0x0f81c98a
|
||||||
|
type_id: 0x1782373c
|
||||||
|
full_name: "pci_epc_mem_free_addr"
|
||||||
|
}
|
||||||
|
elf_symbol {
|
||||||
|
id: 0x8a8d0c1a
|
||||||
|
name: "pci_epc_set_bar"
|
||||||
|
is_defined: true
|
||||||
|
symbol_type: FUNCTION
|
||||||
|
crc: 0x7dc4416e
|
||||||
|
type_id: 0x98c78004
|
||||||
|
full_name: "pci_epc_set_bar"
|
||||||
|
}
|
||||||
|
elf_symbol {
|
||||||
|
id: 0xb7b28cad
|
||||||
|
name: "pci_epc_unmap_addr"
|
||||||
|
is_defined: true
|
||||||
|
symbol_type: FUNCTION
|
||||||
|
crc: 0xba4a789a
|
||||||
|
type_id: 0x15dd5f06
|
||||||
|
full_name: "pci_epc_unmap_addr"
|
||||||
|
}
|
||||||
elf_symbol {
|
elf_symbol {
|
||||||
id: 0x3852868c
|
id: 0x3852868c
|
||||||
name: "pci_find_bus"
|
name: "pci_find_bus"
|
||||||
@@ -480628,6 +480683,15 @@ elf_symbol {
|
|||||||
type_id: 0x5373932e
|
type_id: 0x5373932e
|
||||||
full_name: "pci_ioremap_bar"
|
full_name: "pci_ioremap_bar"
|
||||||
}
|
}
|
||||||
|
elf_symbol {
|
||||||
|
id: 0x231d5ec9
|
||||||
|
name: "pci_ioremap_wc_bar"
|
||||||
|
is_defined: true
|
||||||
|
symbol_type: FUNCTION
|
||||||
|
crc: 0x45d79d6f
|
||||||
|
type_id: 0x5373932e
|
||||||
|
full_name: "pci_ioremap_wc_bar"
|
||||||
|
}
|
||||||
elf_symbol {
|
elf_symbol {
|
||||||
id: 0xec861eec
|
id: 0xec861eec
|
||||||
name: "pci_iounmap"
|
name: "pci_iounmap"
|
||||||
@@ -480745,6 +480809,15 @@ elf_symbol {
|
|||||||
type_id: 0x99f942bc
|
type_id: 0x99f942bc
|
||||||
full_name: "pci_msix_vec_count"
|
full_name: "pci_msix_vec_count"
|
||||||
}
|
}
|
||||||
|
elf_symbol {
|
||||||
|
id: 0x2f7fc8d4
|
||||||
|
name: "pci_num_vf"
|
||||||
|
is_defined: true
|
||||||
|
symbol_type: FUNCTION
|
||||||
|
crc: 0x94842ef3
|
||||||
|
type_id: 0x99f942bc
|
||||||
|
full_name: "pci_num_vf"
|
||||||
|
}
|
||||||
elf_symbol {
|
elf_symbol {
|
||||||
id: 0x180e6903
|
id: 0x180e6903
|
||||||
name: "pci_pio_to_address"
|
name: "pci_pio_to_address"
|
||||||
@@ -514188,6 +514261,10 @@ interface {
|
|||||||
symbol_id: 0xc80fa4a7
|
symbol_id: 0xc80fa4a7
|
||||||
symbol_id: 0x39db373c
|
symbol_id: 0x39db373c
|
||||||
symbol_id: 0x9df0dd4c
|
symbol_id: 0x9df0dd4c
|
||||||
|
symbol_id: 0xb862467e
|
||||||
|
symbol_id: 0xffb38889
|
||||||
|
symbol_id: 0x8a8d0c1a
|
||||||
|
symbol_id: 0xb7b28cad
|
||||||
symbol_id: 0x3852868c
|
symbol_id: 0x3852868c
|
||||||
symbol_id: 0x27f20808
|
symbol_id: 0x27f20808
|
||||||
symbol_id: 0x63876663
|
symbol_id: 0x63876663
|
||||||
@@ -514208,6 +514285,7 @@ interface {
|
|||||||
symbol_id: 0x9c6c58ea
|
symbol_id: 0x9c6c58ea
|
||||||
symbol_id: 0x2fefe933
|
symbol_id: 0x2fefe933
|
||||||
symbol_id: 0x1c994923
|
symbol_id: 0x1c994923
|
||||||
|
symbol_id: 0x231d5ec9
|
||||||
symbol_id: 0xec861eec
|
symbol_id: 0xec861eec
|
||||||
symbol_id: 0x1279792b
|
symbol_id: 0x1279792b
|
||||||
symbol_id: 0x5810bdc3
|
symbol_id: 0x5810bdc3
|
||||||
@@ -514221,6 +514299,7 @@ interface {
|
|||||||
symbol_id: 0x9a271493
|
symbol_id: 0x9a271493
|
||||||
symbol_id: 0xcb617d2b
|
symbol_id: 0xcb617d2b
|
||||||
symbol_id: 0x9d3ae050
|
symbol_id: 0x9d3ae050
|
||||||
|
symbol_id: 0x2f7fc8d4
|
||||||
symbol_id: 0x180e6903
|
symbol_id: 0x180e6903
|
||||||
symbol_id: 0xf32782d8
|
symbol_id: 0xf32782d8
|
||||||
symbol_id: 0x258080ab
|
symbol_id: 0x258080ab
|
||||||
|
|||||||
@@ -10,3 +10,6 @@ type 'struct sched_dl_entity' changed
|
|||||||
type 'struct f2fs_sb_info' changed
|
type 'struct f2fs_sb_info' changed
|
||||||
member 'union { unsigned int reserved_pin_section; unsigned char __kabi_ignored0; }' was added
|
member 'union { unsigned int reserved_pin_section; unsigned char __kabi_ignored0; }' was added
|
||||||
|
|
||||||
|
type 'enum gunyah_rm_vm_status' changed
|
||||||
|
enumerator 'GUNYAH_RM_VM_STATUS_RESET_FAILED' (12) was added
|
||||||
|
|
||||||
|
|||||||
+465
-395
File diff suppressed because it is too large
Load Diff
@@ -112,6 +112,8 @@
|
|||||||
__tracepoint_android_vh_alloc_pages_entry
|
__tracepoint_android_vh_alloc_pages_entry
|
||||||
__traceiter_android_vh_sysrq_crash
|
__traceiter_android_vh_sysrq_crash
|
||||||
__tracepoint_android_vh_sysrq_crash
|
__tracepoint_android_vh_sysrq_crash
|
||||||
|
__traceiter_android_rvh_schedule_bug
|
||||||
|
__tracepoint_android_rvh_schedule_bug
|
||||||
|
|
||||||
#required by metis.ko module
|
#required by metis.ko module
|
||||||
__traceiter_android_vh_rwsem_read_wait_start
|
__traceiter_android_vh_rwsem_read_wait_start
|
||||||
|
|||||||
@@ -202,4 +202,6 @@ DEFINE_GUARD(mutex, struct mutex *, mutex_lock(_T), mutex_unlock(_T))
|
|||||||
DEFINE_GUARD_COND(mutex, _try, mutex_trylock(_T))
|
DEFINE_GUARD_COND(mutex, _try, mutex_trylock(_T))
|
||||||
DEFINE_GUARD_COND(mutex, _intr, mutex_lock_interruptible(_T) == 0)
|
DEFINE_GUARD_COND(mutex, _intr, mutex_lock_interruptible(_T) == 0)
|
||||||
|
|
||||||
|
extern unsigned long mutex_get_owner(struct mutex *lock);
|
||||||
|
|
||||||
#endif /* __LINUX_MUTEX_H */
|
#endif /* __LINUX_MUTEX_H */
|
||||||
|
|||||||
+27
-6
@@ -1271,6 +1271,10 @@ struct task_struct {
|
|||||||
#endif
|
#endif
|
||||||
raw_spinlock_t blocked_lock;
|
raw_spinlock_t blocked_lock;
|
||||||
|
|
||||||
|
#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
|
||||||
|
struct mutex *blocker_mutex;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
|
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
|
||||||
int non_block_count;
|
int non_block_count;
|
||||||
#endif
|
#endif
|
||||||
@@ -2235,6 +2239,29 @@ static inline void __set_blocked_on_waking(struct task_struct *p)
|
|||||||
p->blocked_on_state = BO_WAKING;
|
p->blocked_on_state = BO_WAKING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct mutex *__get_task_blocked_on(struct task_struct *p)
|
||||||
|
{
|
||||||
|
lockdep_assert_held_once(&p->blocked_lock);
|
||||||
|
return p->blocked_on;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_PREEMPT_RT
|
||||||
|
static inline void set_blocked_on_waking_nested(struct task_struct *p, struct mutex *m)
|
||||||
|
{
|
||||||
|
raw_spin_lock_nested(&p->blocked_lock, SINGLE_DEPTH_NESTING);
|
||||||
|
WARN_ON_ONCE(__get_task_blocked_on(p) != m);
|
||||||
|
__set_blocked_on_waking(p);
|
||||||
|
raw_spin_unlock(&p->blocked_lock);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline void set_blocked_on_waking_nested(struct task_struct *p, struct rt_mutex *m)
|
||||||
|
{
|
||||||
|
raw_spin_lock_nested(&p->blocked_lock, SINGLE_DEPTH_NESTING);
|
||||||
|
__set_blocked_on_waking(p);
|
||||||
|
raw_spin_unlock(&p->blocked_lock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline void __set_task_blocked_on(struct task_struct *p, struct mutex *m)
|
static inline void __set_task_blocked_on(struct task_struct *p, struct mutex *m)
|
||||||
{
|
{
|
||||||
WARN_ON_ONCE(!m);
|
WARN_ON_ONCE(!m);
|
||||||
@@ -2263,12 +2290,6 @@ static inline void __clear_task_blocked_on(struct task_struct *p, struct mutex *
|
|||||||
p->blocked_on_state = BO_RUNNABLE;
|
p->blocked_on_state = BO_RUNNABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct mutex *__get_task_blocked_on(struct task_struct *p)
|
|
||||||
{
|
|
||||||
lockdep_assert_held_once(&p->blocked_lock);
|
|
||||||
return p->blocked_on;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __always_inline bool need_resched(void)
|
static __always_inline bool need_resched(void)
|
||||||
{
|
{
|
||||||
return unlikely(tif_need_resched());
|
return unlikely(tif_need_resched());
|
||||||
|
|||||||
@@ -89,6 +89,43 @@ static struct notifier_block panic_block = {
|
|||||||
.notifier_call = hung_task_panic,
|
.notifier_call = hung_task_panic,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
|
||||||
|
static void debug_show_blocker(struct task_struct *task)
|
||||||
|
{
|
||||||
|
struct task_struct *g, *t;
|
||||||
|
unsigned long owner;
|
||||||
|
struct mutex *lock;
|
||||||
|
|
||||||
|
RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "No rcu lock held");
|
||||||
|
|
||||||
|
lock = READ_ONCE(task->blocker_mutex);
|
||||||
|
if (!lock)
|
||||||
|
return;
|
||||||
|
|
||||||
|
owner = mutex_get_owner(lock);
|
||||||
|
if (unlikely(!owner)) {
|
||||||
|
pr_err("INFO: task %s:%d is blocked on a mutex, but the owner is not found.\n",
|
||||||
|
task->comm, task->pid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure the owner information is correct. */
|
||||||
|
for_each_process_thread(g, t) {
|
||||||
|
if ((unsigned long)t == owner) {
|
||||||
|
pr_err("INFO: task %s:%d is blocked on a mutex likely owned by task %s:%d.\n",
|
||||||
|
task->comm, task->pid, t->comm, t->pid);
|
||||||
|
sched_show_task(t);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline void debug_show_blocker(struct task_struct *task)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void check_hung_task(struct task_struct *t, unsigned long timeout)
|
static void check_hung_task(struct task_struct *t, unsigned long timeout)
|
||||||
{
|
{
|
||||||
unsigned long switch_count = t->nvcsw + t->nivcsw;
|
unsigned long switch_count = t->nvcsw + t->nivcsw;
|
||||||
@@ -140,6 +177,7 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout)
|
|||||||
pr_err("\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\""
|
pr_err("\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\""
|
||||||
" disables this message.\n");
|
" disables this message.\n");
|
||||||
sched_show_task(t);
|
sched_show_task(t);
|
||||||
|
debug_show_blocker(t);
|
||||||
hung_task_show_lock = true;
|
hung_task_show_lock = true;
|
||||||
|
|
||||||
if (sysctl_hung_task_all_cpu_backtrace)
|
if (sysctl_hung_task_all_cpu_backtrace)
|
||||||
|
|||||||
@@ -76,6 +76,14 @@ static inline unsigned long __owner_flags(unsigned long owner)
|
|||||||
return owner & MUTEX_FLAGS;
|
return owner & MUTEX_FLAGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Do not use the return value as a pointer directly. */
|
||||||
|
unsigned long mutex_get_owner(struct mutex *lock)
|
||||||
|
{
|
||||||
|
unsigned long owner = atomic_long_read(&lock->owner);
|
||||||
|
|
||||||
|
return (unsigned long)__owner_task(owner);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns: __mutex_owner(lock) on failure or NULL on success.
|
* Returns: __mutex_owner(lock) on failure or NULL on success.
|
||||||
*/
|
*/
|
||||||
@@ -187,6 +195,10 @@ __mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter,
|
|||||||
struct list_head *list)
|
struct list_head *list)
|
||||||
{
|
{
|
||||||
bool already_on_list = false;
|
bool already_on_list = false;
|
||||||
|
|
||||||
|
#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
|
||||||
|
WRITE_ONCE(current->blocker_mutex, lock);
|
||||||
|
#endif
|
||||||
debug_mutex_add_waiter(lock, waiter, current);
|
debug_mutex_add_waiter(lock, waiter, current);
|
||||||
|
|
||||||
trace_android_vh_alter_mutex_list_add(lock, waiter, list, &already_on_list);
|
trace_android_vh_alter_mutex_list_add(lock, waiter, list, &already_on_list);
|
||||||
@@ -204,6 +216,9 @@ __mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter)
|
|||||||
__mutex_clear_flag(lock, MUTEX_FLAGS);
|
__mutex_clear_flag(lock, MUTEX_FLAGS);
|
||||||
|
|
||||||
debug_mutex_remove_waiter(lock, waiter, current);
|
debug_mutex_remove_waiter(lock, waiter, current);
|
||||||
|
#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
|
||||||
|
WRITE_ONCE(current->blocker_mutex, NULL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -284,16 +284,13 @@ __ww_mutex_die(struct MUTEX *lock, struct MUTEX_WAITER *waiter,
|
|||||||
#ifndef WW_RT
|
#ifndef WW_RT
|
||||||
debug_mutex_wake_waiter(lock, waiter);
|
debug_mutex_wake_waiter(lock, waiter);
|
||||||
#endif
|
#endif
|
||||||
/* nested as we should hold current->blocked_lock already */
|
|
||||||
raw_spin_lock_nested(&waiter->task->blocked_lock, SINGLE_DEPTH_NESTING);
|
|
||||||
/*
|
/*
|
||||||
* When waking up the task to die, be sure to set the
|
* When waking up the task to die, be sure to set the
|
||||||
* blocked_on_state to BO_WAKING. Otherwise we can see
|
* blocked_on_state to BO_WAKING. Otherwise we can see
|
||||||
* circular blocked_on relationships that can't resolve.
|
* circular blocked_on relationships that can't resolve.
|
||||||
*/
|
*/
|
||||||
WARN_ON_ONCE(__get_task_blocked_on(waiter->task) != lock);
|
/* nested as we should hold current->blocked_lock already */
|
||||||
__set_blocked_on_waking(waiter->task);
|
set_blocked_on_waking_nested(waiter->task, lock);
|
||||||
raw_spin_unlock(&waiter->task->blocked_lock);
|
|
||||||
wake_q_add(wake_q, waiter->task);
|
wake_q_add(wake_q, waiter->task);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,15 +339,12 @@ static bool __ww_mutex_wound(struct MUTEX *lock,
|
|||||||
* wakeup pending to re-read the wounded state.
|
* wakeup pending to re-read the wounded state.
|
||||||
*/
|
*/
|
||||||
if (owner != current) {
|
if (owner != current) {
|
||||||
/* nested as we should hold current->blocked_lock already */
|
|
||||||
raw_spin_lock_nested(&owner->blocked_lock, SINGLE_DEPTH_NESTING);
|
|
||||||
/*
|
/*
|
||||||
* When waking up the task to wound, be sure to set the
|
* When waking up the task to wound, be sure to set the
|
||||||
* blocked_on_state to BO_WAKING. Otherwise we can see
|
* blocked_on_state to BO_WAKING. Otherwise we can see
|
||||||
* circular blocked_on relationships that can't resolve.
|
* circular blocked_on relationships that can't resolve.
|
||||||
*/
|
*/
|
||||||
__set_blocked_on_waking(owner);
|
set_blocked_on_waking_nested(owner, lock);
|
||||||
raw_spin_unlock(&owner->blocked_lock);
|
|
||||||
wake_q_add(wake_q, owner);
|
wake_q_add(wake_q, owner);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+23
-8
@@ -5588,7 +5588,7 @@ static void zap_balance_callbacks(struct rq *rq)
|
|||||||
}
|
}
|
||||||
rq->balance_callback = found ? &balance_push_callback : NULL;
|
rq->balance_callback = found ? &balance_push_callback : NULL;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SCHED_PROXY_EXEC */
|
#endif
|
||||||
|
|
||||||
static void balance_push(struct rq *rq);
|
static void balance_push(struct rq *rq);
|
||||||
|
|
||||||
@@ -5658,11 +5658,9 @@ void balance_callbacks(struct rq *rq, struct balance_callback *head)
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#ifdef CONFIG_SCHED_PROXY_EXEC
|
|
||||||
static inline void zap_balance_callbacks(struct rq *rq)
|
static inline void zap_balance_callbacks(struct rq *rq)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SCHED_PROXY_EXEC */
|
|
||||||
|
|
||||||
static inline void __balance_callbacks(struct rq *rq)
|
static inline void __balance_callbacks(struct rq *rq)
|
||||||
{
|
{
|
||||||
@@ -7143,11 +7141,13 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
|
|||||||
/*
|
/*
|
||||||
* Helper function for __schedule()
|
* Helper function for __schedule()
|
||||||
*
|
*
|
||||||
* If a task does not have signals pending, deactivate it
|
* Tries to deactivate the task, unless the should_block arg
|
||||||
* Otherwise marks the task's __state as RUNNING
|
* is false or if a signal is pending. In the case a signal
|
||||||
|
* is pending, marks the task's __state as RUNNING (and clear
|
||||||
|
* blocked_on).
|
||||||
*/
|
*/
|
||||||
static bool try_to_block_task(struct rq *rq, struct task_struct *p,
|
static bool try_to_block_task(struct rq *rq, struct task_struct *p,
|
||||||
unsigned long *task_state_p, bool deactivate_cond)
|
unsigned long *task_state_p, bool should_block)
|
||||||
{
|
{
|
||||||
unsigned long task_state = *task_state_p;
|
unsigned long task_state = *task_state_p;
|
||||||
int flags = DEQUEUE_NOCLOCK;
|
int flags = DEQUEUE_NOCLOCK;
|
||||||
@@ -7158,7 +7158,14 @@ static bool try_to_block_task(struct rq *rq, struct task_struct *p,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deactivate_cond)
|
/*
|
||||||
|
* We check should_block after signal_pending because we
|
||||||
|
* will want to wake the task in that case. But if
|
||||||
|
* should_block is false, its likely due to the task being
|
||||||
|
* blocked on a mutex, and we want to keep it on the runqueue
|
||||||
|
* to be selectable for proxy-execution.
|
||||||
|
*/
|
||||||
|
if (!should_block)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
p->sched_contributes_to_load =
|
p->sched_contributes_to_load =
|
||||||
@@ -7309,6 +7316,7 @@ static inline
|
|||||||
void proxy_force_return(struct rq *rq, struct rq_flags *rf,
|
void proxy_force_return(struct rq *rq, struct rq_flags *rf,
|
||||||
struct task_struct *p)
|
struct task_struct *p)
|
||||||
{
|
{
|
||||||
|
force_blocked_on_runnable(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool proxy_can_run_here(struct rq *rq, struct task_struct *p)
|
static inline bool proxy_can_run_here(struct rq *rq, struct task_struct *p)
|
||||||
@@ -7692,7 +7700,14 @@ static void __sched notrace __schedule(int sched_mode)
|
|||||||
goto picked;
|
goto picked;
|
||||||
}
|
}
|
||||||
} else if (!preempt && prev_state) {
|
} else if (!preempt && prev_state) {
|
||||||
block = try_to_block_task(rq, prev, &prev_state, !task_is_blocked(prev));
|
/*
|
||||||
|
* We pass task_is_blocked() as the should_block arg
|
||||||
|
* in order to keep mutex-blocked tasks on the runqueue
|
||||||
|
* for slection with proxy-exec (without proxy-exec
|
||||||
|
* task_is_blocked() will always be false).
|
||||||
|
*/
|
||||||
|
block = try_to_block_task(rq, prev, &prev_state,
|
||||||
|
!task_is_blocked(prev));
|
||||||
switch_count = &prev->nvcsw;
|
switch_count = &prev->nvcsw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -1270,9 +1270,7 @@ static inline bool do_preempt_short(struct cfs_rq *cfs_rq,
|
|||||||
*/
|
*/
|
||||||
s64 update_curr_common(struct rq *rq)
|
s64 update_curr_common(struct rq *rq)
|
||||||
{
|
{
|
||||||
struct task_struct *donor = rq->donor;
|
return update_se(rq, &rq->donor->se);
|
||||||
|
|
||||||
return update_se(rq, &donor->se);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -2336,7 +2336,7 @@ static inline bool task_is_blocked(struct task_struct *p)
|
|||||||
static inline int task_on_cpu(struct rq *rq, struct task_struct *p)
|
static inline int task_on_cpu(struct rq *rq, struct task_struct *p)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
return READ_ONCE(p->on_cpu);
|
return p->on_cpu;
|
||||||
#else
|
#else
|
||||||
return task_current(rq, p);
|
return task_current(rq, p);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1266,6 +1266,17 @@ config BOOTPARAM_HUNG_TASK_PANIC
|
|||||||
|
|
||||||
Say N if unsure.
|
Say N if unsure.
|
||||||
|
|
||||||
|
config DETECT_HUNG_TASK_BLOCKER
|
||||||
|
bool "Dump Hung Tasks Blocker"
|
||||||
|
depends on DETECT_HUNG_TASK
|
||||||
|
depends on !PREEMPT_RT
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Say Y here to show the blocker task's stacktrace who acquires
|
||||||
|
the mutex lock which "hung tasks" are waiting.
|
||||||
|
This will add overhead a bit but shows suspicious tasks and
|
||||||
|
call trace if it comes from waiting a mutex.
|
||||||
|
|
||||||
config WQ_WATCHDOG
|
config WQ_WATCHDOG
|
||||||
bool "Detect Workqueue Stalls"
|
bool "Detect Workqueue Stalls"
|
||||||
depends on DEBUG_KERNEL
|
depends on DEBUG_KERNEL
|
||||||
|
|||||||
Reference in New Issue
Block a user