diff options
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r-- | fs/proc/base.c | 146 |
1 files changed, 122 insertions, 24 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 8418fcc0a6ab..c806dfb24e08 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -63,6 +63,7 @@ | |||
63 | #include <linux/namei.h> | 63 | #include <linux/namei.h> |
64 | #include <linux/mnt_namespace.h> | 64 | #include <linux/mnt_namespace.h> |
65 | #include <linux/mm.h> | 65 | #include <linux/mm.h> |
66 | #include <linux/swap.h> | ||
66 | #include <linux/rcupdate.h> | 67 | #include <linux/rcupdate.h> |
67 | #include <linux/kallsyms.h> | 68 | #include <linux/kallsyms.h> |
68 | #include <linux/stacktrace.h> | 69 | #include <linux/stacktrace.h> |
@@ -166,18 +167,6 @@ static int get_fs_path(struct task_struct *task, struct path *path, bool root) | |||
166 | return result; | 167 | return result; |
167 | } | 168 | } |
168 | 169 | ||
169 | static int get_nr_threads(struct task_struct *tsk) | ||
170 | { | ||
171 | unsigned long flags; | ||
172 | int count = 0; | ||
173 | |||
174 | if (lock_task_sighand(tsk, &flags)) { | ||
175 | count = atomic_read(&tsk->signal->count); | ||
176 | unlock_task_sighand(tsk, &flags); | ||
177 | } | ||
178 | return count; | ||
179 | } | ||
180 | |||
181 | static int proc_cwd_link(struct inode *inode, struct path *path) | 170 | static int proc_cwd_link(struct inode *inode, struct path *path) |
182 | { | 171 | { |
183 | struct task_struct *task = get_proc_task(inode); | 172 | struct task_struct *task = get_proc_task(inode); |
@@ -439,17 +428,14 @@ static const struct file_operations proc_lstats_operations = { | |||
439 | 428 | ||
440 | #endif | 429 | #endif |
441 | 430 | ||
442 | /* The badness from the OOM killer */ | ||
443 | unsigned long badness(struct task_struct *p, unsigned long uptime); | ||
444 | static int proc_oom_score(struct task_struct *task, char *buffer) | 431 | static int proc_oom_score(struct task_struct *task, char *buffer) |
445 | { | 432 | { |
446 | unsigned long points = 0; | 433 | unsigned long points = 0; |
447 | struct timespec uptime; | ||
448 | 434 | ||
449 | do_posix_clock_monotonic_gettime(&uptime); | ||
450 | read_lock(&tasklist_lock); | 435 | read_lock(&tasklist_lock); |
451 | if (pid_alive(task)) | 436 | if (pid_alive(task)) |
452 | points = badness(task, uptime.tv_sec); | 437 | points = oom_badness(task, NULL, NULL, |
438 | totalram_pages + total_swap_pages); | ||
453 | read_unlock(&tasklist_lock); | 439 | read_unlock(&tasklist_lock); |
454 | return sprintf(buffer, "%lu\n", points); | 440 | return sprintf(buffer, "%lu\n", points); |
455 | } | 441 | } |
@@ -573,9 +559,19 @@ static int proc_setattr(struct dentry *dentry, struct iattr *attr) | |||
573 | return -EPERM; | 559 | return -EPERM; |
574 | 560 | ||
575 | error = inode_change_ok(inode, attr); | 561 | error = inode_change_ok(inode, attr); |
576 | if (!error) | 562 | if (error) |
577 | error = inode_setattr(inode, attr); | 563 | return error; |
578 | return error; | 564 | |
565 | if ((attr->ia_valid & ATTR_SIZE) && | ||
566 | attr->ia_size != i_size_read(inode)) { | ||
567 | error = vmtruncate(inode, attr->ia_size); | ||
568 | if (error) | ||
569 | return error; | ||
570 | } | ||
571 | |||
572 | setattr_copy(inode, attr); | ||
573 | mark_inode_dirty(inode); | ||
574 | return 0; | ||
579 | } | 575 | } |
580 | 576 | ||
581 | static const struct inode_operations proc_def_inode_operations = { | 577 | static const struct inode_operations proc_def_inode_operations = { |
@@ -730,6 +726,7 @@ out_no_task: | |||
730 | 726 | ||
731 | static const struct file_operations proc_info_file_operations = { | 727 | static const struct file_operations proc_info_file_operations = { |
732 | .read = proc_info_read, | 728 | .read = proc_info_read, |
729 | .llseek = generic_file_llseek, | ||
733 | }; | 730 | }; |
734 | 731 | ||
735 | static int proc_single_show(struct seq_file *m, void *v) | 732 | static int proc_single_show(struct seq_file *m, void *v) |
@@ -987,6 +984,7 @@ out_no_task: | |||
987 | 984 | ||
988 | static const struct file_operations proc_environ_operations = { | 985 | static const struct file_operations proc_environ_operations = { |
989 | .read = environ_read, | 986 | .read = environ_read, |
987 | .llseek = generic_file_llseek, | ||
990 | }; | 988 | }; |
991 | 989 | ||
992 | static ssize_t oom_adjust_read(struct file *file, char __user *buf, | 990 | static ssize_t oom_adjust_read(struct file *file, char __user *buf, |
@@ -1049,8 +1047,24 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, | |||
1049 | return -EACCES; | 1047 | return -EACCES; |
1050 | } | 1048 | } |
1051 | 1049 | ||
1050 | /* | ||
1051 | * Warn that /proc/pid/oom_adj is deprecated, see | ||
1052 | * Documentation/feature-removal-schedule.txt. | ||
1053 | */ | ||
1054 | printk_once(KERN_WARNING "%s (%d): /proc/%d/oom_adj is deprecated, " | ||
1055 | "please use /proc/%d/oom_score_adj instead.\n", | ||
1056 | current->comm, task_pid_nr(current), | ||
1057 | task_pid_nr(task), task_pid_nr(task)); | ||
1052 | task->signal->oom_adj = oom_adjust; | 1058 | task->signal->oom_adj = oom_adjust; |
1053 | 1059 | /* | |
1060 | * Scale /proc/pid/oom_score_adj appropriately ensuring that a maximum | ||
1061 | * value is always attainable. | ||
1062 | */ | ||
1063 | if (task->signal->oom_adj == OOM_ADJUST_MAX) | ||
1064 | task->signal->oom_score_adj = OOM_SCORE_ADJ_MAX; | ||
1065 | else | ||
1066 | task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) / | ||
1067 | -OOM_DISABLE; | ||
1054 | unlock_task_sighand(task, &flags); | 1068 | unlock_task_sighand(task, &flags); |
1055 | put_task_struct(task); | 1069 | put_task_struct(task); |
1056 | 1070 | ||
@@ -1060,6 +1074,83 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, | |||
1060 | static const struct file_operations proc_oom_adjust_operations = { | 1074 | static const struct file_operations proc_oom_adjust_operations = { |
1061 | .read = oom_adjust_read, | 1075 | .read = oom_adjust_read, |
1062 | .write = oom_adjust_write, | 1076 | .write = oom_adjust_write, |
1077 | .llseek = generic_file_llseek, | ||
1078 | }; | ||
1079 | |||
1080 | static ssize_t oom_score_adj_read(struct file *file, char __user *buf, | ||
1081 | size_t count, loff_t *ppos) | ||
1082 | { | ||
1083 | struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); | ||
1084 | char buffer[PROC_NUMBUF]; | ||
1085 | int oom_score_adj = OOM_SCORE_ADJ_MIN; | ||
1086 | unsigned long flags; | ||
1087 | size_t len; | ||
1088 | |||
1089 | if (!task) | ||
1090 | return -ESRCH; | ||
1091 | if (lock_task_sighand(task, &flags)) { | ||
1092 | oom_score_adj = task->signal->oom_score_adj; | ||
1093 | unlock_task_sighand(task, &flags); | ||
1094 | } | ||
1095 | put_task_struct(task); | ||
1096 | len = snprintf(buffer, sizeof(buffer), "%d\n", oom_score_adj); | ||
1097 | return simple_read_from_buffer(buf, count, ppos, buffer, len); | ||
1098 | } | ||
1099 | |||
1100 | static ssize_t oom_score_adj_write(struct file *file, const char __user *buf, | ||
1101 | size_t count, loff_t *ppos) | ||
1102 | { | ||
1103 | struct task_struct *task; | ||
1104 | char buffer[PROC_NUMBUF]; | ||
1105 | unsigned long flags; | ||
1106 | long oom_score_adj; | ||
1107 | int err; | ||
1108 | |||
1109 | memset(buffer, 0, sizeof(buffer)); | ||
1110 | if (count > sizeof(buffer) - 1) | ||
1111 | count = sizeof(buffer) - 1; | ||
1112 | if (copy_from_user(buffer, buf, count)) | ||
1113 | return -EFAULT; | ||
1114 | |||
1115 | err = strict_strtol(strstrip(buffer), 0, &oom_score_adj); | ||
1116 | if (err) | ||
1117 | return -EINVAL; | ||
1118 | if (oom_score_adj < OOM_SCORE_ADJ_MIN || | ||
1119 | oom_score_adj > OOM_SCORE_ADJ_MAX) | ||
1120 | return -EINVAL; | ||
1121 | |||
1122 | task = get_proc_task(file->f_path.dentry->d_inode); | ||
1123 | if (!task) | ||
1124 | return -ESRCH; | ||
1125 | if (!lock_task_sighand(task, &flags)) { | ||
1126 | put_task_struct(task); | ||
1127 | return -ESRCH; | ||
1128 | } | ||
1129 | if (oom_score_adj < task->signal->oom_score_adj && | ||
1130 | !capable(CAP_SYS_RESOURCE)) { | ||
1131 | unlock_task_sighand(task, &flags); | ||
1132 | put_task_struct(task); | ||
1133 | return -EACCES; | ||
1134 | } | ||
1135 | |||
1136 | task->signal->oom_score_adj = oom_score_adj; | ||
1137 | /* | ||
1138 | * Scale /proc/pid/oom_adj appropriately ensuring that OOM_DISABLE is | ||
1139 | * always attainable. | ||
1140 | */ | ||
1141 | if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) | ||
1142 | task->signal->oom_adj = OOM_DISABLE; | ||
1143 | else | ||
1144 | task->signal->oom_adj = (oom_score_adj * OOM_ADJUST_MAX) / | ||
1145 | OOM_SCORE_ADJ_MAX; | ||
1146 | unlock_task_sighand(task, &flags); | ||
1147 | put_task_struct(task); | ||
1148 | return count; | ||
1149 | } | ||
1150 | |||
1151 | static const struct file_operations proc_oom_score_adj_operations = { | ||
1152 | .read = oom_score_adj_read, | ||
1153 | .write = oom_score_adj_write, | ||
1063 | }; | 1154 | }; |
1064 | 1155 | ||
1065 | #ifdef CONFIG_AUDITSYSCALL | 1156 | #ifdef CONFIG_AUDITSYSCALL |
@@ -1131,6 +1222,7 @@ out_free_page: | |||
1131 | static const struct file_operations proc_loginuid_operations = { | 1222 | static const struct file_operations proc_loginuid_operations = { |
1132 | .read = proc_loginuid_read, | 1223 | .read = proc_loginuid_read, |
1133 | .write = proc_loginuid_write, | 1224 | .write = proc_loginuid_write, |
1225 | .llseek = generic_file_llseek, | ||
1134 | }; | 1226 | }; |
1135 | 1227 | ||
1136 | static ssize_t proc_sessionid_read(struct file * file, char __user * buf, | 1228 | static ssize_t proc_sessionid_read(struct file * file, char __user * buf, |
@@ -1151,6 +1243,7 @@ static ssize_t proc_sessionid_read(struct file * file, char __user * buf, | |||
1151 | 1243 | ||
1152 | static const struct file_operations proc_sessionid_operations = { | 1244 | static const struct file_operations proc_sessionid_operations = { |
1153 | .read = proc_sessionid_read, | 1245 | .read = proc_sessionid_read, |
1246 | .llseek = generic_file_llseek, | ||
1154 | }; | 1247 | }; |
1155 | #endif | 1248 | #endif |
1156 | 1249 | ||
@@ -1202,6 +1295,7 @@ static ssize_t proc_fault_inject_write(struct file * file, | |||
1202 | static const struct file_operations proc_fault_inject_operations = { | 1295 | static const struct file_operations proc_fault_inject_operations = { |
1203 | .read = proc_fault_inject_read, | 1296 | .read = proc_fault_inject_read, |
1204 | .write = proc_fault_inject_write, | 1297 | .write = proc_fault_inject_write, |
1298 | .llseek = generic_file_llseek, | ||
1205 | }; | 1299 | }; |
1206 | #endif | 1300 | #endif |
1207 | 1301 | ||
@@ -1943,7 +2037,7 @@ static ssize_t proc_fdinfo_read(struct file *file, char __user *buf, | |||
1943 | } | 2037 | } |
1944 | 2038 | ||
1945 | static const struct file_operations proc_fdinfo_file_operations = { | 2039 | static const struct file_operations proc_fdinfo_file_operations = { |
1946 | .open = nonseekable_open, | 2040 | .open = nonseekable_open, |
1947 | .read = proc_fdinfo_read, | 2041 | .read = proc_fdinfo_read, |
1948 | }; | 2042 | }; |
1949 | 2043 | ||
@@ -2227,6 +2321,7 @@ out_no_task: | |||
2227 | static const struct file_operations proc_pid_attr_operations = { | 2321 | static const struct file_operations proc_pid_attr_operations = { |
2228 | .read = proc_pid_attr_read, | 2322 | .read = proc_pid_attr_read, |
2229 | .write = proc_pid_attr_write, | 2323 | .write = proc_pid_attr_write, |
2324 | .llseek = generic_file_llseek, | ||
2230 | }; | 2325 | }; |
2231 | 2326 | ||
2232 | static const struct pid_entry attr_dir_stuff[] = { | 2327 | static const struct pid_entry attr_dir_stuff[] = { |
@@ -2347,6 +2442,7 @@ static ssize_t proc_coredump_filter_write(struct file *file, | |||
2347 | static const struct file_operations proc_coredump_filter_operations = { | 2442 | static const struct file_operations proc_coredump_filter_operations = { |
2348 | .read = proc_coredump_filter_read, | 2443 | .read = proc_coredump_filter_read, |
2349 | .write = proc_coredump_filter_write, | 2444 | .write = proc_coredump_filter_write, |
2445 | .llseek = generic_file_llseek, | ||
2350 | }; | 2446 | }; |
2351 | #endif | 2447 | #endif |
2352 | 2448 | ||
@@ -2436,7 +2532,7 @@ static struct dentry *proc_base_instantiate(struct inode *dir, | |||
2436 | const struct pid_entry *p = ptr; | 2532 | const struct pid_entry *p = ptr; |
2437 | struct inode *inode; | 2533 | struct inode *inode; |
2438 | struct proc_inode *ei; | 2534 | struct proc_inode *ei; |
2439 | struct dentry *error = ERR_PTR(-EINVAL); | 2535 | struct dentry *error; |
2440 | 2536 | ||
2441 | /* Allocate the inode */ | 2537 | /* Allocate the inode */ |
2442 | error = ERR_PTR(-ENOMEM); | 2538 | error = ERR_PTR(-ENOMEM); |
@@ -2629,6 +2725,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2629 | #endif | 2725 | #endif |
2630 | INF("oom_score", S_IRUGO, proc_oom_score), | 2726 | INF("oom_score", S_IRUGO, proc_oom_score), |
2631 | REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_operations), | 2727 | REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_operations), |
2728 | REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), | ||
2632 | #ifdef CONFIG_AUDITSYSCALL | 2729 | #ifdef CONFIG_AUDITSYSCALL |
2633 | REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), | 2730 | REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), |
2634 | REG("sessionid", S_IRUGO, proc_sessionid_operations), | 2731 | REG("sessionid", S_IRUGO, proc_sessionid_operations), |
@@ -2786,7 +2883,7 @@ out: | |||
2786 | 2883 | ||
2787 | struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) | 2884 | struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) |
2788 | { | 2885 | { |
2789 | struct dentry *result = ERR_PTR(-ENOENT); | 2886 | struct dentry *result; |
2790 | struct task_struct *task; | 2887 | struct task_struct *task; |
2791 | unsigned tgid; | 2888 | unsigned tgid; |
2792 | struct pid_namespace *ns; | 2889 | struct pid_namespace *ns; |
@@ -2963,6 +3060,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
2963 | #endif | 3060 | #endif |
2964 | INF("oom_score", S_IRUGO, proc_oom_score), | 3061 | INF("oom_score", S_IRUGO, proc_oom_score), |
2965 | REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_operations), | 3062 | REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_operations), |
3063 | REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), | ||
2966 | #ifdef CONFIG_AUDITSYSCALL | 3064 | #ifdef CONFIG_AUDITSYSCALL |
2967 | REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), | 3065 | REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), |
2968 | REG("sessionid", S_IRUSR, proc_sessionid_operations), | 3066 | REG("sessionid", S_IRUSR, proc_sessionid_operations), |