diff options
Diffstat (limited to 'mm/migrate.c')
| -rw-r--r-- | mm/migrate.c | 59 |
1 files changed, 46 insertions, 13 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index 1e0d6b237f44..d8f07667fc80 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
| @@ -987,25 +987,18 @@ out: | |||
| 987 | /* | 987 | /* |
| 988 | * Determine the nodes of an array of pages and store it in an array of status. | 988 | * Determine the nodes of an array of pages and store it in an array of status. |
| 989 | */ | 989 | */ |
| 990 | static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages, | 990 | static void do_pages_stat_array(struct mm_struct *mm, unsigned long nr_pages, |
| 991 | const void __user * __user *pages, | 991 | const void __user **pages, int *status) |
| 992 | int __user *status) | ||
| 993 | { | 992 | { |
| 994 | unsigned long i; | 993 | unsigned long i; |
| 995 | int err; | ||
| 996 | 994 | ||
| 997 | down_read(&mm->mmap_sem); | 995 | down_read(&mm->mmap_sem); |
| 998 | 996 | ||
| 999 | for (i = 0; i < nr_pages; i++) { | 997 | for (i = 0; i < nr_pages; i++) { |
| 1000 | const void __user *p; | 998 | unsigned long addr = (unsigned long)(*pages); |
| 1001 | unsigned long addr; | ||
| 1002 | struct vm_area_struct *vma; | 999 | struct vm_area_struct *vma; |
| 1003 | struct page *page; | 1000 | struct page *page; |
| 1004 | 1001 | int err; | |
| 1005 | err = -EFAULT; | ||
| 1006 | if (get_user(p, pages+i)) | ||
| 1007 | goto out; | ||
| 1008 | addr = (unsigned long) p; | ||
| 1009 | 1002 | ||
| 1010 | vma = find_vma(mm, addr); | 1003 | vma = find_vma(mm, addr); |
| 1011 | if (!vma) | 1004 | if (!vma) |
| @@ -1024,12 +1017,52 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages, | |||
| 1024 | 1017 | ||
| 1025 | err = page_to_nid(page); | 1018 | err = page_to_nid(page); |
| 1026 | set_status: | 1019 | set_status: |
| 1027 | put_user(err, status+i); | 1020 | *status = err; |
| 1021 | |||
| 1022 | pages++; | ||
| 1023 | status++; | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | up_read(&mm->mmap_sem); | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | /* | ||
| 1030 | * Determine the nodes of a user array of pages and store it in | ||
| 1031 | * a user array of status. | ||
| 1032 | */ | ||
| 1033 | static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages, | ||
| 1034 | const void __user * __user *pages, | ||
| 1035 | int __user *status) | ||
| 1036 | { | ||
| 1037 | #define DO_PAGES_STAT_CHUNK_NR 16 | ||
| 1038 | const void __user *chunk_pages[DO_PAGES_STAT_CHUNK_NR]; | ||
| 1039 | int chunk_status[DO_PAGES_STAT_CHUNK_NR]; | ||
| 1040 | unsigned long i, chunk_nr = DO_PAGES_STAT_CHUNK_NR; | ||
| 1041 | int err; | ||
| 1042 | |||
| 1043 | for (i = 0; i < nr_pages; i += chunk_nr) { | ||
| 1044 | if (chunk_nr + i > nr_pages) | ||
| 1045 | chunk_nr = nr_pages - i; | ||
| 1046 | |||
| 1047 | err = copy_from_user(chunk_pages, &pages[i], | ||
| 1048 | chunk_nr * sizeof(*chunk_pages)); | ||
| 1049 | if (err) { | ||
| 1050 | err = -EFAULT; | ||
| 1051 | goto out; | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | do_pages_stat_array(mm, chunk_nr, chunk_pages, chunk_status); | ||
| 1055 | |||
| 1056 | err = copy_to_user(&status[i], chunk_status, | ||
| 1057 | chunk_nr * sizeof(*chunk_status)); | ||
| 1058 | if (err) { | ||
| 1059 | err = -EFAULT; | ||
| 1060 | goto out; | ||
| 1061 | } | ||
| 1028 | } | 1062 | } |
| 1029 | err = 0; | 1063 | err = 0; |
| 1030 | 1064 | ||
| 1031 | out: | 1065 | out: |
| 1032 | up_read(&mm->mmap_sem); | ||
| 1033 | return err; | 1066 | return err; |
| 1034 | } | 1067 | } |
| 1035 | 1068 | ||
