mm, oom: reintroduce /proc/pid/oom_adj
[platform/adaptation/renesas_rcar/renesas_kernel.git] / fs / proc / base.c
index 144a967..3c231ad 100644 (file)
@@ -873,6 +873,113 @@ static const struct file_operations proc_environ_operations = {
        .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,
                                        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),
 #endif
        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),
 #ifdef CONFIG_AUDITSYSCALL
        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),
 #endif
        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),
 #ifdef CONFIG_AUDITSYSCALL
        REG("loginuid",  S_IWUSR|S_IRUGO, proc_loginuid_operations),