diff options
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r-- | fs/proc/base.c | 168 |
1 files changed, 134 insertions, 34 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index aeaf0d0f2f51..33537487f5ab 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -199,9 +199,29 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf | |||
199 | (task == current || \ | 199 | (task == current || \ |
200 | (task->parent == current && \ | 200 | (task->parent == current && \ |
201 | (task->ptrace & PT_PTRACED) && \ | 201 | (task->ptrace & PT_PTRACED) && \ |
202 | (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \ | 202 | (task_is_stopped_or_traced(task)) && \ |
203 | security_ptrace(current,task) == 0)) | 203 | security_ptrace(current,task) == 0)) |
204 | 204 | ||
205 | struct mm_struct *mm_for_maps(struct task_struct *task) | ||
206 | { | ||
207 | struct mm_struct *mm = get_task_mm(task); | ||
208 | if (!mm) | ||
209 | return NULL; | ||
210 | down_read(&mm->mmap_sem); | ||
211 | task_lock(task); | ||
212 | if (task->mm != mm) | ||
213 | goto out; | ||
214 | if (task->mm != current->mm && __ptrace_may_attach(task) < 0) | ||
215 | goto out; | ||
216 | task_unlock(task); | ||
217 | return mm; | ||
218 | out: | ||
219 | task_unlock(task); | ||
220 | up_read(&mm->mmap_sem); | ||
221 | mmput(mm); | ||
222 | return NULL; | ||
223 | } | ||
224 | |||
205 | static int proc_pid_cmdline(struct task_struct *task, char * buffer) | 225 | static int proc_pid_cmdline(struct task_struct *task, char * buffer) |
206 | { | 226 | { |
207 | int res = 0; | 227 | int res = 0; |
@@ -290,6 +310,77 @@ static int proc_pid_schedstat(struct task_struct *task, char *buffer) | |||
290 | } | 310 | } |
291 | #endif | 311 | #endif |
292 | 312 | ||
313 | #ifdef CONFIG_LATENCYTOP | ||
314 | static int lstats_show_proc(struct seq_file *m, void *v) | ||
315 | { | ||
316 | int i; | ||
317 | struct task_struct *task = m->private; | ||
318 | seq_puts(m, "Latency Top version : v0.1\n"); | ||
319 | |||
320 | for (i = 0; i < 32; i++) { | ||
321 | if (task->latency_record[i].backtrace[0]) { | ||
322 | int q; | ||
323 | seq_printf(m, "%i %li %li ", | ||
324 | task->latency_record[i].count, | ||
325 | task->latency_record[i].time, | ||
326 | task->latency_record[i].max); | ||
327 | for (q = 0; q < LT_BACKTRACEDEPTH; q++) { | ||
328 | char sym[KSYM_NAME_LEN]; | ||
329 | char *c; | ||
330 | if (!task->latency_record[i].backtrace[q]) | ||
331 | break; | ||
332 | if (task->latency_record[i].backtrace[q] == ULONG_MAX) | ||
333 | break; | ||
334 | sprint_symbol(sym, task->latency_record[i].backtrace[q]); | ||
335 | c = strchr(sym, '+'); | ||
336 | if (c) | ||
337 | *c = 0; | ||
338 | seq_printf(m, "%s ", sym); | ||
339 | } | ||
340 | seq_printf(m, "\n"); | ||
341 | } | ||
342 | |||
343 | } | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static int lstats_open(struct inode *inode, struct file *file) | ||
348 | { | ||
349 | int ret; | ||
350 | struct seq_file *m; | ||
351 | struct task_struct *task = get_proc_task(inode); | ||
352 | |||
353 | ret = single_open(file, lstats_show_proc, NULL); | ||
354 | if (!ret) { | ||
355 | m = file->private_data; | ||
356 | m->private = task; | ||
357 | } | ||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | static ssize_t lstats_write(struct file *file, const char __user *buf, | ||
362 | size_t count, loff_t *offs) | ||
363 | { | ||
364 | struct seq_file *m; | ||
365 | struct task_struct *task; | ||
366 | |||
367 | m = file->private_data; | ||
368 | task = m->private; | ||
369 | clear_all_latency_tracing(task); | ||
370 | |||
371 | return count; | ||
372 | } | ||
373 | |||
374 | static const struct file_operations proc_lstats_operations = { | ||
375 | .open = lstats_open, | ||
376 | .read = seq_read, | ||
377 | .write = lstats_write, | ||
378 | .llseek = seq_lseek, | ||
379 | .release = single_release, | ||
380 | }; | ||
381 | |||
382 | #endif | ||
383 | |||
293 | /* The badness from the OOM killer */ | 384 | /* The badness from the OOM killer */ |
294 | unsigned long badness(struct task_struct *p, unsigned long uptime); | 385 | unsigned long badness(struct task_struct *p, unsigned long uptime); |
295 | static int proc_oom_score(struct task_struct *task, char *buffer) | 386 | static int proc_oom_score(struct task_struct *task, char *buffer) |
@@ -893,7 +984,7 @@ static ssize_t proc_loginuid_read(struct file * file, char __user * buf, | |||
893 | if (!task) | 984 | if (!task) |
894 | return -ESRCH; | 985 | return -ESRCH; |
895 | length = scnprintf(tmpbuf, TMPBUFLEN, "%u", | 986 | length = scnprintf(tmpbuf, TMPBUFLEN, "%u", |
896 | audit_get_loginuid(task->audit_context)); | 987 | audit_get_loginuid(task)); |
897 | put_task_struct(task); | 988 | put_task_struct(task); |
898 | return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); | 989 | return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); |
899 | } | 990 | } |
@@ -1000,6 +1091,7 @@ static const struct file_operations proc_fault_inject_operations = { | |||
1000 | }; | 1091 | }; |
1001 | #endif | 1092 | #endif |
1002 | 1093 | ||
1094 | |||
1003 | #ifdef CONFIG_SCHED_DEBUG | 1095 | #ifdef CONFIG_SCHED_DEBUG |
1004 | /* | 1096 | /* |
1005 | * Print out various scheduling related per-task fields: | 1097 | * Print out various scheduling related per-task fields: |
@@ -2210,6 +2302,9 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2210 | #ifdef CONFIG_SCHEDSTATS | 2302 | #ifdef CONFIG_SCHEDSTATS |
2211 | INF("schedstat", S_IRUGO, pid_schedstat), | 2303 | INF("schedstat", S_IRUGO, pid_schedstat), |
2212 | #endif | 2304 | #endif |
2305 | #ifdef CONFIG_LATENCYTOP | ||
2306 | REG("latency", S_IRUGO, lstats), | ||
2307 | #endif | ||
2213 | #ifdef CONFIG_PROC_PID_CPUSET | 2308 | #ifdef CONFIG_PROC_PID_CPUSET |
2214 | REG("cpuset", S_IRUGO, cpuset), | 2309 | REG("cpuset", S_IRUGO, cpuset), |
2215 | #endif | 2310 | #endif |
@@ -2328,21 +2423,18 @@ out: | |||
2328 | 2423 | ||
2329 | void proc_flush_task(struct task_struct *task) | 2424 | void proc_flush_task(struct task_struct *task) |
2330 | { | 2425 | { |
2331 | int i, leader; | 2426 | int i; |
2332 | struct pid *pid, *tgid; | 2427 | struct pid *pid, *tgid = NULL; |
2333 | struct upid *upid; | 2428 | struct upid *upid; |
2334 | 2429 | ||
2335 | leader = thread_group_leader(task); | ||
2336 | proc_flush_task_mnt(proc_mnt, task->pid, leader ? task->tgid : 0); | ||
2337 | pid = task_pid(task); | 2430 | pid = task_pid(task); |
2338 | if (pid->level == 0) | 2431 | if (thread_group_leader(task)) |
2339 | return; | 2432 | tgid = task_tgid(task); |
2340 | 2433 | ||
2341 | tgid = task_tgid(task); | 2434 | for (i = 0; i <= pid->level; i++) { |
2342 | for (i = 1; i <= pid->level; i++) { | ||
2343 | upid = &pid->numbers[i]; | 2435 | upid = &pid->numbers[i]; |
2344 | proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr, | 2436 | proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr, |
2345 | leader ? 0 : tgid->numbers[i].nr); | 2437 | tgid ? tgid->numbers[i].nr : 0); |
2346 | } | 2438 | } |
2347 | 2439 | ||
2348 | upid = &pid->numbers[pid->level]; | 2440 | upid = &pid->numbers[pid->level]; |
@@ -2414,19 +2506,23 @@ out: | |||
2414 | * Find the first task with tgid >= tgid | 2506 | * Find the first task with tgid >= tgid |
2415 | * | 2507 | * |
2416 | */ | 2508 | */ |
2417 | static struct task_struct *next_tgid(unsigned int tgid, | 2509 | struct tgid_iter { |
2418 | struct pid_namespace *ns) | 2510 | unsigned int tgid; |
2419 | { | ||
2420 | struct task_struct *task; | 2511 | struct task_struct *task; |
2512 | }; | ||
2513 | static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter iter) | ||
2514 | { | ||
2421 | struct pid *pid; | 2515 | struct pid *pid; |
2422 | 2516 | ||
2517 | if (iter.task) | ||
2518 | put_task_struct(iter.task); | ||
2423 | rcu_read_lock(); | 2519 | rcu_read_lock(); |
2424 | retry: | 2520 | retry: |
2425 | task = NULL; | 2521 | iter.task = NULL; |
2426 | pid = find_ge_pid(tgid, ns); | 2522 | pid = find_ge_pid(iter.tgid, ns); |
2427 | if (pid) { | 2523 | if (pid) { |
2428 | tgid = pid_nr_ns(pid, ns) + 1; | 2524 | iter.tgid = pid_nr_ns(pid, ns); |
2429 | task = pid_task(pid, PIDTYPE_PID); | 2525 | iter.task = pid_task(pid, PIDTYPE_PID); |
2430 | /* What we to know is if the pid we have find is the | 2526 | /* What we to know is if the pid we have find is the |
2431 | * pid of a thread_group_leader. Testing for task | 2527 | * pid of a thread_group_leader. Testing for task |
2432 | * being a thread_group_leader is the obvious thing | 2528 | * being a thread_group_leader is the obvious thing |
@@ -2439,23 +2535,25 @@ retry: | |||
2439 | * found doesn't happen to be a thread group leader. | 2535 | * found doesn't happen to be a thread group leader. |
2440 | * As we don't care in the case of readdir. | 2536 | * As we don't care in the case of readdir. |
2441 | */ | 2537 | */ |
2442 | if (!task || !has_group_leader_pid(task)) | 2538 | if (!iter.task || !has_group_leader_pid(iter.task)) { |
2539 | iter.tgid += 1; | ||
2443 | goto retry; | 2540 | goto retry; |
2444 | get_task_struct(task); | 2541 | } |
2542 | get_task_struct(iter.task); | ||
2445 | } | 2543 | } |
2446 | rcu_read_unlock(); | 2544 | rcu_read_unlock(); |
2447 | return task; | 2545 | return iter; |
2448 | } | 2546 | } |
2449 | 2547 | ||
2450 | #define TGID_OFFSET (FIRST_PROCESS_ENTRY + ARRAY_SIZE(proc_base_stuff)) | 2548 | #define TGID_OFFSET (FIRST_PROCESS_ENTRY + ARRAY_SIZE(proc_base_stuff)) |
2451 | 2549 | ||
2452 | static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | 2550 | static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir, |
2453 | struct task_struct *task, int tgid) | 2551 | struct tgid_iter iter) |
2454 | { | 2552 | { |
2455 | char name[PROC_NUMBUF]; | 2553 | char name[PROC_NUMBUF]; |
2456 | int len = snprintf(name, sizeof(name), "%d", tgid); | 2554 | int len = snprintf(name, sizeof(name), "%d", iter.tgid); |
2457 | return proc_fill_cache(filp, dirent, filldir, name, len, | 2555 | return proc_fill_cache(filp, dirent, filldir, name, len, |
2458 | proc_pid_instantiate, task, NULL); | 2556 | proc_pid_instantiate, iter.task, NULL); |
2459 | } | 2557 | } |
2460 | 2558 | ||
2461 | /* for the /proc/ directory itself, after non-process stuff has been done */ | 2559 | /* for the /proc/ directory itself, after non-process stuff has been done */ |
@@ -2463,8 +2561,7 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
2463 | { | 2561 | { |
2464 | unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY; | 2562 | unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY; |
2465 | struct task_struct *reaper = get_proc_task(filp->f_path.dentry->d_inode); | 2563 | struct task_struct *reaper = get_proc_task(filp->f_path.dentry->d_inode); |
2466 | struct task_struct *task; | 2564 | struct tgid_iter iter; |
2467 | int tgid; | ||
2468 | struct pid_namespace *ns; | 2565 | struct pid_namespace *ns; |
2469 | 2566 | ||
2470 | if (!reaper) | 2567 | if (!reaper) |
@@ -2477,14 +2574,14 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
2477 | } | 2574 | } |
2478 | 2575 | ||
2479 | ns = filp->f_dentry->d_sb->s_fs_info; | 2576 | ns = filp->f_dentry->d_sb->s_fs_info; |
2480 | tgid = filp->f_pos - TGID_OFFSET; | 2577 | iter.task = NULL; |
2481 | for (task = next_tgid(tgid, ns); | 2578 | iter.tgid = filp->f_pos - TGID_OFFSET; |
2482 | task; | 2579 | for (iter = next_tgid(ns, iter); |
2483 | put_task_struct(task), task = next_tgid(tgid + 1, ns)) { | 2580 | iter.task; |
2484 | tgid = task_pid_nr_ns(task, ns); | 2581 | iter.tgid += 1, iter = next_tgid(ns, iter)) { |
2485 | filp->f_pos = tgid + TGID_OFFSET; | 2582 | filp->f_pos = iter.tgid + TGID_OFFSET; |
2486 | if (proc_pid_fill_cache(filp, dirent, filldir, task, tgid) < 0) { | 2583 | if (proc_pid_fill_cache(filp, dirent, filldir, iter) < 0) { |
2487 | put_task_struct(task); | 2584 | put_task_struct(iter.task); |
2488 | goto out; | 2585 | goto out; |
2489 | } | 2586 | } |
2490 | } | 2587 | } |
@@ -2533,6 +2630,9 @@ static const struct pid_entry tid_base_stuff[] = { | |||
2533 | #ifdef CONFIG_SCHEDSTATS | 2630 | #ifdef CONFIG_SCHEDSTATS |
2534 | INF("schedstat", S_IRUGO, pid_schedstat), | 2631 | INF("schedstat", S_IRUGO, pid_schedstat), |
2535 | #endif | 2632 | #endif |
2633 | #ifdef CONFIG_LATENCYTOP | ||
2634 | REG("latency", S_IRUGO, lstats), | ||
2635 | #endif | ||
2536 | #ifdef CONFIG_PROC_PID_CPUSET | 2636 | #ifdef CONFIG_PROC_PID_CPUSET |
2537 | REG("cpuset", S_IRUGO, cpuset), | 2637 | REG("cpuset", S_IRUGO, cpuset), |
2538 | #endif | 2638 | #endif |