Skip to contentSkip to conversation

RTTIME watchdog timer proc interface

RFC PATCH Superseded Hiroshi Shimamoto 2 participants 5 messages Feb 12, 2008 – Feb 13, 2008 Proc filesystem

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

RFC PATCH v2 1/1 RTTIME watchdog timer proc interface

From: Hiroshi Shimamoto <[email protected]>

Introduce new proc interface for RTTIME watchdog.
It makes administrator able to set RTTIME watchdog to existing real-time applications without impact.

$ echo 10000000 > /proc/<pid>/rttime
set RTTIME current value to 10000000, it means 10sec.
$ echo "10000000 20000000" > /proc/<pid>/rttime
set RTTIME current value to 10000000 and max value to 20000000.

And /proc/<pid>/task/<tid>/rttime is also accessible.

---
 fs/proc/base.c |   89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 89 insertions(+), 0 deletions(-)
fs/proc/base.c +89 -0
index 7c6b4ec..3212b44 100644
@@ -381,6 +381,93 @@ static const struct file_operations proc_lstats_operations = {
 
 #endif
 
+static int rttime_show_proc(struct seq_file *m, void *v)
+{
+	struct task_struct *task = m->private;
+	struct signal_struct *signal = task->signal;
+	struct rlimit *rt = &signal->rlim[RLIMIT_RTTIME];
+
+	if (rt->rlim_cur == RLIM_INFINITY)
+		seq_printf(m, "unlimited ");
+	else
+		seq_printf(m, "%lu ", rt->rlim_cur);
+
+	if (rt->rlim_max == RLIM_INFINITY)
+		seq_printf(m, "unlimited\n");
+	else
+		seq_printf(m, "%lu\n", rt->rlim_max);
+
+	return 0;
+}
+
+static int rttime_open(struct inode *inode, struct file *file)
+{
+	int ret;
+	struct seq_file *m;
+	struct task_struct *task = get_proc_task(inode);
+
+	ret = single_open(file, rttime_show_proc, NULL);
+	if (!ret) {
+		m = file->private_data;
+		m->private = task;
+	}
+	return ret;
+}
+
+static ssize_t rttime_write(struct file *file,
+			    const char __user *buf,
+			    size_t count,
+			    loff_t *ppos)
+{
+	struct seq_file *m = file->private_data;
+	struct task_struct *task = m->private;
+	char buffer[PROC_NUMBUF], *end;
+	struct rlimit new_rlim, *old_rlim;
+	int n, ret;
+
+	old_rlim = task->signal->rlim + RLIMIT_RTTIME;
+	new_rlim = *old_rlim;
+	memset(buffer, 0, sizeof(buffer));
+	n = count;
+	if (n > sizeof(buffer) - 1)
+		n = sizeof(buffer) - 1;
+	if (copy_from_user(buffer, buf, n))
+		return -EFAULT;
+	new_rlim.rlim_cur = simple_strtoul(buffer, &end, 0);
+	if (*end == ' ') {
+		++end;
+		buf += end - buffer;
+		memset(buffer, 0, sizeof(buffer));
+		n = count - (end - buffer);
+		if (n > sizeof(buffer) - 1)
+			n = sizeof(buffer) - 1;
+		if (copy_from_user(buffer, buf, n))
+			return -EFAULT;
+		new_rlim.rlim_max = simple_strtoul(buffer, &end, 0);
+	}
+	if (new_rlim.rlim_cur > new_rlim.rlim_max)
+		return -EINVAL;
+	if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
+	    !capable(CAP_SYS_RESOURCE))
+		return -EPERM;
+	ret = security_task_setrlimit(RLIMIT_RTTIME, &new_rlim);
+	if (ret)
+		return ret;
+	task_lock(task->group_leader);
+	*old_rlim = new_rlim;
+	task_unlock(task->group_leader);
+
+	return count;
+}
+
+static const struct file_operations proc_rttime_operations = {
+	.open		= rttime_open,
+	.read		= seq_read,
+	.write		= rttime_write,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 /* The badness from the OOM killer */
 unsigned long badness(struct task_struct *p, unsigned long uptime);
 static int proc_oom_score(struct task_struct *task, char *buffer)
@@ -2300,6 +2387,7 @@ static const struct pid_entry tgid_base_stuff[] = {
 	LNK("exe",        exe),
 	REG("mounts",     S_IRUGO, mounts),
 	REG("mountstats", S_IRUSR, mountstats),
+	REG("rttime",     S_IRUSR|S_IWUSR, rttime),
 #ifdef CONFIG_PROC_PAGE_MONITOR
 	REG("clear_refs", S_IWUSR, clear_refs),
 	REG("smaps",      S_IRUGO, smaps),
@@ -2630,6 +2718,7 @@ static const struct pid_entry tid_base_stuff[] = {
 	LNK("root",      root),
 	LNK("exe",       exe),
 	REG("mounts",    S_IRUGO, mounts),
+	REG("rttime",    S_IRUSR|S_IWUSR, rttime),
 #ifdef CONFIG_PROC_PAGE_MONITOR
 	REG("clear_refs", S_IWUSR, clear_refs),
 	REG("smaps",     S_IRUGO, smaps),
Signature · 1 line
1.5.3.8
#1 lore raw
Quoted 11 lines · On Tue, 12 Feb 2008 14:41:42 -0800 Hiroshi Shimamoto…

From: Hiroshi Shimamoto <[email protected]>

Introduce new proc interface for RTTIME watchdog.
It makes administrator able to set RTTIME watchdog to existing real-time applications without impact.

$ echo 10000000 > /proc/<pid>/rttime
set RTTIME current value to 10000000, it means 10sec.
$ echo "10000000 20000000" > /proc/<pid>/rttime
set RTTIME current value to 10000000 and max value to 20000000.

How does one set it to `unlimited'?

Quoted 1 line

And /proc/<pid>/task/<tid>/rttime is also accessible.

Please describe the format in the changelog.

Quoted 35 lines
---
 fs/proc/base.c |   89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 89 insertions(+), 0 deletions(-)
fs/proc/base.c +22 -0
index 7c6b4ec..3212b44 100644
@@ -381,6 +381,93 @@ static const struct file_operations proc_lstats_operations = {
 
 #endif
 
+static int rttime_show_proc(struct seq_file *m, void *v)
+{
+	struct task_struct *task = m->private;
+	struct signal_struct *signal = task->signal;
+	struct rlimit *rt = &signal->rlim[RLIMIT_RTTIME];
+
+	if (rt->rlim_cur == RLIM_INFINITY)
+		seq_printf(m, "unlimited ");
+	else
+		seq_printf(m, "%lu ", rt->rlim_cur);
+
+	if (rt->rlim_max == RLIM_INFINITY)
+		seq_printf(m, "unlimited\n");
+	else
+		seq_printf(m, "%lu\n", rt->rlim_max);
+
+	return 0;
+}
+
+static int rttime_open(struct inode *inode, struct file *file)
+{
+	int ret;

fs/proc/base.c static const struct file_operations proc_lstats_operations = { · line 415

Quoted 10 lines
fs/proc/base.c +10 -0
+	struct seq_file *m;
+	struct task_struct *task = get_proc_task(inode);
+
+	ret = single_open(file, rttime_show_proc, NULL);
+	if (!ret) {
+		m = file->private_data;
+		m->private = task;
+	}
+	return ret;
+}

get_proc_task() can return NULL, in which case it appears that the kernel will later oops?

fs/proc/base.c static const struct file_operations proc_lstats_operations = { · line 426

Quoted 10 lines
fs/proc/base.c +10 -0
+static ssize_t rttime_write(struct file *file,
+			    const char __user *buf,
+			    size_t count,
+			    loff_t *ppos)
+{
+	struct seq_file *m = file->private_data;
+	struct task_struct *task = m->private;
+	char buffer[PROC_NUMBUF], *end;
+	struct rlimit new_rlim, *old_rlim;
+	int n, ret;

`n' should be size_t. And a better name would be nice.

fs/proc/base.c static const struct file_operations proc_lstats_operations = { · line 433

Quoted 6 lines
fs/proc/base.c +6 -0
+	old_rlim = task->signal->rlim + RLIMIT_RTTIME;
+	new_rlim = *old_rlim;
+	memset(buffer, 0, sizeof(buffer));
+	n = count;
+	if (n > sizeof(buffer) - 1)
+		n = sizeof(buffer) - 1;

min()

fs/proc/base.c static const struct file_operations proc_lstats_operations = { · line 443

Quoted 10 lines
fs/proc/base.c +10 -0
+	if (copy_from_user(buffer, buf, n))
+		return -EFAULT;
+	new_rlim.rlim_cur = simple_strtoul(buffer, &end, 0);
+	if (*end == ' ') {
+		++end;
+		buf += end - buffer;
+		memset(buffer, 0, sizeof(buffer));
+		n = count - (end - buffer);
+		if (n > sizeof(buffer) - 1)
+			n = sizeof(buffer) - 1;

min()

fs/proc/base.c static const struct file_operations proc_lstats_operations = { · line 446

Quoted 3 lines
fs/proc/base.c +3 -0
+		if (copy_from_user(buffer, buf, n))
+			return -EFAULT;
+		new_rlim.rlim_max = simple_strtoul(buffer, &end, 0);

strict_strtoul()?

fs/proc/base.c static const struct file_operations proc_lstats_operations = { · line 458

Quoted 12 lines
fs/proc/base.c +12 -0
+	}
+	if (new_rlim.rlim_cur > new_rlim.rlim_max)
+		return -EINVAL;
+	if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
+	    !capable(CAP_SYS_RESOURCE))
+		return -EPERM;
+	ret = security_task_setrlimit(RLIMIT_RTTIME, &new_rlim);
+	if (ret)
+		return ret;
+	task_lock(task->group_leader);
+	*old_rlim = new_rlim;
+	task_unlock(task->group_leader);

hm. Why do we lock on ->group_leader rather than the task itself?

Quoted 30 lines
fs/proc/base.c +13 -0
+	return count;
+}
+
+static const struct file_operations proc_rttime_operations = {
+	.open		= rttime_open,
+	.read		= seq_read,
+	.write		= rttime_write,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 /* The badness from the OOM killer */
 unsigned long badness(struct task_struct *p, unsigned long uptime);
 static int proc_oom_score(struct task_struct *task, char *buffer)
@@ -2300,6 +2387,7 @@ static const struct pid_entry tgid_base_stuff[] = {
 	LNK("exe",        exe),
 	REG("mounts",     S_IRUGO, mounts),
 	REG("mountstats", S_IRUSR, mountstats),
+	REG("rttime",     S_IRUSR|S_IWUSR, rttime),
 #ifdef CONFIG_PROC_PAGE_MONITOR
 	REG("clear_refs", S_IWUSR, clear_refs),
 	REG("smaps",      S_IRUGO, smaps),
@@ -2630,6 +2718,7 @@ static const struct pid_entry tid_base_stuff[] = {
 	LNK("root",      root),
 	LNK("exe",       exe),
 	REG("mounts",    S_IRUGO, mounts),
+	REG("rttime",    S_IRUSR|S_IWUSR, rttime),
 #ifdef CONFIG_PROC_PAGE_MONITOR
 	REG("clear_refs", S_IWUSR, clear_refs),
 	REG("smaps",     S_IRUGO, smaps),
#2 lore raw
Quoted 8 lines · Andrew Morton
Quoted 6 lines · On Tue, 12 Feb 2008 14:41:42 -0800 Hiroshi Shimamoto…

From: Hiroshi Shimamoto <[email protected]>

Introduce new proc interface for RTTIME watchdog.
It makes administrator able to set RTTIME watchdog to existing real-time applications without impact.

Quoted 7 lines
Quoted 5 lines
$ echo 10000000 > /proc/<pid>/rttime
set RTTIME current value to 10000000, it means 10sec.
$ echo "10000000 20000000" > /proc/<pid>/rttime
set RTTIME current value to 10000000 and max value to 20000000.

How does one set it to `unlimited'?

There is no way now. Will add.

Quoted 4 lines
Quoted 2 lines

And /proc/<pid>/task/<tid>/rttime is also accessible.

Please describe the format in the changelog.

I'm sorry I cannot catch your meaning.

Quoted 41 lines
Quoted 41 lines
---
 fs/proc/base.c |   89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 89 insertions(+), 0 deletions(-)
fs/proc/base.c +27 -0
index 7c6b4ec..3212b44 100644
@@ -381,6 +381,93 @@ static const struct file_operations proc_lstats_operations = {
 
 #endif
 
+static int rttime_show_proc(struct seq_file *m, void *v)
+{
+	struct task_struct *task = m->private;
+	struct signal_struct *signal = task->signal;
+	struct rlimit *rt = &signal->rlim[RLIMIT_RTTIME];
+
+	if (rt->rlim_cur == RLIM_INFINITY)
+		seq_printf(m, "unlimited ");
+	else
+		seq_printf(m, "%lu ", rt->rlim_cur);
+
+	if (rt->rlim_max == RLIM_INFINITY)
+		seq_printf(m, "unlimited\n");
+	else
+		seq_printf(m, "%lu\n", rt->rlim_max);
+
+	return 0;
+}
+
+static int rttime_open(struct inode *inode, struct file *file)
+{
+	int ret;
+	struct seq_file *m;
+	struct task_struct *task = get_proc_task(inode);
+
+	ret = single_open(file, rttime_show_proc, NULL);
+	if (!ret) {
Quoted 8 lines

fs/proc/base.c static const struct file_operations proc_lstats_operations = { · line 415

Quoted 5 lines
fs/proc/base.c +5 -0
+		m = file->private_data;
+		m->private = task;
+	}
+	return ret;
+}

get_proc_task() can return NULL, in which case it appears that the kernel will later oops?

Yes, it could cause oops. Will fix.

Quoted 13 lines

fs/proc/base.c static const struct file_operations proc_lstats_operations = { · line 426

Quoted 11 lines
fs/proc/base.c +10 -0
+static ssize_t rttime_write(struct file *file,
+			    const char __user *buf,
+			    size_t count,
+			    loff_t *ppos)
+{
+	struct seq_file *m = file->private_data;
+	struct task_struct *task = m->private;
+	char buffer[PROC_NUMBUF], *end;
+	struct rlimit new_rlim, *old_rlim;
+	int n, ret;

`n' should be size_t. And a better name would be nice.

Agree.

Quoted 9 lines

fs/proc/base.c static const struct file_operations proc_lstats_operations = { · line 433

Quoted 7 lines
fs/proc/base.c +6 -0
+	old_rlim = task->signal->rlim + RLIMIT_RTTIME;
+	new_rlim = *old_rlim;
+	memset(buffer, 0, sizeof(buffer));
+	n = count;
+	if (n > sizeof(buffer) - 1)
+		n = sizeof(buffer) - 1;

min()

Thanks, I hadn't noticed min().

Quoted 14 lines

fs/proc/base.c static const struct file_operations proc_lstats_operations = { · line 443

Quoted 11 lines
fs/proc/base.c +10 -0
+	if (copy_from_user(buffer, buf, n))
+		return -EFAULT;
+	new_rlim.rlim_cur = simple_strtoul(buffer, &end, 0);
+	if (*end == ' ') {
+		++end;
+		buf += end - buffer;
+		memset(buffer, 0, sizeof(buffer));
+		n = count - (end - buffer);
+		if (n > sizeof(buffer) - 1)
+			n = sizeof(buffer) - 1;

min()

Quoted 5 lines

fs/proc/base.c static const struct file_operations proc_lstats_operations = { · line 446

Quoted 3 lines
fs/proc/base.c +3 -0
+		if (copy_from_user(buffer, buf, n))
+			return -EFAULT;
+		new_rlim.rlim_max = simple_strtoul(buffer, &end, 0);

strict_strtoul()?

OK, I should look at it.

Quoted 15 lines

fs/proc/base.c static const struct file_operations proc_lstats_operations = { · line 458

Quoted 13 lines
fs/proc/base.c +12 -0
+	}
+	if (new_rlim.rlim_cur > new_rlim.rlim_max)
+		return -EINVAL;
+	if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
+	    !capable(CAP_SYS_RESOURCE))
+		return -EPERM;
+	ret = security_task_setrlimit(RLIMIT_RTTIME, &new_rlim);
+	if (ret)
+		return ret;
+	task_lock(task->group_leader);
+	*old_rlim = new_rlim;
+	task_unlock(task->group_leader);

hm. Why do we lock on ->group_leader rather than the task itself?

It's same as setrlimit.

Quoted 23 lines
Quoted 23 lines
fs/proc/base.c +12 -0
+	return count;
+}
+
+static const struct file_operations proc_rttime_operations = {
+	.open		= rttime_open,
+	.read		= seq_read,
+	.write		= rttime_write,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 /* The badness from the OOM killer */
 unsigned long badness(struct task_struct *p, unsigned long uptime);
 static int proc_oom_score(struct task_struct *task, char *buffer)
@@ -2300,6 +2387,7 @@ static const struct pid_entry tgid_base_stuff[] = {
 	LNK("exe",        exe),
 	REG("mounts",     S_IRUGO, mounts),
 	REG("mountstats", S_IRUSR, mountstats),
+	REG("rttime",     S_IRUSR|S_IWUSR, rttime),
 #ifdef CONFIG_PROC_PAGE_MONITOR
 	REG("clear_refs", S_IWUSR, clear_refs),
 	REG("smaps",      S_IRUGO, smaps),
Quoted 8 lines

fs/proc/base.c static const struct pid_entry tid_base_stuff[] = { · line 2724

Quoted 8 lines
fs/proc/base.c +1 -0
@@ -2630,6 +2718,7 @@ static const struct pid_entry tid_base_stuff[] = {
 	LNK("root",      root),
 	LNK("exe",       exe),
 	REG("mounts",    S_IRUGO, mounts),
+	REG("rttime",    S_IRUSR|S_IWUSR, rttime),
 #ifdef CONFIG_PROC_PAGE_MONITOR
 	REG("clear_refs", S_IWUSR, clear_refs),
 	REG("smaps",     S_IRUGO, smaps),

Thanks for reviewing.

Hiroshi Shimamoto

#3 lore raw
Quoted 6 lines · On Wed, 13 Feb 2008 09:45:54 -0800 Hiroshi Shimamoto…
Quoted 4 lines
Quoted 2 lines

And /proc/<pid>/task/<tid>/rttime is also accessible.

Please describe the format in the changelog.

I'm sorry I cannot catch your meaning.

Please include an example of the output of
`cat /proc/<pid>/task/<tid>/rttime' in the changelog so that we can see precisely what interface you are proposing.

#4 lore raw
Quoted 10 lines · Andrew Morton
Quoted 3 lines · On Wed, 13 Feb 2008 09:45:54 -0800 Hiroshi Shimamoto…
Quoted 2 lines
Quoted 1 line

And /proc/<pid>/task/<tid>/rttime is also accessible.

Please describe the format in the changelog.

I'm sorry I cannot catch your meaning.

Please include an example of the output of
`cat /proc/<pid>/task/<tid>/rttime' in the changelog so that we can see precisely what interface you are proposing.

thanks, I see.