From patchwork Sat Jun 20 15:22:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Thibault X-Patchwork-Id: 39711 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2E8DB3890407; Sat, 20 Jun 2020 15:22:19 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from hera.aquilenet.fr (hera.aquilenet.fr [185.233.100.1]) by sourceware.org (Postfix) with ESMTPS id 7B8A73840C0E for ; Sat, 20 Jun 2020 15:22:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 7B8A73840C0E Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=ens-lyon.org Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=samuel.thibault@ens-lyon.org Received: from localhost (localhost [127.0.0.1]) by hera.aquilenet.fr (Postfix) with ESMTP id 73336A722; Sat, 20 Jun 2020 17:22:13 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at aquilenet.fr Received: from hera.aquilenet.fr ([127.0.0.1]) by localhost (hera.aquilenet.fr [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ZfsAwrbFcTOO; Sat, 20 Jun 2020 17:22:12 +0200 (CEST) Received: from function.home (unknown [IPv6:2a01:cb19:956:1b00:9eb6:d0ff:fe88:c3c7]) by hera.aquilenet.fr (Postfix) with ESMTPSA id 7CB7EA6D3; Sat, 20 Jun 2020 17:22:12 +0200 (CEST) Received: from samy by function.home with local (Exim 4.94) (envelope-from ) id 1jmfJr-000GXp-9K; Sat, 20 Jun 2020 17:22:11 +0200 From: Samuel Thibault To: libc-alpha@sourceware.org Subject: [hurd,commited] hurd: Add mremap Date: Sat, 20 Jun 2020 17:22:11 +0200 Message-Id: <20200620152211.63530-1-samuel.thibault@ens-lyon.org> X-Mailer: git-send-email 2.27.0 MIME-Version: 1.0 X-Spam-Status: No, score=-11.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_DMARC_STATUS, KAM_SHORT, SPF_HELO_PASS, SPF_NEUTRAL, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: commit-hurd@gnu.org Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" * 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. --- sysdeps/mach/hurd/Makefile | 2 +- sysdeps/mach/hurd/Versions | 3 + sysdeps/mach/hurd/i386/libc.abilist | 1 + sysdeps/mach/hurd/mremap.c | 180 ++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 sysdeps/mach/hurd/mremap.c diff --git a/sysdeps/mach/hurd/Makefile b/sysdeps/mach/hurd/Makefile index daa69c0dae..edab284d11 100644 --- a/sysdeps/mach/hurd/Makefile +++ b/sysdeps/mach/hurd/Makefile @@ -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) diff --git a/sysdeps/mach/hurd/Versions b/sysdeps/mach/hurd/Versions index d93ad1264e..e8b4aba776 100644 --- a/sysdeps/mach/hurd/Versions +++ b/sysdeps/mach/hurd/Versions @@ -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; diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist index 60696d827f..6400885d1d 100644 --- a/sysdeps/mach/hurd/i386/libc.abilist +++ b/sysdeps/mach/hurd/i386/libc.abilist @@ -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 diff --git a/sysdeps/mach/hurd/mremap.c b/sysdeps/mach/hurd/mremap.c new file mode 100644 index 0000000000..b710019539 --- /dev/null +++ b/sysdeps/mach/hurd/mremap.c @@ -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 + . */ + +#include +#include +#include +#include +#include + +#include + +/* 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)