|
@@ -873,6 +873,113 @@ static const struct file_operations proc_environ_operations = {
|
|
.release = mem_release,
|
|
.release = mem_release,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count,
|
|
|
|
+ loff_t *ppos)
|
|
|
|
+{
|
|
|
|
+ struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
|
|
|
|
+ char buffer[PROC_NUMBUF];
|
|
|
|
+ int oom_adj = OOM_ADJUST_MIN;
|
|
|
|
+ size_t len;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+
|
|
|
|
+ if (!task)
|
|
|
|
+ return -ESRCH;
|
|
|
|
+ if (lock_task_sighand(task, &flags)) {
|
|
|
|
+ if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MAX)
|
|
|
|
+ oom_adj = OOM_ADJUST_MAX;
|
|
|
|
+ else
|
|
|
|
+ oom_adj = (task->signal->oom_score_adj * -OOM_DISABLE) /
|
|
|
|
+ OOM_SCORE_ADJ_MAX;
|
|
|
|
+ unlock_task_sighand(task, &flags);
|
|
|
|
+ }
|
|
|
|
+ put_task_struct(task);
|
|
|
|
+ len = snprintf(buffer, sizeof(buffer), "%d\n", oom_adj);
|
|
|
|
+ return simple_read_from_buffer(buf, count, ppos, buffer, len);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static ssize_t oom_adj_write(struct file *file, const char __user *buf,
|
|
|
|
+ size_t count, loff_t *ppos)
|
|
|
|
+{
|
|
|
|
+ struct task_struct *task;
|
|
|
|
+ char buffer[PROC_NUMBUF];
|
|
|
|
+ int oom_adj;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ int err;
|
|
|
|
+
|
|
|
|
+ memset(buffer, 0, sizeof(buffer));
|
|
|
|
+ if (count > sizeof(buffer) - 1)
|
|
|
|
+ count = sizeof(buffer) - 1;
|
|
|
|
+ if (copy_from_user(buffer, buf, count)) {
|
|
|
|
+ err = -EFAULT;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ err = kstrtoint(strstrip(buffer), 0, &oom_adj);
|
|
|
|
+ if (err)
|
|
|
|
+ goto out;
|
|
|
|
+ if ((oom_adj < OOM_ADJUST_MIN || oom_adj > OOM_ADJUST_MAX) &&
|
|
|
|
+ oom_adj != OOM_DISABLE) {
|
|
|
|
+ err = -EINVAL;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ task = get_proc_task(file->f_path.dentry->d_inode);
|
|
|
|
+ if (!task) {
|
|
|
|
+ err = -ESRCH;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ task_lock(task);
|
|
|
|
+ if (!task->mm) {
|
|
|
|
+ err = -EINVAL;
|
|
|
|
+ goto err_task_lock;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!lock_task_sighand(task, &flags)) {
|
|
|
|
+ err = -ESRCH;
|
|
|
|
+ goto err_task_lock;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Scale /proc/pid/oom_score_adj appropriately ensuring that a maximum
|
|
|
|
+ * value is always attainable.
|
|
|
|
+ */
|
|
|
|
+ if (oom_adj == OOM_ADJUST_MAX)
|
|
|
|
+ oom_adj = OOM_SCORE_ADJ_MAX;
|
|
|
|
+ else
|
|
|
|
+ oom_adj = (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
|
|
|
|
+
|
|
|
|
+ if (oom_adj < task->signal->oom_score_adj &&
|
|
|
|
+ !capable(CAP_SYS_RESOURCE)) {
|
|
|
|
+ err = -EACCES;
|
|
|
|
+ goto err_sighand;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * /proc/pid/oom_adj is provided for legacy purposes, ask users to use
|
|
|
|
+ * /proc/pid/oom_score_adj instead.
|
|
|
|
+ */
|
|
|
|
+ printk_once(KERN_WARNING "%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n",
|
|
|
|
+ current->comm, task_pid_nr(current), task_pid_nr(task),
|
|
|
|
+ task_pid_nr(task));
|
|
|
|
+
|
|
|
|
+ task->signal->oom_score_adj = oom_adj;
|
|
|
|
+ trace_oom_score_adj_update(task);
|
|
|
|
+err_sighand:
|
|
|
|
+ unlock_task_sighand(task, &flags);
|
|
|
|
+err_task_lock:
|
|
|
|
+ task_unlock(task);
|
|
|
|
+ put_task_struct(task);
|
|
|
|
+out:
|
|
|
|
+ return err < 0 ? err : count;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static const struct file_operations proc_oom_adj_operations = {
|
|
|
|
+ .read = oom_adj_read,
|
|
|
|
+ .write = oom_adj_write,
|
|
|
|
+ .llseek = generic_file_llseek,
|
|
|
|
+};
|
|
|
|
+
|
|
static ssize_t oom_score_adj_read(struct file *file, char __user *buf,
|
|
static ssize_t oom_score_adj_read(struct file *file, char __user *buf,
|
|
size_t count, loff_t *ppos)
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
{
|
|
@@ -2598,6 +2705,7 @@ static const struct pid_entry tgid_base_stuff[] = {
|
|
REG("cgroup", S_IRUGO, proc_cgroup_operations),
|
|
REG("cgroup", S_IRUGO, proc_cgroup_operations),
|
|
#endif
|
|
#endif
|
|
INF("oom_score", S_IRUGO, proc_oom_score),
|
|
INF("oom_score", S_IRUGO, proc_oom_score),
|
|
|
|
+ REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations),
|
|
REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
|
|
REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
|
|
#ifdef CONFIG_AUDITSYSCALL
|
|
#ifdef CONFIG_AUDITSYSCALL
|
|
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
|
|
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
|
|
@@ -2964,6 +3072,7 @@ static const struct pid_entry tid_base_stuff[] = {
|
|
REG("cgroup", S_IRUGO, proc_cgroup_operations),
|
|
REG("cgroup", S_IRUGO, proc_cgroup_operations),
|
|
#endif
|
|
#endif
|
|
INF("oom_score", S_IRUGO, proc_oom_score),
|
|
INF("oom_score", S_IRUGO, proc_oom_score),
|
|
|
|
+ REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations),
|
|
REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
|
|
REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
|
|
#ifdef CONFIG_AUDITSYSCALL
|
|
#ifdef CONFIG_AUDITSYSCALL
|
|
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
|
|
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
|