aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r--fs/proc/base.c99
1 files changed, 72 insertions, 27 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index dc5d5f51f3fe..53dc8ad40ae6 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1023,28 +1023,47 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
1023 memset(buffer, 0, sizeof(buffer)); 1023 memset(buffer, 0, sizeof(buffer));
1024 if (count > sizeof(buffer) - 1) 1024 if (count > sizeof(buffer) - 1)
1025 count = sizeof(buffer) - 1; 1025 count = sizeof(buffer) - 1;
1026 if (copy_from_user(buffer, buf, count)) 1026 if (copy_from_user(buffer, buf, count)) {
1027 return -EFAULT; 1027 err = -EFAULT;
1028 goto out;
1029 }
1028 1030
1029 err = strict_strtol(strstrip(buffer), 0, &oom_adjust); 1031 err = strict_strtol(strstrip(buffer), 0, &oom_adjust);
1030 if (err) 1032 if (err)
1031 return -EINVAL; 1033 goto out;
1032 if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) && 1034 if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) &&
1033 oom_adjust != OOM_DISABLE) 1035 oom_adjust != OOM_DISABLE) {
1034 return -EINVAL; 1036 err = -EINVAL;
1037 goto out;
1038 }
1035 1039
1036 task = get_proc_task(file->f_path.dentry->d_inode); 1040 task = get_proc_task(file->f_path.dentry->d_inode);
1037 if (!task) 1041 if (!task) {
1038 return -ESRCH; 1042 err = -ESRCH;
1043 goto out;
1044 }
1045
1046 task_lock(task);
1047 if (!task->mm) {
1048 err = -EINVAL;
1049 goto err_task_lock;
1050 }
1051
1039 if (!lock_task_sighand(task, &flags)) { 1052 if (!lock_task_sighand(task, &flags)) {
1040 put_task_struct(task); 1053 err = -ESRCH;
1041 return -ESRCH; 1054 goto err_task_lock;
1042 } 1055 }
1043 1056
1044 if (oom_adjust < task->signal->oom_adj && !capable(CAP_SYS_RESOURCE)) { 1057 if (oom_adjust < task->signal->oom_adj && !capable(CAP_SYS_RESOURCE)) {
1045 unlock_task_sighand(task, &flags); 1058 err = -EACCES;
1046 put_task_struct(task); 1059 goto err_sighand;
1047 return -EACCES; 1060 }
1061
1062 if (oom_adjust != task->signal->oom_adj) {
1063 if (oom_adjust == OOM_DISABLE)
1064 atomic_inc(&task->mm->oom_disable_count);
1065 if (task->signal->oom_adj == OOM_DISABLE)
1066 atomic_dec(&task->mm->oom_disable_count);
1048 } 1067 }
1049 1068
1050 /* 1069 /*
@@ -1065,10 +1084,13 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
1065 else 1084 else
1066 task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) / 1085 task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) /
1067 -OOM_DISABLE; 1086 -OOM_DISABLE;
1087err_sighand:
1068 unlock_task_sighand(task, &flags); 1088 unlock_task_sighand(task, &flags);
1089err_task_lock:
1090 task_unlock(task);
1069 put_task_struct(task); 1091 put_task_struct(task);
1070 1092out:
1071 return count; 1093 return err < 0 ? err : count;
1072} 1094}
1073 1095
1074static const struct file_operations proc_oom_adjust_operations = { 1096static const struct file_operations proc_oom_adjust_operations = {
@@ -1109,30 +1131,49 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
1109 memset(buffer, 0, sizeof(buffer)); 1131 memset(buffer, 0, sizeof(buffer));
1110 if (count > sizeof(buffer) - 1) 1132 if (count > sizeof(buffer) - 1)
1111 count = sizeof(buffer) - 1; 1133 count = sizeof(buffer) - 1;
1112 if (copy_from_user(buffer, buf, count)) 1134 if (copy_from_user(buffer, buf, count)) {
1113 return -EFAULT; 1135 err = -EFAULT;
1136 goto out;
1137 }
1114 1138
1115 err = strict_strtol(strstrip(buffer), 0, &oom_score_adj); 1139 err = strict_strtol(strstrip(buffer), 0, &oom_score_adj);
1116 if (err) 1140 if (err)
1117 return -EINVAL; 1141 goto out;
1118 if (oom_score_adj < OOM_SCORE_ADJ_MIN || 1142 if (oom_score_adj < OOM_SCORE_ADJ_MIN ||
1119 oom_score_adj > OOM_SCORE_ADJ_MAX) 1143 oom_score_adj > OOM_SCORE_ADJ_MAX) {
1120 return -EINVAL; 1144 err = -EINVAL;
1145 goto out;
1146 }
1121 1147
1122 task = get_proc_task(file->f_path.dentry->d_inode); 1148 task = get_proc_task(file->f_path.dentry->d_inode);
1123 if (!task) 1149 if (!task) {
1124 return -ESRCH; 1150 err = -ESRCH;
1151 goto out;
1152 }
1153
1154 task_lock(task);
1155 if (!task->mm) {
1156 err = -EINVAL;
1157 goto err_task_lock;
1158 }
1159
1125 if (!lock_task_sighand(task, &flags)) { 1160 if (!lock_task_sighand(task, &flags)) {
1126 put_task_struct(task); 1161 err = -ESRCH;
1127 return -ESRCH; 1162 goto err_task_lock;
1128 } 1163 }
1164
1129 if (oom_score_adj < task->signal->oom_score_adj && 1165 if (oom_score_adj < task->signal->oom_score_adj &&
1130 !capable(CAP_SYS_RESOURCE)) { 1166 !capable(CAP_SYS_RESOURCE)) {
1131 unlock_task_sighand(task, &flags); 1167 err = -EACCES;
1132 put_task_struct(task); 1168 goto err_sighand;
1133 return -EACCES;
1134 } 1169 }
1135 1170
1171 if (oom_score_adj != task->signal->oom_score_adj) {
1172 if (oom_score_adj == OOM_SCORE_ADJ_MIN)
1173 atomic_inc(&task->mm->oom_disable_count);
1174 if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
1175 atomic_dec(&task->mm->oom_disable_count);
1176 }
1136 task->signal->oom_score_adj = oom_score_adj; 1177 task->signal->oom_score_adj = oom_score_adj;
1137 /* 1178 /*
1138 * Scale /proc/pid/oom_adj appropriately ensuring that OOM_DISABLE is 1179 * Scale /proc/pid/oom_adj appropriately ensuring that OOM_DISABLE is
@@ -1143,9 +1184,13 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
1143 else 1184 else
1144 task->signal->oom_adj = (oom_score_adj * OOM_ADJUST_MAX) / 1185 task->signal->oom_adj = (oom_score_adj * OOM_ADJUST_MAX) /
1145 OOM_SCORE_ADJ_MAX; 1186 OOM_SCORE_ADJ_MAX;
1187err_sighand:
1146 unlock_task_sighand(task, &flags); 1188 unlock_task_sighand(task, &flags);
1189err_task_lock:
1190 task_unlock(task);
1147 put_task_struct(task); 1191 put_task_struct(task);
1148 return count; 1192out:
1193 return err < 0 ? err : count;
1149} 1194}
1150 1195
1151static const struct file_operations proc_oom_score_adj_operations = { 1196static const struct file_operations proc_oom_score_adj_operations = {