Commit f19412a2a6346ff4976d57c2692464f7cd8fa7eb
1 parent
45bc1f52
linux-user: mremap(): handle MREMAP_FIXED and MREMAP_MAYMOVE correctly
Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name> Acked-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5959 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
28 additions
and
6 deletions
linux-user/mmap.c
| @@ -537,19 +537,41 @@ int target_munmap(abi_ulong start, abi_ulong len) | @@ -537,19 +537,41 @@ int target_munmap(abi_ulong start, abi_ulong len) | ||
| 537 | return ret; | 537 | return ret; |
| 538 | } | 538 | } |
| 539 | 539 | ||
| 540 | -/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED | ||
| 541 | - blocks which have been allocated starting on a host page */ | ||
| 542 | abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, | 540 | abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, |
| 543 | abi_ulong new_size, unsigned long flags, | 541 | abi_ulong new_size, unsigned long flags, |
| 544 | abi_ulong new_addr) | 542 | abi_ulong new_addr) |
| 545 | { | 543 | { |
| 546 | int prot; | 544 | int prot; |
| 547 | - unsigned long host_addr; | 545 | + void *host_addr; |
| 548 | 546 | ||
| 549 | mmap_lock(); | 547 | mmap_lock(); |
| 550 | - /* XXX: use 5 args syscall */ | ||
| 551 | - host_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags); | ||
| 552 | - if (host_addr == -1) { | 548 | + |
| 549 | + if (flags & MREMAP_FIXED) | ||
| 550 | + host_addr = mremap(g2h(old_addr), old_size, new_size, | ||
| 551 | + flags, new_addr); | ||
| 552 | + else if (flags & MREMAP_MAYMOVE) { | ||
| 553 | + abi_ulong mmap_start; | ||
| 554 | + | ||
| 555 | + mmap_start = mmap_find_vma(0, new_size); | ||
| 556 | + | ||
| 557 | + if (mmap_start == -1) { | ||
| 558 | + errno = ENOMEM; | ||
| 559 | + host_addr = MAP_FAILED; | ||
| 560 | + } else | ||
| 561 | + host_addr = mremap(g2h(old_addr), old_size, new_size, | ||
| 562 | + flags | MREMAP_FIXED, g2h(mmap_start)); | ||
| 563 | + } else { | ||
| 564 | + host_addr = mremap(g2h(old_addr), old_size, new_size, flags); | ||
| 565 | + /* Check if address fits target address space */ | ||
| 566 | + if ((unsigned long)host_addr + new_size > (abi_ulong)-1) { | ||
| 567 | + /* Revert mremap() changes */ | ||
| 568 | + host_addr = mremap(g2h(old_addr), new_size, old_size, flags); | ||
| 569 | + errno = ENOMEM; | ||
| 570 | + host_addr = MAP_FAILED; | ||
| 571 | + } | ||
| 572 | + } | ||
| 573 | + | ||
| 574 | + if (host_addr == MAP_FAILED) { | ||
| 553 | new_addr = -1; | 575 | new_addr = -1; |
| 554 | } else { | 576 | } else { |
| 555 | new_addr = h2g(host_addr); | 577 | new_addr = h2g(host_addr); |