diff options
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r-- | fs/proc/base.c | 99 |
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; |
1087 | err_sighand: | ||
1068 | unlock_task_sighand(task, &flags); | 1088 | unlock_task_sighand(task, &flags); |
1089 | err_task_lock: | ||
1090 | task_unlock(task); | ||
1069 | put_task_struct(task); | 1091 | put_task_struct(task); |
1070 | 1092 | out: | |
1071 | return count; | 1093 | return err < 0 ? err : count; |
1072 | } | 1094 | } |
1073 | 1095 | ||
1074 | static const struct file_operations proc_oom_adjust_operations = { | 1096 | static 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; |
1187 | err_sighand: | ||
1146 | unlock_task_sighand(task, &flags); | 1188 | unlock_task_sighand(task, &flags); |
1189 | err_task_lock: | ||
1190 | task_unlock(task); | ||
1147 | put_task_struct(task); | 1191 | put_task_struct(task); |
1148 | return count; | 1192 | out: |
1193 | return err < 0 ? err : count; | ||
1149 | } | 1194 | } |
1150 | 1195 | ||
1151 | static const struct file_operations proc_oom_score_adj_operations = { | 1196 | static const struct file_operations proc_oom_score_adj_operations = { |