diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/base.c | 5 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 87 |
2 files changed, 41 insertions, 51 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 9e82adc37b0c..7621db800a74 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -443,12 +443,13 @@ static const struct file_operations proc_lstats_operations = { | |||
443 | unsigned long badness(struct task_struct *p, unsigned long uptime); | 443 | unsigned long badness(struct task_struct *p, unsigned long uptime); |
444 | static int proc_oom_score(struct task_struct *task, char *buffer) | 444 | static int proc_oom_score(struct task_struct *task, char *buffer) |
445 | { | 445 | { |
446 | unsigned long points; | 446 | unsigned long points = 0; |
447 | struct timespec uptime; | 447 | struct timespec uptime; |
448 | 448 | ||
449 | do_posix_clock_monotonic_gettime(&uptime); | 449 | do_posix_clock_monotonic_gettime(&uptime); |
450 | read_lock(&tasklist_lock); | 450 | read_lock(&tasklist_lock); |
451 | points = badness(task->group_leader, uptime.tv_sec); | 451 | if (pid_alive(task)) |
452 | points = badness(task, uptime.tv_sec); | ||
452 | read_unlock(&tasklist_lock); | 453 | read_unlock(&tasklist_lock); |
453 | return sprintf(buffer, "%lu\n", points); | 454 | return sprintf(buffer, "%lu\n", points); |
454 | } | 455 | } |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 2d45889931f6..caf0337dff73 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -407,6 +407,7 @@ static int show_smap(struct seq_file *m, void *v) | |||
407 | 407 | ||
408 | memset(&mss, 0, sizeof mss); | 408 | memset(&mss, 0, sizeof mss); |
409 | mss.vma = vma; | 409 | mss.vma = vma; |
410 | /* mmap_sem is held in m_start */ | ||
410 | if (vma->vm_mm && !is_vm_hugetlb_page(vma)) | 411 | if (vma->vm_mm && !is_vm_hugetlb_page(vma)) |
411 | walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); | 412 | walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); |
412 | 413 | ||
@@ -553,7 +554,8 @@ const struct file_operations proc_clear_refs_operations = { | |||
553 | }; | 554 | }; |
554 | 555 | ||
555 | struct pagemapread { | 556 | struct pagemapread { |
556 | u64 __user *out, *end; | 557 | int pos, len; |
558 | u64 *buffer; | ||
557 | }; | 559 | }; |
558 | 560 | ||
559 | #define PM_ENTRY_BYTES sizeof(u64) | 561 | #define PM_ENTRY_BYTES sizeof(u64) |
@@ -576,10 +578,8 @@ struct pagemapread { | |||
576 | static int add_to_pagemap(unsigned long addr, u64 pfn, | 578 | static int add_to_pagemap(unsigned long addr, u64 pfn, |
577 | struct pagemapread *pm) | 579 | struct pagemapread *pm) |
578 | { | 580 | { |
579 | if (put_user(pfn, pm->out)) | 581 | pm->buffer[pm->pos++] = pfn; |
580 | return -EFAULT; | 582 | if (pm->pos >= pm->len) |
581 | pm->out++; | ||
582 | if (pm->out >= pm->end) | ||
583 | return PM_END_OF_BUFFER; | 583 | return PM_END_OF_BUFFER; |
584 | return 0; | 584 | return 0; |
585 | } | 585 | } |
@@ -721,21 +721,20 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long addr, | |||
721 | * determine which areas of memory are actually mapped and llseek to | 721 | * determine which areas of memory are actually mapped and llseek to |
722 | * skip over unmapped regions. | 722 | * skip over unmapped regions. |
723 | */ | 723 | */ |
724 | #define PAGEMAP_WALK_SIZE (PMD_SIZE) | ||
724 | static ssize_t pagemap_read(struct file *file, char __user *buf, | 725 | static ssize_t pagemap_read(struct file *file, char __user *buf, |
725 | size_t count, loff_t *ppos) | 726 | size_t count, loff_t *ppos) |
726 | { | 727 | { |
727 | struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); | 728 | struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); |
728 | struct page **pages, *page; | ||
729 | unsigned long uaddr, uend; | ||
730 | struct mm_struct *mm; | 729 | struct mm_struct *mm; |
731 | struct pagemapread pm; | 730 | struct pagemapread pm; |
732 | int pagecount; | ||
733 | int ret = -ESRCH; | 731 | int ret = -ESRCH; |
734 | struct mm_walk pagemap_walk = {}; | 732 | struct mm_walk pagemap_walk = {}; |
735 | unsigned long src; | 733 | unsigned long src; |
736 | unsigned long svpfn; | 734 | unsigned long svpfn; |
737 | unsigned long start_vaddr; | 735 | unsigned long start_vaddr; |
738 | unsigned long end_vaddr; | 736 | unsigned long end_vaddr; |
737 | int copied = 0; | ||
739 | 738 | ||
740 | if (!task) | 739 | if (!task) |
741 | goto out; | 740 | goto out; |
@@ -758,35 +757,12 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
758 | if (!mm) | 757 | if (!mm) |
759 | goto out_task; | 758 | goto out_task; |
760 | 759 | ||
761 | 760 | pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); | |
762 | uaddr = (unsigned long)buf & PAGE_MASK; | 761 | pm.buffer = kmalloc(pm.len, GFP_TEMPORARY); |
763 | uend = (unsigned long)(buf + count); | ||
764 | pagecount = (PAGE_ALIGN(uend) - uaddr) / PAGE_SIZE; | ||
765 | ret = 0; | ||
766 | if (pagecount == 0) | ||
767 | goto out_mm; | ||
768 | pages = kcalloc(pagecount, sizeof(struct page *), GFP_KERNEL); | ||
769 | ret = -ENOMEM; | 762 | ret = -ENOMEM; |
770 | if (!pages) | 763 | if (!pm.buffer) |
771 | goto out_mm; | 764 | goto out_mm; |
772 | 765 | ||
773 | down_read(¤t->mm->mmap_sem); | ||
774 | ret = get_user_pages(current, current->mm, uaddr, pagecount, | ||
775 | 1, 0, pages, NULL); | ||
776 | up_read(¤t->mm->mmap_sem); | ||
777 | |||
778 | if (ret < 0) | ||
779 | goto out_free; | ||
780 | |||
781 | if (ret != pagecount) { | ||
782 | pagecount = ret; | ||
783 | ret = -EFAULT; | ||
784 | goto out_pages; | ||
785 | } | ||
786 | |||
787 | pm.out = (u64 __user *)buf; | ||
788 | pm.end = (u64 __user *)(buf + count); | ||
789 | |||
790 | pagemap_walk.pmd_entry = pagemap_pte_range; | 766 | pagemap_walk.pmd_entry = pagemap_pte_range; |
791 | pagemap_walk.pte_hole = pagemap_pte_hole; | 767 | pagemap_walk.pte_hole = pagemap_pte_hole; |
792 | pagemap_walk.hugetlb_entry = pagemap_hugetlb_range; | 768 | pagemap_walk.hugetlb_entry = pagemap_hugetlb_range; |
@@ -808,23 +784,36 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
808 | * user buffer is tracked in "pm", and the walk | 784 | * user buffer is tracked in "pm", and the walk |
809 | * will stop when we hit the end of the buffer. | 785 | * will stop when we hit the end of the buffer. |
810 | */ | 786 | */ |
811 | ret = walk_page_range(start_vaddr, end_vaddr, &pagemap_walk); | 787 | ret = 0; |
812 | if (ret == PM_END_OF_BUFFER) | 788 | while (count && (start_vaddr < end_vaddr)) { |
813 | ret = 0; | 789 | int len; |
814 | /* don't need mmap_sem for these, but this looks cleaner */ | 790 | unsigned long end; |
815 | *ppos += (char __user *)pm.out - buf; | 791 | |
816 | if (!ret) | 792 | pm.pos = 0; |
817 | ret = (char __user *)pm.out - buf; | 793 | end = start_vaddr + PAGEMAP_WALK_SIZE; |
818 | 794 | /* overflow ? */ | |
819 | out_pages: | 795 | if (end < start_vaddr || end > end_vaddr) |
820 | for (; pagecount; pagecount--) { | 796 | end = end_vaddr; |
821 | page = pages[pagecount-1]; | 797 | down_read(&mm->mmap_sem); |
822 | if (!PageReserved(page)) | 798 | ret = walk_page_range(start_vaddr, end, &pagemap_walk); |
823 | SetPageDirty(page); | 799 | up_read(&mm->mmap_sem); |
824 | page_cache_release(page); | 800 | start_vaddr = end; |
801 | |||
802 | len = min(count, PM_ENTRY_BYTES * pm.pos); | ||
803 | if (copy_to_user(buf, pm.buffer, len) < 0) { | ||
804 | ret = -EFAULT; | ||
805 | goto out_free; | ||
806 | } | ||
807 | copied += len; | ||
808 | buf += len; | ||
809 | count -= len; | ||
825 | } | 810 | } |
811 | *ppos += copied; | ||
812 | if (!ret || ret == PM_END_OF_BUFFER) | ||
813 | ret = copied; | ||
814 | |||
826 | out_free: | 815 | out_free: |
827 | kfree(pages); | 816 | kfree(pm.buffer); |
828 | out_mm: | 817 | out_mm: |
829 | mmput(mm); | 818 | mmput(mm); |
830 | out_task: | 819 | out_task: |