.. | .. |
---|
14 | 14 | */ |
---|
15 | 15 | |
---|
16 | 16 | #include <linux/atomic.h> |
---|
17 | | -#include <linux/cpufreq_times.h> |
---|
18 | 17 | #include <linux/err.h> |
---|
19 | 18 | #include <linux/hashtable.h> |
---|
20 | 19 | #include <linux/init.h> |
---|
.. | .. |
---|
78 | 77 | #endif |
---|
79 | 78 | }; |
---|
80 | 79 | |
---|
81 | | -static u64 compute_write_bytes(struct task_struct *task) |
---|
| 80 | +static u64 compute_write_bytes(struct task_io_accounting *ioac) |
---|
82 | 81 | { |
---|
83 | | - if (task->ioac.write_bytes <= task->ioac.cancelled_write_bytes) |
---|
| 82 | + if (ioac->write_bytes <= ioac->cancelled_write_bytes) |
---|
84 | 83 | return 0; |
---|
85 | 84 | |
---|
86 | | - return task->ioac.write_bytes - task->ioac.cancelled_write_bytes; |
---|
| 85 | + return ioac->write_bytes - ioac->cancelled_write_bytes; |
---|
87 | 86 | } |
---|
88 | 87 | |
---|
89 | 88 | static void compute_io_bucket_stats(struct io_stats *io_bucket, |
---|
.. | .. |
---|
137 | 136 | |
---|
138 | 137 | /* next the executable file name */ |
---|
139 | 138 | if (mm) { |
---|
140 | | - down_read(&mm->mmap_sem); |
---|
| 139 | + mmap_write_lock(mm); |
---|
141 | 140 | if (mm->exe_file) { |
---|
142 | 141 | char *pathname = d_path(&mm->exe_file->f_path, buf, |
---|
143 | 142 | unused_len); |
---|
.. | .. |
---|
150 | 149 | unused_len--; |
---|
151 | 150 | } |
---|
152 | 151 | } |
---|
153 | | - up_read(&mm->mmap_sem); |
---|
| 152 | + mmap_write_unlock(mm); |
---|
154 | 153 | } |
---|
155 | 154 | unused_len -= len; |
---|
156 | 155 | |
---|
.. | .. |
---|
240 | 239 | } |
---|
241 | 240 | } |
---|
242 | 241 | |
---|
243 | | -static void add_uid_tasks_io_stats(struct uid_entry *uid_entry, |
---|
244 | | - struct task_struct *task, int slot) |
---|
| 242 | +static void add_uid_tasks_io_stats(struct task_entry *task_entry, |
---|
| 243 | + struct task_io_accounting *ioac, int slot) |
---|
245 | 244 | { |
---|
246 | | - struct task_entry *task_entry = find_or_register_task(uid_entry, task); |
---|
247 | 245 | struct io_stats *task_io_slot = &task_entry->io[slot]; |
---|
248 | 246 | |
---|
249 | | - task_io_slot->read_bytes += task->ioac.read_bytes; |
---|
250 | | - task_io_slot->write_bytes += compute_write_bytes(task); |
---|
251 | | - task_io_slot->rchar += task->ioac.rchar; |
---|
252 | | - task_io_slot->wchar += task->ioac.wchar; |
---|
253 | | - task_io_slot->fsync += task->ioac.syscfs; |
---|
| 247 | + task_io_slot->read_bytes += ioac->read_bytes; |
---|
| 248 | + task_io_slot->write_bytes += compute_write_bytes(ioac); |
---|
| 249 | + task_io_slot->rchar += ioac->rchar; |
---|
| 250 | + task_io_slot->wchar += ioac->wchar; |
---|
| 251 | + task_io_slot->fsync += ioac->syscfs; |
---|
254 | 252 | } |
---|
255 | 253 | |
---|
256 | 254 | static void compute_io_uid_tasks(struct uid_entry *uid_entry) |
---|
.. | .. |
---|
291 | 289 | #else |
---|
292 | 290 | static void remove_uid_tasks(struct uid_entry *uid_entry) {}; |
---|
293 | 291 | static void set_io_uid_tasks_zero(struct uid_entry *uid_entry) {}; |
---|
294 | | -static void add_uid_tasks_io_stats(struct uid_entry *uid_entry, |
---|
295 | | - struct task_struct *task, int slot) {}; |
---|
296 | 292 | static void compute_io_uid_tasks(struct uid_entry *uid_entry) {}; |
---|
297 | 293 | static void show_io_uid_tasks(struct seq_file *m, |
---|
298 | 294 | struct uid_entry *uid_entry) {} |
---|
.. | .. |
---|
385 | 381 | return single_open(file, uid_cputime_show, PDE_DATA(inode)); |
---|
386 | 382 | } |
---|
387 | 383 | |
---|
388 | | -static const struct file_operations uid_cputime_fops = { |
---|
389 | | - .open = uid_cputime_open, |
---|
390 | | - .read = seq_read, |
---|
391 | | - .llseek = seq_lseek, |
---|
392 | | - .release = single_release, |
---|
| 384 | +static const struct proc_ops uid_cputime_fops = { |
---|
| 385 | + .proc_open = uid_cputime_open, |
---|
| 386 | + .proc_read = seq_read, |
---|
| 387 | + .proc_lseek = seq_lseek, |
---|
| 388 | + .proc_release = single_release, |
---|
393 | 389 | }; |
---|
394 | 390 | |
---|
395 | 391 | static int uid_remove_open(struct inode *inode, struct file *file) |
---|
.. | .. |
---|
404 | 400 | struct hlist_node *tmp; |
---|
405 | 401 | char uids[128]; |
---|
406 | 402 | char *start_uid, *end_uid = NULL; |
---|
407 | | - uid_t uid_start = 0, uid_end = 0; |
---|
408 | | - u64 uid; |
---|
| 403 | + long int uid_start = 0, uid_end = 0; |
---|
409 | 404 | |
---|
410 | 405 | if (count >= sizeof(uids)) |
---|
411 | 406 | count = sizeof(uids) - 1; |
---|
.. | .. |
---|
420 | 415 | if (!start_uid || !end_uid) |
---|
421 | 416 | return -EINVAL; |
---|
422 | 417 | |
---|
423 | | - if (kstrtouint(start_uid, 10, &uid_start) != 0 || |
---|
424 | | - kstrtouint(end_uid, 10, &uid_end) != 0) { |
---|
| 418 | + if (kstrtol(start_uid, 10, &uid_start) != 0 || |
---|
| 419 | + kstrtol(end_uid, 10, &uid_end) != 0) { |
---|
425 | 420 | return -EINVAL; |
---|
426 | 421 | } |
---|
427 | 422 | |
---|
428 | | - /* Also remove uids from /proc/uid_time_in_state */ |
---|
429 | | - cpufreq_task_times_remove_uids(uid_start, uid_end); |
---|
430 | | - |
---|
431 | 423 | rt_mutex_lock(&uid_lock); |
---|
432 | 424 | |
---|
433 | | - for (uid = uid_start; uid <= uid_end; uid++) { |
---|
| 425 | + for (; uid_start <= uid_end; uid_start++) { |
---|
434 | 426 | hash_for_each_possible_safe(hash_table, uid_entry, tmp, |
---|
435 | | - hash, uid) { |
---|
436 | | - if (uid == uid_entry->uid) { |
---|
| 427 | + hash, (uid_t)uid_start) { |
---|
| 428 | + if (uid_start == uid_entry->uid) { |
---|
437 | 429 | remove_uid_tasks(uid_entry); |
---|
438 | 430 | hash_del(&uid_entry->hash); |
---|
439 | 431 | kfree(uid_entry); |
---|
.. | .. |
---|
445 | 437 | return count; |
---|
446 | 438 | } |
---|
447 | 439 | |
---|
448 | | -static const struct file_operations uid_remove_fops = { |
---|
449 | | - .open = uid_remove_open, |
---|
450 | | - .release = single_release, |
---|
451 | | - .write = uid_remove_write, |
---|
| 440 | +static const struct proc_ops uid_remove_fops = { |
---|
| 441 | + .proc_open = uid_remove_open, |
---|
| 442 | + .proc_release = single_release, |
---|
| 443 | + .proc_write = uid_remove_write, |
---|
452 | 444 | }; |
---|
453 | 445 | |
---|
| 446 | +static void __add_uid_io_stats(struct uid_entry *uid_entry, |
---|
| 447 | + struct task_io_accounting *ioac, int slot) |
---|
| 448 | +{ |
---|
| 449 | + struct io_stats *io_slot = &uid_entry->io[slot]; |
---|
| 450 | + |
---|
| 451 | + io_slot->read_bytes += ioac->read_bytes; |
---|
| 452 | + io_slot->write_bytes += compute_write_bytes(ioac); |
---|
| 453 | + io_slot->rchar += ioac->rchar; |
---|
| 454 | + io_slot->wchar += ioac->wchar; |
---|
| 455 | + io_slot->fsync += ioac->syscfs; |
---|
| 456 | +} |
---|
454 | 457 | |
---|
455 | 458 | static void add_uid_io_stats(struct uid_entry *uid_entry, |
---|
456 | 459 | struct task_struct *task, int slot) |
---|
457 | 460 | { |
---|
458 | | - struct io_stats *io_slot = &uid_entry->io[slot]; |
---|
| 461 | + struct task_entry *task_entry __maybe_unused; |
---|
459 | 462 | |
---|
460 | 463 | /* avoid double accounting of dying threads */ |
---|
461 | 464 | if (slot != UID_STATE_DEAD_TASKS && (task->flags & PF_EXITING)) |
---|
462 | 465 | return; |
---|
463 | 466 | |
---|
464 | | - io_slot->read_bytes += task->ioac.read_bytes; |
---|
465 | | - io_slot->write_bytes += compute_write_bytes(task); |
---|
466 | | - io_slot->rchar += task->ioac.rchar; |
---|
467 | | - io_slot->wchar += task->ioac.wchar; |
---|
468 | | - io_slot->fsync += task->ioac.syscfs; |
---|
469 | | - |
---|
470 | | - add_uid_tasks_io_stats(uid_entry, task, slot); |
---|
| 467 | +#ifdef CONFIG_UID_SYS_STATS_DEBUG |
---|
| 468 | + task_entry = find_or_register_task(uid_entry, task); |
---|
| 469 | + add_uid_tasks_io_stats(task_entry, &task->ioac, slot); |
---|
| 470 | +#endif |
---|
| 471 | + __add_uid_io_stats(uid_entry, &task->ioac, slot); |
---|
471 | 472 | } |
---|
472 | 473 | |
---|
473 | 474 | static void update_io_stats_all_locked(void) |
---|
.. | .. |
---|
564 | 565 | return single_open(file, uid_io_show, PDE_DATA(inode)); |
---|
565 | 566 | } |
---|
566 | 567 | |
---|
567 | | -static const struct file_operations uid_io_fops = { |
---|
568 | | - .open = uid_io_open, |
---|
569 | | - .read = seq_read, |
---|
570 | | - .llseek = seq_lseek, |
---|
571 | | - .release = single_release, |
---|
| 568 | +static const struct proc_ops uid_io_fops = { |
---|
| 569 | + .proc_open = uid_io_open, |
---|
| 570 | + .proc_read = seq_read, |
---|
| 571 | + .proc_lseek = seq_lseek, |
---|
| 572 | + .proc_release = single_release, |
---|
572 | 573 | }; |
---|
573 | 574 | |
---|
574 | 575 | static int uid_procstat_open(struct inode *inode, struct file *file) |
---|
.. | .. |
---|
621 | 622 | return count; |
---|
622 | 623 | } |
---|
623 | 624 | |
---|
624 | | -static const struct file_operations uid_procstat_fops = { |
---|
625 | | - .open = uid_procstat_open, |
---|
626 | | - .release = single_release, |
---|
627 | | - .write = uid_procstat_write, |
---|
| 625 | +static const struct proc_ops uid_procstat_fops = { |
---|
| 626 | + .proc_open = uid_procstat_open, |
---|
| 627 | + .proc_release = single_release, |
---|
| 628 | + .proc_write = uid_procstat_write, |
---|
628 | 629 | }; |
---|
| 630 | + |
---|
| 631 | +struct update_stats_work { |
---|
| 632 | + struct work_struct work; |
---|
| 633 | + uid_t uid; |
---|
| 634 | +#ifdef CONFIG_UID_SYS_STATS_DEBUG |
---|
| 635 | + struct task_struct *task; |
---|
| 636 | +#endif |
---|
| 637 | + struct task_io_accounting ioac; |
---|
| 638 | + u64 utime; |
---|
| 639 | + u64 stime; |
---|
| 640 | +}; |
---|
| 641 | + |
---|
| 642 | +static void update_stats_workfn(struct work_struct *work) |
---|
| 643 | +{ |
---|
| 644 | + struct update_stats_work *usw = |
---|
| 645 | + container_of(work, struct update_stats_work, work); |
---|
| 646 | + struct uid_entry *uid_entry; |
---|
| 647 | + struct task_entry *task_entry __maybe_unused; |
---|
| 648 | + |
---|
| 649 | + rt_mutex_lock(&uid_lock); |
---|
| 650 | + uid_entry = find_uid_entry(usw->uid); |
---|
| 651 | + if (!uid_entry) |
---|
| 652 | + goto exit; |
---|
| 653 | + |
---|
| 654 | + uid_entry->utime += usw->utime; |
---|
| 655 | + uid_entry->stime += usw->stime; |
---|
| 656 | + |
---|
| 657 | +#ifdef CONFIG_UID_SYS_STATS_DEBUG |
---|
| 658 | + task_entry = find_task_entry(uid_entry, usw->task); |
---|
| 659 | + if (!task_entry) |
---|
| 660 | + goto exit; |
---|
| 661 | + add_uid_tasks_io_stats(task_entry, &usw->ioac, |
---|
| 662 | + UID_STATE_DEAD_TASKS); |
---|
| 663 | +#endif |
---|
| 664 | + __add_uid_io_stats(uid_entry, &usw->ioac, UID_STATE_DEAD_TASKS); |
---|
| 665 | +exit: |
---|
| 666 | + rt_mutex_unlock(&uid_lock); |
---|
| 667 | +#ifdef CONFIG_UID_SYS_STATS_DEBUG |
---|
| 668 | + put_task_struct(usw->task); |
---|
| 669 | +#endif |
---|
| 670 | + kfree(usw); |
---|
| 671 | +} |
---|
629 | 672 | |
---|
630 | 673 | static int process_notifier(struct notifier_block *self, |
---|
631 | 674 | unsigned long cmd, void *v) |
---|
.. | .. |
---|
638 | 681 | if (!task) |
---|
639 | 682 | return NOTIFY_OK; |
---|
640 | 683 | |
---|
641 | | - rt_mutex_lock(&uid_lock); |
---|
642 | 684 | uid = from_kuid_munged(current_user_ns(), task_uid(task)); |
---|
| 685 | + if (!rt_mutex_trylock(&uid_lock)) { |
---|
| 686 | + struct update_stats_work *usw; |
---|
| 687 | + |
---|
| 688 | + usw = kmalloc(sizeof(struct update_stats_work), GFP_KERNEL); |
---|
| 689 | + if (usw) { |
---|
| 690 | + INIT_WORK(&usw->work, update_stats_workfn); |
---|
| 691 | + usw->uid = uid; |
---|
| 692 | +#ifdef CONFIG_UID_SYS_STATS_DEBUG |
---|
| 693 | + usw->task = get_task_struct(task); |
---|
| 694 | +#endif |
---|
| 695 | + /* |
---|
| 696 | + * Copy task->ioac since task might be destroyed before |
---|
| 697 | + * the work is later performed. |
---|
| 698 | + */ |
---|
| 699 | + usw->ioac = task->ioac; |
---|
| 700 | + task_cputime_adjusted(task, &usw->utime, &usw->stime); |
---|
| 701 | + schedule_work(&usw->work); |
---|
| 702 | + } |
---|
| 703 | + return NOTIFY_OK; |
---|
| 704 | + } |
---|
| 705 | + |
---|
643 | 706 | uid_entry = find_or_register_uid(uid); |
---|
644 | 707 | if (!uid_entry) { |
---|
645 | 708 | pr_err("%s: failed to find uid %d\n", __func__, uid); |
---|