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

Commit db1aa31a authored by Imran Khan's avatar Imran Khan Committed by Srinivas Ramana
Browse files

hung task: check specific tasks for long uninterruptible sleep state



khungtask by default monitors all tasks for long unterruptible sleep.
This change introduces a sysctl option, /proc/sys/kernel/
hung_task_selective_monitoring, to enable monitoring selected tasks.
If this sysctl option is enabled then only the tasks with
/proc/$PID/hang_detection_enabled set are to be monitored,
otherwise all tasks are monitored as default case.

Some tasks may intentionally moves to uninterruptable sleep state,
which shouldn't leads to khungtask panics, as those are recoverable
hungs. So to avoid false hung reports, add an option to select tasks
to be monitored and report/panic them only.
By default, enable the feature always to monitor selected tasks.

Change-Id: I48cd8cfe73dbe2b577541fe9607190eac5556bb2
Signed-off-by: default avatarImran Khan <kimran@codeaurora.org>
Signed-off-by: default avatarLingutla Chandrasekhar <clingutla@codeaurora.org>
[sramana: Resolved minor merge conflict]
Signed-off-by: default avatarSrinivas Ramana <sramana@codeaurora.org>
parent 55a26aeb
Loading
Loading
Loading
Loading
+54 −0
Original line number Original line Diff line number Diff line
@@ -2965,6 +2965,52 @@ static int proc_tgid_io_accounting(struct seq_file *m, struct pid_namespace *ns,
}
}
#endif /* CONFIG_TASK_IO_ACCOUNTING */
#endif /* CONFIG_TASK_IO_ACCOUNTING */


#ifdef CONFIG_DETECT_HUNG_TASK
static ssize_t proc_hung_task_detection_enabled_read(struct file *file,
				char __user *buf, size_t count, loff_t *ppos)
{
	struct task_struct *task = get_proc_task(file_inode(file));
	char buffer[PROC_NUMBUF];
	size_t len;
	bool hang_detection_enabled;

	if (!task)
		return -ESRCH;
	hang_detection_enabled = task->hang_detection_enabled;
	put_task_struct(task);

	len = snprintf(buffer, sizeof(buffer), "%d\n", hang_detection_enabled);

	return simple_read_from_buffer(buf, sizeof(buffer), ppos, buffer, len);
}

static ssize_t proc_hung_task_detection_enabled_write(struct file *file,
			const char __user *buf, size_t count, loff_t *ppos)
{
	struct task_struct *task;
	bool hang_detection_enabled;
	int rv;

	rv = kstrtobool_from_user(buf, count, &hang_detection_enabled);
	if (rv < 0)
		return rv;

	task = get_proc_task(file_inode(file));
	if (!task)
		return -ESRCH;
	task->hang_detection_enabled = hang_detection_enabled;
	put_task_struct(task);

	return count;
}

static const struct file_operations proc_hung_task_detection_enabled_operations = {
	.read		= proc_hung_task_detection_enabled_read,
	.write		= proc_hung_task_detection_enabled_write,
	.llseek		= generic_file_llseek,
};
#endif

#ifdef CONFIG_USER_NS
#ifdef CONFIG_USER_NS
static int proc_id_map_open(struct inode *inode, struct file *file,
static int proc_id_map_open(struct inode *inode, struct file *file,
	const struct seq_operations *seq_ops)
	const struct seq_operations *seq_ops)
@@ -3218,6 +3264,10 @@ static const struct pid_entry tgid_base_stuff[] = {
#ifdef CONFIG_HARDWALL
#ifdef CONFIG_HARDWALL
	ONE("hardwall",   S_IRUGO, proc_pid_hardwall),
	ONE("hardwall",   S_IRUGO, proc_pid_hardwall),
#endif
#endif
#ifdef CONFIG_DETECT_HUNG_TASK
	REG("hang_detection_enabled", 0666,
		proc_hung_task_detection_enabled_operations),
#endif
#ifdef CONFIG_USER_NS
#ifdef CONFIG_USER_NS
	REG("uid_map",    S_IRUGO|S_IWUSR, proc_uid_map_operations),
	REG("uid_map",    S_IRUGO|S_IWUSR, proc_uid_map_operations),
	REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations),
	REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations),
