diff options
Diffstat (limited to 'mm/nommu.c')
-rw-r--r-- | mm/nommu.c | 187 |
1 files changed, 142 insertions, 45 deletions
diff --git a/mm/nommu.c b/mm/nommu.c index 9876fa0c3ad3..63fa17d121f0 100644 --- a/mm/nommu.c +++ b/mm/nommu.c | |||
@@ -162,7 +162,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, | |||
162 | } | 162 | } |
163 | if (vmas) | 163 | if (vmas) |
164 | vmas[i] = vma; | 164 | vmas[i] = vma; |
165 | start += PAGE_SIZE; | 165 | start = (start + PAGE_SIZE) & PAGE_MASK; |
166 | } | 166 | } |
167 | 167 | ||
168 | return i; | 168 | return i; |
@@ -432,6 +432,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) | |||
432 | /* | 432 | /* |
433 | * Ok, looks good - let it rip. | 433 | * Ok, looks good - let it rip. |
434 | */ | 434 | */ |
435 | flush_icache_range(mm->brk, brk); | ||
435 | return mm->brk = brk; | 436 | return mm->brk = brk; |
436 | } | 437 | } |
437 | 438 | ||
@@ -551,11 +552,11 @@ static void free_page_series(unsigned long from, unsigned long to) | |||
551 | static void __put_nommu_region(struct vm_region *region) | 552 | static void __put_nommu_region(struct vm_region *region) |
552 | __releases(nommu_region_sem) | 553 | __releases(nommu_region_sem) |
553 | { | 554 | { |
554 | kenter("%p{%d}", region, atomic_read(®ion->vm_usage)); | 555 | kenter("%p{%d}", region, region->vm_usage); |
555 | 556 | ||
556 | BUG_ON(!nommu_region_tree.rb_node); | 557 | BUG_ON(!nommu_region_tree.rb_node); |
557 | 558 | ||
558 | if (atomic_dec_and_test(®ion->vm_usage)) { | 559 | if (--region->vm_usage == 0) { |
559 | if (region->vm_top > region->vm_start) | 560 | if (region->vm_top > region->vm_start) |
560 | delete_nommu_region(region); | 561 | delete_nommu_region(region); |
561 | up_write(&nommu_region_sem); | 562 | up_write(&nommu_region_sem); |
@@ -1039,10 +1040,9 @@ static int do_mmap_shared_file(struct vm_area_struct *vma) | |||
1039 | if (ret != -ENOSYS) | 1040 | if (ret != -ENOSYS) |
1040 | return ret; | 1041 | return ret; |
1041 | 1042 | ||
1042 | /* getting an ENOSYS error indicates that direct mmap isn't | 1043 | /* getting -ENOSYS indicates that direct mmap isn't possible (as |
1043 | * possible (as opposed to tried but failed) so we'll fall | 1044 | * opposed to tried but failed) so we can only give a suitable error as |
1044 | * through to making a private copy of the data and mapping | 1045 | * it's not possible to make a private copy if MAP_SHARED was given */ |
1045 | * that if we can */ | ||
1046 | return -ENODEV; | 1046 | return -ENODEV; |
1047 | } | 1047 | } |
1048 | 1048 | ||
@@ -1143,9 +1143,6 @@ static int do_mmap_private(struct vm_area_struct *vma, | |||
1143 | if (ret < rlen) | 1143 | if (ret < rlen) |
1144 | memset(base + ret, 0, rlen - ret); | 1144 | memset(base + ret, 0, rlen - ret); |
1145 | 1145 | ||
1146 | } else { | ||
1147 | /* if it's an anonymous mapping, then just clear it */ | ||
1148 | memset(base, 0, rlen); | ||
1149 | } | 1146 | } |
1150 | 1147 | ||
1151 | return 0; | 1148 | return 0; |
@@ -1207,11 +1204,11 @@ unsigned long do_mmap_pgoff(struct file *file, | |||
1207 | if (!vma) | 1204 | if (!vma) |
1208 | goto error_getting_vma; | 1205 | goto error_getting_vma; |
1209 | 1206 | ||
1210 | atomic_set(®ion->vm_usage, 1); | 1207 | region->vm_usage = 1; |
1211 | region->vm_flags = vm_flags; | 1208 | region->vm_flags = vm_flags; |
1212 | region->vm_pgoff = pgoff; | 1209 | region->vm_pgoff = pgoff; |
1213 | 1210 | ||
1214 | INIT_LIST_HEAD(&vma->anon_vma_node); | 1211 | INIT_LIST_HEAD(&vma->anon_vma_chain); |
1215 | vma->vm_flags = vm_flags; | 1212 | vma->vm_flags = vm_flags; |
1216 | vma->vm_pgoff = pgoff; | 1213 | vma->vm_pgoff = pgoff; |
1217 | 1214 | ||
@@ -1274,7 +1271,7 @@ unsigned long do_mmap_pgoff(struct file *file, | |||
1274 | } | 1271 | } |
1275 | 1272 | ||
1276 | /* we've found a region we can share */ | 1273 | /* we've found a region we can share */ |
1277 | atomic_inc(&pregion->vm_usage); | 1274 | pregion->vm_usage++; |
1278 | vma->vm_region = pregion; | 1275 | vma->vm_region = pregion; |
1279 | start = pregion->vm_start; | 1276 | start = pregion->vm_start; |
1280 | start += (pgoff - pregion->vm_pgoff) << PAGE_SHIFT; | 1277 | start += (pgoff - pregion->vm_pgoff) << PAGE_SHIFT; |
@@ -1291,7 +1288,7 @@ unsigned long do_mmap_pgoff(struct file *file, | |||
1291 | vma->vm_region = NULL; | 1288 | vma->vm_region = NULL; |
1292 | vma->vm_start = 0; | 1289 | vma->vm_start = 0; |
1293 | vma->vm_end = 0; | 1290 | vma->vm_end = 0; |
1294 | atomic_dec(&pregion->vm_usage); | 1291 | pregion->vm_usage--; |
1295 | pregion = NULL; | 1292 | pregion = NULL; |
1296 | goto error_just_free; | 1293 | goto error_just_free; |
1297 | } | 1294 | } |
@@ -1343,6 +1340,11 @@ unsigned long do_mmap_pgoff(struct file *file, | |||
1343 | goto error_just_free; | 1340 | goto error_just_free; |
1344 | add_nommu_region(region); | 1341 | add_nommu_region(region); |
1345 | 1342 | ||
1343 | /* clear anonymous mappings that don't ask for uninitialized data */ | ||
1344 | if (!vma->vm_file && !(flags & MAP_UNINITIALIZED)) | ||
1345 | memset((void *)region->vm_start, 0, | ||
1346 | region->vm_end - region->vm_start); | ||
1347 | |||
1346 | /* okay... we have a mapping; now we have to register it */ | 1348 | /* okay... we have a mapping; now we have to register it */ |
1347 | result = vma->vm_start; | 1349 | result = vma->vm_start; |
1348 | 1350 | ||
@@ -1351,10 +1353,14 @@ unsigned long do_mmap_pgoff(struct file *file, | |||
1351 | share: | 1353 | share: |
1352 | add_vma_to_mm(current->mm, vma); | 1354 | add_vma_to_mm(current->mm, vma); |
1353 | 1355 | ||
1354 | up_write(&nommu_region_sem); | 1356 | /* we flush the region from the icache only when the first executable |
1357 | * mapping of it is made */ | ||
1358 | if (vma->vm_flags & VM_EXEC && !region->vm_icache_flushed) { | ||
1359 | flush_icache_range(region->vm_start, region->vm_end); | ||
1360 | region->vm_icache_flushed = true; | ||
1361 | } | ||
1355 | 1362 | ||
1356 | if (prot & PROT_EXEC) | 1363 | up_write(&nommu_region_sem); |
1357 | flush_icache_range(result, result + len); | ||
1358 | 1364 | ||
1359 | kleave(" = %lx", result); | 1365 | kleave(" = %lx", result); |
1360 | return result; | 1366 | return result; |
@@ -1396,6 +1402,55 @@ error_getting_region: | |||
1396 | } | 1402 | } |
1397 | EXPORT_SYMBOL(do_mmap_pgoff); | 1403 | EXPORT_SYMBOL(do_mmap_pgoff); |
1398 | 1404 | ||
1405 | SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, | ||
1406 | unsigned long, prot, unsigned long, flags, | ||
1407 | unsigned long, fd, unsigned long, pgoff) | ||
1408 | { | ||
1409 | struct file *file = NULL; | ||
1410 | unsigned long retval = -EBADF; | ||
1411 | |||
1412 | if (!(flags & MAP_ANONYMOUS)) { | ||
1413 | file = fget(fd); | ||
1414 | if (!file) | ||
1415 | goto out; | ||
1416 | } | ||
1417 | |||
1418 | flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); | ||
1419 | |||
1420 | down_write(¤t->mm->mmap_sem); | ||
1421 | retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); | ||
1422 | up_write(¤t->mm->mmap_sem); | ||
1423 | |||
1424 | if (file) | ||
1425 | fput(file); | ||
1426 | out: | ||
1427 | return retval; | ||
1428 | } | ||
1429 | |||
1430 | #ifdef __ARCH_WANT_SYS_OLD_MMAP | ||
1431 | struct mmap_arg_struct { | ||
1432 | unsigned long addr; | ||
1433 | unsigned long len; | ||
1434 | unsigned long prot; | ||
1435 | unsigned long flags; | ||
1436 | unsigned long fd; | ||
1437 | unsigned long offset; | ||
1438 | }; | ||
1439 | |||
1440 | SYSCALL_DEFINE1(old_mmap, struct mmap_arg_struct __user *, arg) | ||
1441 | { | ||
1442 | struct mmap_arg_struct a; | ||
1443 | |||
1444 | if (copy_from_user(&a, arg, sizeof(a))) | ||
1445 | return -EFAULT; | ||
1446 | if (a.offset & ~PAGE_MASK) | ||
1447 | return -EINVAL; | ||
1448 | |||
1449 | return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, | ||
1450 | a.offset >> PAGE_SHIFT); | ||
1451 | } | ||
1452 | #endif /* __ARCH_WANT_SYS_OLD_MMAP */ | ||
1453 | |||
1399 | /* | 1454 | /* |
1400 | * split a vma into two pieces at address 'addr', a new vma is allocated either | 1455 | * split a vma into two pieces at address 'addr', a new vma is allocated either |
1401 | * for the first part or the tail. | 1456 | * for the first part or the tail. |
@@ -1409,10 +1464,9 @@ int split_vma(struct mm_struct *mm, struct vm_area_struct *vma, | |||
1409 | 1464 | ||
1410 | kenter(""); | 1465 | kenter(""); |
1411 | 1466 | ||
1412 | /* we're only permitted to split anonymous regions that have a single | 1467 | /* we're only permitted to split anonymous regions (these should have |
1413 | * owner */ | 1468 | * only a single usage on the region) */ |
1414 | if (vma->vm_file || | 1469 | if (vma->vm_file) |
1415 | atomic_read(&vma->vm_region->vm_usage) != 1) | ||
1416 | return -ENOMEM; | 1470 | return -ENOMEM; |
1417 | 1471 | ||
1418 | if (mm->map_count >= sysctl_max_map_count) | 1472 | if (mm->map_count >= sysctl_max_map_count) |
@@ -1486,7 +1540,7 @@ static int shrink_vma(struct mm_struct *mm, | |||
1486 | 1540 | ||
1487 | /* cut the backing region down to size */ | 1541 | /* cut the backing region down to size */ |
1488 | region = vma->vm_region; | 1542 | region = vma->vm_region; |
1489 | BUG_ON(atomic_read(®ion->vm_usage) != 1); | 1543 | BUG_ON(region->vm_usage != 1); |
1490 | 1544 | ||
1491 | down_write(&nommu_region_sem); | 1545 | down_write(&nommu_region_sem); |
1492 | delete_nommu_region(region); | 1546 | delete_nommu_region(region); |
@@ -1730,27 +1784,6 @@ void unmap_mapping_range(struct address_space *mapping, | |||
1730 | EXPORT_SYMBOL(unmap_mapping_range); | 1784 | EXPORT_SYMBOL(unmap_mapping_range); |
1731 | 1785 | ||
1732 | /* | 1786 | /* |
1733 | * ask for an unmapped area at which to create a mapping on a file | ||
1734 | */ | ||
1735 | unsigned long get_unmapped_area(struct file *file, unsigned long addr, | ||
1736 | unsigned long len, unsigned long pgoff, | ||
1737 | unsigned long flags) | ||
1738 | { | ||
1739 | unsigned long (*get_area)(struct file *, unsigned long, unsigned long, | ||
1740 | unsigned long, unsigned long); | ||
1741 | |||
1742 | get_area = current->mm->get_unmapped_area; | ||
1743 | if (file && file->f_op && file->f_op->get_unmapped_area) | ||
1744 | get_area = file->f_op->get_unmapped_area; | ||
1745 | |||
1746 | if (!get_area) | ||
1747 | return -ENOSYS; | ||
1748 | |||
1749 | return get_area(file, addr, len, pgoff, flags); | ||
1750 | } | ||
1751 | EXPORT_SYMBOL(get_unmapped_area); | ||
1752 | |||
1753 | /* | ||
1754 | * Check that a process has enough memory to allocate a new virtual | 1787 | * Check that a process has enough memory to allocate a new virtual |
1755 | * mapping. 0 means there is enough memory for the allocation to | 1788 | * mapping. 0 means there is enough memory for the allocation to |
1756 | * succeed and -ENOMEM implies there is not. | 1789 | * succeed and -ENOMEM implies there is not. |
@@ -1889,9 +1922,11 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in | |||
1889 | 1922 | ||
1890 | /* only read or write mappings where it is permitted */ | 1923 | /* only read or write mappings where it is permitted */ |
1891 | if (write && vma->vm_flags & VM_MAYWRITE) | 1924 | if (write && vma->vm_flags & VM_MAYWRITE) |
1892 | len -= copy_to_user((void *) addr, buf, len); | 1925 | copy_to_user_page(vma, NULL, addr, |
1926 | (void *) addr, buf, len); | ||
1893 | else if (!write && vma->vm_flags & VM_MAYREAD) | 1927 | else if (!write && vma->vm_flags & VM_MAYREAD) |
1894 | len -= copy_from_user(buf, (void *) addr, len); | 1928 | copy_from_user_page(vma, NULL, addr, |
1929 | buf, (void *) addr, len); | ||
1895 | else | 1930 | else |
1896 | len = 0; | 1931 | len = 0; |
1897 | } else { | 1932 | } else { |
@@ -1902,3 +1937,65 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in | |||
1902 | mmput(mm); | 1937 | mmput(mm); |
1903 | return len; | 1938 | return len; |
1904 | } | 1939 | } |
1940 | |||
1941 | /** | ||
1942 | * nommu_shrink_inode_mappings - Shrink the shared mappings on an inode | ||
1943 | * @inode: The inode to check | ||
1944 | * @size: The current filesize of the inode | ||
1945 | * @newsize: The proposed filesize of the inode | ||
1946 | * | ||
1947 | * Check the shared mappings on an inode on behalf of a shrinking truncate to | ||
1948 | * make sure that that any outstanding VMAs aren't broken and then shrink the | ||
1949 | * vm_regions that extend that beyond so that do_mmap_pgoff() doesn't | ||
1950 | * automatically grant mappings that are too large. | ||
1951 | */ | ||
1952 | int nommu_shrink_inode_mappings(struct inode *inode, size_t size, | ||
1953 | size_t newsize) | ||
1954 | { | ||
1955 | struct vm_area_struct *vma; | ||
1956 | struct prio_tree_iter iter; | ||
1957 | struct vm_region *region; | ||
1958 | pgoff_t low, high; | ||
1959 | size_t r_size, r_top; | ||
1960 | |||
1961 | low = newsize >> PAGE_SHIFT; | ||
1962 | high = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
1963 | |||
1964 | down_write(&nommu_region_sem); | ||
1965 | |||
1966 | /* search for VMAs that fall within the dead zone */ | ||
1967 | vma_prio_tree_foreach(vma, &iter, &inode->i_mapping->i_mmap, | ||
1968 | low, high) { | ||
1969 | /* found one - only interested if it's shared out of the page | ||
1970 | * cache */ | ||
1971 | if (vma->vm_flags & VM_SHARED) { | ||
1972 | up_write(&nommu_region_sem); | ||
1973 | return -ETXTBSY; /* not quite true, but near enough */ | ||
1974 | } | ||
1975 | } | ||
1976 | |||
1977 | /* reduce any regions that overlap the dead zone - if in existence, | ||
1978 | * these will be pointed to by VMAs that don't overlap the dead zone | ||
1979 | * | ||
1980 | * we don't check for any regions that start beyond the EOF as there | ||
1981 | * shouldn't be any | ||
1982 | */ | ||
1983 | vma_prio_tree_foreach(vma, &iter, &inode->i_mapping->i_mmap, | ||
1984 | 0, ULONG_MAX) { | ||
1985 | if (!(vma->vm_flags & VM_SHARED)) | ||
1986 | continue; | ||
1987 | |||
1988 | region = vma->vm_region; | ||
1989 | r_size = region->vm_top - region->vm_start; | ||
1990 | r_top = (region->vm_pgoff << PAGE_SHIFT) + r_size; | ||
1991 | |||
1992 | if (r_top > newsize) { | ||
1993 | region->vm_top -= r_top - newsize; | ||
1994 | if (region->vm_end > region->vm_top) | ||
1995 | region->vm_end = region->vm_top; | ||
1996 | } | ||
1997 | } | ||
1998 | |||
1999 | up_write(&nommu_region_sem); | ||
2000 | return 0; | ||
2001 | } | ||