121 lines
2.3 KiB
C
121 lines
2.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright 2019 Google, Inc.
|
|
*
|
|
* Support for setting tasks as latency sensitive
|
|
* using /proc/pid/tasks/tid/latency_sensitive interface.
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/sched/task.h>
|
|
#include <linux/sched/latsense.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/fs_struct.h>
|
|
|
|
#include "internal.h"
|
|
|
|
/*
|
|
* Print out latsense related information:
|
|
*/
|
|
static int sched_latsense_show(struct seq_file *m, void *v)
|
|
{
|
|
struct inode *inode = m->private;
|
|
struct task_struct *p;
|
|
|
|
p = get_proc_task(inode);
|
|
if (!p)
|
|
return -ESRCH;
|
|
|
|
seq_printf(m, "%d\n", !!proc_sched_get_latency_sensitive(p));
|
|
|
|
put_task_struct(p);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t
|
|
sched_latsense_write(struct file *file, const char __user *buf,
|
|
size_t count, loff_t *offset)
|
|
{
|
|
struct inode *inode = file_inode(file);
|
|
struct task_struct *p;
|
|
char buffer[PROC_NUMBUF];
|
|
int val;
|
|
int err;
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
if (count > sizeof(buffer) - 1)
|
|
count = sizeof(buffer) - 1;
|
|
if (copy_from_user(buffer, buf, count))
|
|
return -EFAULT;
|
|
|
|
err = kstrtoint(strstrip(buffer), 0, &val);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
if (val != 0 && val != 1)
|
|
return -EINVAL;
|
|
|
|
p = get_proc_task(inode);
|
|
if (!p)
|
|
return -ESRCH;
|
|
|
|
err = proc_sched_set_latency_sensitive(p, val);
|
|
if (err)
|
|
count = err;
|
|
|
|
put_task_struct(p);
|
|
|
|
return count;
|
|
}
|
|
|
|
static int sched_latsense_access(struct inode *inode, fmode_t mode)
|
|
{
|
|
struct task_struct *p;
|
|
int ret = -EACCES;
|
|
|
|
if (!(mode & FMODE_WRITE))
|
|
return 0;
|
|
|
|
p = get_proc_task(inode);
|
|
if (!p)
|
|
return -ESRCH;
|
|
|
|
if (ptrace_may_access(p, PTRACE_MODE_ATTACH_REALCREDS) ||
|
|
capable(CAP_SYS_NICE)) {
|
|
ret = 0;
|
|
}
|
|
|
|
put_task_struct(p);
|
|
return ret;
|
|
}
|
|
|
|
static int sched_latsense_open(struct inode *inode, struct file *filp)
|
|
{
|
|
int ret;
|
|
|
|
ret = sched_latsense_access(inode, filp->f_mode);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = single_open(filp, sched_latsense_show, NULL);
|
|
if (!ret) {
|
|
struct seq_file *m = filp->private_data;
|
|
|
|
m->private = inode;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
const struct file_operations proc_tid_latsense_operations = {
|
|
.open = sched_latsense_open,
|
|
.read = seq_read,
|
|
.write = sched_latsense_write,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
};
|