@@ -3612,6 +3662,10 @@ static const struct pid_entry tid_base_stuff[] = {
#ifdef CONFIG_HARDWALL
#ifdef CONFIG_HARDWALL
	ONE("hardwall",   S_IRUGO, proc_pid_hardwall),
	ONE("hardwall",   S_IRUGO, proc_pid_hardwall),
#endif
#endif
#ifdef CONFIG_DETECT_HUNG_TASK
	REG("hang_detection_enabled", 0666,
		proc_hung_task_detection_enabled_operations),
#endif
#ifdef CONFIG_USER_NS
#ifdef CONFIG_USER_NS
	REG("uid_map",    S_IRUGO|S_IWUSR, proc_uid_map_operations),
	REG("uid_map",    S_IRUGO|S_IWUSR, proc_uid_map_operations),
	REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations),
	REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations),
+2 −0
Original line number Original line Diff line number Diff line
@@ -1001,7 +1001,9 @@ struct task_struct {
	struct sysv_shm			sysvshm;
	struct sysv_shm			sysvshm;
#endif
#endif
#ifdef CONFIG_DETECT_HUNG_TASK
#ifdef CONFIG_DETECT_HUNG_TASK
	/* hung task detection */
	unsigned long			last_switch_count;
	unsigned long			last_switch_count;
	bool hang_detection_enabled;
#endif
#endif
	/* Filesystem information: */
	/* Filesystem information: */
	struct fs_struct		*fs;
	struct fs_struct		*fs;
+1 −0
Original line number Original line Diff line number Diff line
@@ -11,6 +11,7 @@ extern int sysctl_hung_task_check_count;
extern unsigned int  sysctl_hung_task_panic;
extern unsigned int  sysctl_hung_task_panic;
extern unsigned long sysctl_hung_task_timeout_secs;
extern unsigned long sysctl_hung_task_timeout_secs;
extern int sysctl_hung_task_warnings;
extern int sysctl_hung_task_warnings;
extern int sysctl_hung_task_selective_monitoring;
extern int proc_dohung_task_timeout_secs(struct ctl_table *table, int write,
extern int proc_dohung_task_timeout_secs(struct ctl_table *table, int write,
					 void __user *buffer,
					 void __user *buffer,
					 size_t *lenp, loff_t *ppos);
					 size_t *lenp, loff_t *ppos);
+13 −1
Original line number Original line Diff line number Diff line
@@ -20,12 +20,21 @@
#include <linux/sched/debug.h>
#include <linux/sched/debug.h>


#include <trace/events/sched.h>
#include <trace/events/sched.h>
#include <linux/sched/sysctl.h>


/*
/*
 * The number of tasks checked:
 * The number of tasks checked:
 */
 */
int __read_mostly sysctl_hung_task_check_count = PID_MAX_LIMIT;
int __read_mostly sysctl_hung_task_check_count = PID_MAX_LIMIT;


/*
 * Selective monitoring of hung tasks.
 *
 * if set to 1, khungtaskd skips monitoring tasks, which has
 * task_struct->hang_detection_enabled value not set, else monitors all tasks.
 */
int sysctl_hung_task_selective_monitoring = 1;

/*
/*
 * Limit number of tasks checked in a batch.
 * Limit number of tasks checked in a batch.
 *
 *
@@ -186,6 +195,9 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
		}
		}
		/* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */
		/* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */
		if (t->state == TASK_UNINTERRUPTIBLE)
		if (t->state == TASK_UNINTERRUPTIBLE)
			/* Check for selective monitoring */
			if (!sysctl_hung_task_selective_monitoring ||
			    t->hang_detection_enabled)
				check_hung_task(t, timeout);
				check_hung_task(t, timeout);
	}
	}
 unlock:
 unlock:
+10 −0
Original line number Original line Diff line number Diff line
@@ -1232,6 +1232,16 @@ static struct ctl_table kern_table[] = {
		.proc_handler	= proc_dointvec_minmax,
		.proc_handler	= proc_dointvec_minmax,
		.extra1		= &neg_one,
		.extra1		= &neg_one,
	},
	},
	{
		.procname	= "hung_task_selective_monitoring",
		.data		= &sysctl_hung_task_selective_monitoring,
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= proc_dointvec_minmax,
		.extra1		= &zero,
		.extra2		= &one,
	},

#endif
#endif
#ifdef CONFIG_RT_MUTEXES
#ifdef CONFIG_RT_MUTEXES
	{
	{