mirror of
git://sourceware.org/git/glibc.git
synced 2024-11-21 01:12:26 +08:00
hurd: Add mremap
* sysdeps/mach/hurd/mremap.c: New file. * sysdeps/mach/hurd/Makefile [misc] (sysdep_routines): Add mremap. * sysdeps/mach/hurd/Versions (libc.GLIBC_2.32): Add mremap. * sysdeps/mach/hurd/i386/libc.abilist: Add mremap.
This commit is contained in:
parent
3297d019e1
commit
c013d5d3aa
@ -201,7 +201,7 @@ sysdep_routines += f_setlk close_nocancel_nostatus read_nocancel \
|
||||
endif
|
||||
|
||||
ifeq (misc, $(subdir))
|
||||
sysdep_routines += writev_nocancel writev_nocancel_nostatus
|
||||
sysdep_routines += writev_nocancel writev_nocancel_nostatus mremap
|
||||
endif
|
||||
|
||||
ifeq ($(subdir),sunrpc)
|
||||
|
@ -7,6 +7,9 @@ libc {
|
||||
# functions with a weak definition in the dynamic linker
|
||||
__writev;
|
||||
}
|
||||
GLIBC_2.32 {
|
||||
mremap;
|
||||
}
|
||||
GLIBC_PRIVATE {
|
||||
# Functions shared with the dynamic linker
|
||||
__access; __access_noerrno; __libc_read; __libc_write; __libc_lseek64;
|
||||
|
@ -2182,6 +2182,7 @@ GLIBC_2.3.4 xdr_quad_t F
|
||||
GLIBC_2.3.4 xdr_u_quad_t F
|
||||
GLIBC_2.30 twalk_r F
|
||||
GLIBC_2.32 mach_print F
|
||||
GLIBC_2.32 mremap F
|
||||
GLIBC_2.32 thrd_current F
|
||||
GLIBC_2.32 thrd_equal F
|
||||
GLIBC_2.32 thrd_sleep F
|
||||
|
180
sysdeps/mach/hurd/mremap.c
Normal file
180
sysdeps/mach/hurd/mremap.c
Normal file
@ -0,0 +1,180 @@
|
||||
/* Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <hurd.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Remap pages mapped by the range [ADDR,ADDR+OLD_LEN) to new length
|
||||
NEW_LEN. If MREMAP_MAYMOVE is set in FLAGS the returned address
|
||||
may differ from ADDR. If MREMAP_FIXED is set in FLAGS the function
|
||||
takes another parameter which is a fixed address at which the block
|
||||
resides after a successful call. */
|
||||
|
||||
void *
|
||||
__mremap (void *addr, size_t old_len, size_t new_len, int flags, ...)
|
||||
{
|
||||
error_t err;
|
||||
vm_address_t vm_addr = (vm_address_t) addr;
|
||||
vm_offset_t new_vm_addr = 0;
|
||||
|
||||
vm_address_t begin = vm_addr;
|
||||
vm_address_t end;
|
||||
vm_size_t len;
|
||||
vm_prot_t prot;
|
||||
vm_prot_t max_prot;
|
||||
vm_inherit_t inherit;
|
||||
boolean_t shared;
|
||||
memory_object_name_t obj;
|
||||
vm_offset_t offset;
|
||||
|
||||
if ((flags & ~(MREMAP_MAYMOVE | MREMAP_FIXED)) ||
|
||||
((flags & MREMAP_FIXED) && !(flags & MREMAP_MAYMOVE)) ||
|
||||
(old_len == 0 && !(flags & MREMAP_MAYMOVE)))
|
||||
return (void *) (long int) __hurd_fail (EINVAL);
|
||||
|
||||
if (flags & MREMAP_FIXED)
|
||||
{
|
||||
va_list arg;
|
||||
va_start (arg, flags);
|
||||
new_vm_addr = (vm_offset_t) va_arg (arg, void *);
|
||||
va_end (arg);
|
||||
}
|
||||
|
||||
err = __vm_region (__mach_task_self (),
|
||||
&begin, &len, &prot, &max_prot, &inherit,
|
||||
&shared, &obj, &offset);
|
||||
if (err)
|
||||
return (void *) (uintptr_t) __hurd_fail (err);
|
||||
|
||||
if (begin > vm_addr)
|
||||
{
|
||||
err = EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (begin < vm_addr || (old_len != 0 && old_len != len))
|
||||
{
|
||||
err = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
end = begin + len;
|
||||
|
||||
if ((flags & MREMAP_FIXED) &&
|
||||
((new_vm_addr + new_len > vm_addr && new_vm_addr < end)))
|
||||
{
|
||||
/* Overlapping is not supported, like in Linux. */
|
||||
err = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* FIXME: locked memory. */
|
||||
|
||||
if (old_len != 0 && !(flags & MREMAP_FIXED))
|
||||
{
|
||||
/* A mere change of the existing map. */
|
||||
|
||||
if (new_len == len)
|
||||
{
|
||||
new_vm_addr = vm_addr;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (new_len < len)
|
||||
{
|
||||
/* Shrink. */
|
||||
__mach_port_deallocate (__mach_task_self (), obj);
|
||||
err = __vm_deallocate (__mach_task_self (),
|
||||
begin + new_len, len - new_len);
|
||||
new_vm_addr = vm_addr;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Try to expand. */
|
||||
err = __vm_map (__mach_task_self (),
|
||||
&end, new_len - len, 0, 0,
|
||||
obj, offset + len, 0, prot, max_prot, inherit);
|
||||
if (!err)
|
||||
{
|
||||
/* Ok, that worked. Now coalesce them. */
|
||||
new_vm_addr = vm_addr;
|
||||
|
||||
/* XXX this is not atomic as it is in unix! */
|
||||
err = __vm_deallocate (__mach_task_self (), begin, new_len);
|
||||
if (err)
|
||||
{
|
||||
__vm_deallocate (__mach_task_self (), end, new_len - len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = __vm_map (__mach_task_self (),
|
||||
&begin, new_len, 0, 0,
|
||||
obj, offset, 0, prot, max_prot, inherit);
|
||||
if (err)
|
||||
{
|
||||
/* Oops, try to remap before reporting. */
|
||||
__vm_map (__mach_task_self (),
|
||||
&begin, len, 0, 0,
|
||||
obj, offset, 0, prot, max_prot, inherit);
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & MREMAP_MAYMOVE))
|
||||
{
|
||||
/* Can not map here */
|
||||
err = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = __vm_map (__mach_task_self (),
|
||||
&new_vm_addr, new_len, 0,
|
||||
new_vm_addr == 0, obj, offset,
|
||||
old_len == 0, prot, max_prot, inherit);
|
||||
|
||||
if (err == KERN_NO_SPACE && (flags & MREMAP_FIXED))
|
||||
{
|
||||
/* XXX this is not atomic as it is in unix! */
|
||||
/* The region is already allocated; deallocate it first. */
|
||||
err = __vm_deallocate (__mach_task_self (), new_vm_addr, new_len);
|
||||
if (! err)
|
||||
err = __vm_map (__mach_task_self (),
|
||||
&new_vm_addr, new_len, 0,
|
||||
0, obj, offset,
|
||||
old_len == 0, prot, max_prot, inherit);
|
||||
}
|
||||
|
||||
if (!err)
|
||||
/* Alright, can remove old mapping. */
|
||||
__vm_deallocate (__mach_task_self (), begin, len);
|
||||
|
||||
out:
|
||||
__mach_port_deallocate (__mach_task_self (), obj);
|
||||
if (err)
|
||||
return (void *) (uintptr_t) __hurd_fail (err);
|
||||
return (void *) new_vm_addr;
|
||||
}
|
||||
|
||||
libc_hidden_def (__mremap)
|
||||
weak_alias (__mremap, mremap)
|
Loading…
Reference in New Issue
Block a user