aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelo Tosatti <marcelo@kvack.org>2008-03-13 15:32:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-03-13 16:11:43 -0400
commitfb39380b8d683b55630ba5ba381f4e43e417420e (patch)
tree4fa4386d054b2af1b66651f8cc3d87eeb48ebf73
parentb500ce8d24d1f14426643da5f6fada28c1f60533 (diff)
pagemap: proper read error handling
Fix pagemap_read() error handling by releasing acquired resources and checking for get_user_pages() partial failure. Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Acked-by: Matt Mackall <mpm@selenic.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/proc/task_mmu.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 6dc0334815f7..4206454734e0 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -640,17 +640,17 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
640 640
641 ret = -EACCES; 641 ret = -EACCES;
642 if (!ptrace_may_attach(task)) 642 if (!ptrace_may_attach(task))
643 goto out; 643 goto out_task;
644 644
645 ret = -EINVAL; 645 ret = -EINVAL;
646 /* file position must be aligned */ 646 /* file position must be aligned */
647 if (*ppos % PM_ENTRY_BYTES) 647 if (*ppos % PM_ENTRY_BYTES)
648 goto out; 648 goto out_task;
649 649
650 ret = 0; 650 ret = 0;
651 mm = get_task_mm(task); 651 mm = get_task_mm(task);
652 if (!mm) 652 if (!mm)
653 goto out; 653 goto out_task;
654 654
655 ret = -ENOMEM; 655 ret = -ENOMEM;
656 uaddr = (unsigned long)buf & PAGE_MASK; 656 uaddr = (unsigned long)buf & PAGE_MASK;
@@ -658,7 +658,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
658 pagecount = (PAGE_ALIGN(uend) - uaddr) / PAGE_SIZE; 658 pagecount = (PAGE_ALIGN(uend) - uaddr) / PAGE_SIZE;
659 pages = kmalloc(pagecount * sizeof(struct page *), GFP_KERNEL); 659 pages = kmalloc(pagecount * sizeof(struct page *), GFP_KERNEL);
660 if (!pages) 660 if (!pages)
661 goto out_task; 661 goto out_mm;
662 662
663 down_read(&current->mm->mmap_sem); 663 down_read(&current->mm->mmap_sem);
664 ret = get_user_pages(current, current->mm, uaddr, pagecount, 664 ret = get_user_pages(current, current->mm, uaddr, pagecount,
@@ -668,6 +668,12 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
668 if (ret < 0) 668 if (ret < 0)
669 goto out_free; 669 goto out_free;
670 670
671 if (ret != pagecount) {
672 pagecount = ret;
673 ret = -EFAULT;
674 goto out_pages;
675 }
676
671 pm.out = buf; 677 pm.out = buf;
672 pm.end = buf + count; 678 pm.end = buf + count;
673 679
@@ -699,15 +705,17 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
699 ret = pm.out - buf; 705 ret = pm.out - buf;
700 } 706 }
701 707
708out_pages:
702 for (; pagecount; pagecount--) { 709 for (; pagecount; pagecount--) {
703 page = pages[pagecount-1]; 710 page = pages[pagecount-1];
704 if (!PageReserved(page)) 711 if (!PageReserved(page))
705 SetPageDirty(page); 712 SetPageDirty(page);
706 page_cache_release(page); 713 page_cache_release(page);
707 } 714 }
708 mmput(mm);
709out_free: 715out_free:
710 kfree(pages); 716 kfree(pages);
717out_mm:
718 mmput(mm);
711out_task: 719out_task:
712 put_task_struct(task); 720 put_task_struct(task);
713out: 721out: