From c0376a123418df0050dc45d3e1e84f6b29a6a1f3 Mon Sep 17 00:00:00 2001 From: Greg V Date: Thu, 18 Jan 2018 23:29:14 +0300 Subject: [PATCH 1/1] util: add anon_file.h for all memfd/temp file usage Move the Weston os_create_anonymous_file code from egl/wayland into util, add support for Linux memfd and FreeBSD SHM_ANON, use that code in anv/aubinator instead of explicit memfd calls for portability. Acked-by: Lionel Landwerlin Reviewed-by: Eric Engestrom --- src/egl/drivers/dri2/platform_wayland.c | 119 +----------------- src/intel/tools/aub_mem.c | 13 +- src/intel/vulkan/anv_allocator.c | 28 +---- src/intel/vulkan/anv_gem_stubs.c | 15 +-- src/util/Makefile.sources | 2 + src/util/anon_file.c | 155 ++++++++++++++++++++++++ src/util/anon_file.h | 34 ++++++ src/util/meson.build | 2 + 8 files changed, 205 insertions(+), 163 deletions(-) create mode 100644 src/util/anon_file.c create mode 100644 src/util/anon_file.h diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index 2a2d6fe357d..4c9046446a7 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -43,6 +43,7 @@ #include "egl_dri2_fallbacks.h" #include "loader.h" #include "util/u_vector.h" +#include "util/anon_file.h" #include "eglglobals.h" #include @@ -1588,122 +1589,6 @@ dri2_wl_swrast_get_stride_for_format(int format, int w) return w * (dri2_wl_visuals[visual_idx].bpp / 8); } -/* - * Taken from weston shared/os-compatibility.c - */ - -#ifndef HAVE_MKOSTEMP - -static int -set_cloexec_or_close(int fd) -{ - long flags; - - if (fd == -1) - return -1; - - flags = fcntl(fd, F_GETFD); - if (flags == -1) - goto err; - - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) - goto err; - - return fd; - -err: - close(fd); - return -1; -} - -#endif - -/* - * Taken from weston shared/os-compatibility.c - */ - -static int -create_tmpfile_cloexec(char *tmpname) -{ - int fd; - -#ifdef HAVE_MKOSTEMP - fd = mkostemp(tmpname, O_CLOEXEC); - if (fd >= 0) - unlink(tmpname); -#else - fd = mkstemp(tmpname); - if (fd >= 0) { - fd = set_cloexec_or_close(fd); - unlink(tmpname); - } -#endif - - return fd; -} - -/* - * Taken from weston shared/os-compatibility.c - * - * Create a new, unique, anonymous file of the given size, and - * return the file descriptor for it. The file descriptor is set - * CLOEXEC. The file is immediately suitable for mmap()'ing - * the given size at offset zero. - * - * The file should not have a permanent backing store like a disk, - * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. - * - * The file name is deleted from the file system. - * - * The file is suitable for buffer sharing between processes by - * transmitting the file descriptor over Unix sockets using the - * SCM_RIGHTS methods. - * - * If the C library implements posix_fallocate(), it is used to - * guarantee that disk space is available for the file at the - * given size. If disk space is insufficient, errno is set to ENOSPC. - * If posix_fallocate() is not supported, program may receive - * SIGBUS on accessing mmap()'ed file contents instead. - */ -static int -os_create_anonymous_file(off_t size) -{ - static const char templ[] = "/mesa-shared-XXXXXX"; - const char *path; - char *name; - int fd; - int ret; - - path = getenv("XDG_RUNTIME_DIR"); - if (!path) { - errno = ENOENT; - return -1; - } - - name = malloc(strlen(path) + sizeof(templ)); - if (!name) - return -1; - - strcpy(name, path); - strcat(name, templ); - - fd = create_tmpfile_cloexec(name); - - free(name); - - if (fd < 0) - return -1; - - ret = ftruncate(fd, size); - if (ret < 0) { - close(fd); - return -1; - } - - return fd; -} - - static EGLBoolean dri2_wl_swrast_allocate_buffer(struct dri2_egl_surface *dri2_surf, int format, int w, int h, @@ -1720,7 +1605,7 @@ dri2_wl_swrast_allocate_buffer(struct dri2_egl_surface *dri2_surf, size_map = h * stride; /* Create a shareable buffer */ - fd = os_create_anonymous_file(size_map); + fd = os_create_anonymous_file(size_map, NULL); if (fd < 0) return EGL_FALSE; diff --git a/src/intel/tools/aub_mem.c b/src/intel/tools/aub_mem.c index 1b217e130ca..f436627d19d 100644 --- a/src/intel/tools/aub_mem.c +++ b/src/intel/tools/aub_mem.c @@ -27,16 +27,7 @@ #include #include "aub_mem.h" - -#ifndef HAVE_MEMFD_CREATE -#include - -static inline int -memfd_create(const char *name, unsigned int flags) -{ - return syscall(SYS_memfd_create, name, flags); -} -#endif +#include "util/anon_file.h" struct bo_map { struct list_head link; @@ -373,7 +364,7 @@ aub_mem_init(struct aub_mem *mem) list_inithead(&mem->maps); - mem->mem_fd = memfd_create("phys memory", 0); + mem->mem_fd = os_create_anonymous_file(0, "phys memory"); return mem->mem_fd != -1; } diff --git a/src/intel/vulkan/anv_allocator.c b/src/intel/vulkan/anv_allocator.c index 48d41891cfb..a6eeed79a02 100644 --- a/src/intel/vulkan/anv_allocator.c +++ b/src/intel/vulkan/anv_allocator.c @@ -25,13 +25,13 @@ #include #include #include -#include #include #include "anv_private.h" #include "util/hash_table.h" #include "util/simple_mtx.h" +#include "util/anon_file.h" #ifdef HAVE_VALGRIND #define VG_NOACCESS_READ(__ptr) ({ \ @@ -111,14 +111,6 @@ struct anv_mmap_cleanup { #define ANV_MMAP_CLEANUP_INIT ((struct anv_mmap_cleanup){0}) -#ifndef HAVE_MEMFD_CREATE -static inline int -memfd_create(const char *name, unsigned int flags) -{ - return syscall(SYS_memfd_create, name, flags); -} -#endif - static inline uint32_t ilog2_round_up(uint32_t value) { @@ -152,15 +144,12 @@ anv_state_table_init(struct anv_state_table *table, table->device = device; - table->fd = memfd_create("state table", MFD_CLOEXEC); - if (table->fd == -1) - return vk_error(VK_ERROR_INITIALIZATION_FAILED); - /* Just make it 2GB up-front. The Linux kernel won't actually back it * with pages until we either map and fault on one of them or we use * userptr and send a chunk of it off to the GPU. */ - if (ftruncate(table->fd, BLOCK_POOL_MEMFD_SIZE) == -1) { + table->fd = os_create_anonymous_file(BLOCK_POOL_MEMFD_SIZE, "state table"); + if (table->fd == -1) { result = vk_error(VK_ERROR_INITIALIZATION_FAILED); goto fail_fd; } @@ -446,18 +435,13 @@ anv_block_pool_init(struct anv_block_pool *pool, anv_bo_init(pool->bo, 0, 0); if (!(pool->bo_flags & EXEC_OBJECT_PINNED)) { - pool->fd = memfd_create("block pool", MFD_CLOEXEC); - if (pool->fd == -1) - return vk_error(VK_ERROR_INITIALIZATION_FAILED); - /* Just make it 2GB up-front. The Linux kernel won't actually back it * with pages until we either map and fault on one of them or we use * userptr and send a chunk of it off to the GPU. */ - if (ftruncate(pool->fd, BLOCK_POOL_MEMFD_SIZE) == -1) { - result = vk_error(VK_ERROR_INITIALIZATION_FAILED); - goto fail_fd; - } + pool->fd = os_create_anonymous_file(BLOCK_POOL_MEMFD_SIZE, "block pool"); + if (pool->fd == -1) + return vk_error(VK_ERROR_INITIALIZATION_FAILED); } else { pool->fd = -1; } diff --git a/src/intel/vulkan/anv_gem_stubs.c b/src/intel/vulkan/anv_gem_stubs.c index 8cc3ad1f22e..2c27ce26f37 100644 --- a/src/intel/vulkan/anv_gem_stubs.c +++ b/src/intel/vulkan/anv_gem_stubs.c @@ -21,32 +21,21 @@ * IN THE SOFTWARE. */ -#include #include #include +#include "util/anon_file.h" #include "anv_private.h" -#ifndef HAVE_MEMFD_CREATE -static inline int -memfd_create(const char *name, unsigned int flags) -{ - return syscall(SYS_memfd_create, name, flags); -} -#endif - uint32_t anv_gem_create(struct anv_device *device, uint64_t size) { - int fd = memfd_create("fake bo", MFD_CLOEXEC); + int fd = os_create_anonymous_file(size, "fake bo"); if (fd == -1) return 0; assert(fd != 0); - if (ftruncate(fd, size) == -1) - return 0; - return fd; } diff --git a/src/util/Makefile.sources b/src/util/Makefile.sources index cbbf5126875..fdb9b6dd135 100644 --- a/src/util/Makefile.sources +++ b/src/util/Makefile.sources @@ -1,4 +1,6 @@ MESA_UTIL_FILES := \ + anon_file.h \ + anon_file.c \ bigmath.h \ bitscan.c \ bitscan.h \ diff --git a/src/util/anon_file.c b/src/util/anon_file.c new file mode 100644 index 00000000000..184b8445bad --- /dev/null +++ b/src/util/anon_file.c @@ -0,0 +1,155 @@ +/* + * Copyright © 2012 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Based on weston shared/os-compatibility.c + */ + +#ifndef WIN32 +#include "anon_file.h" + +#include +#include +#include + +#ifdef __FreeBSD__ +#include +#elif defined(HAVE_MEMFD_CREATE) +#include +#include +#endif + +#if !(defined(__FreeBSD__) || defined(HAVE_MEMFD_CREATE) || defined(HAVE_MKOSTEMP)) +static int +set_cloexec_or_close(int fd) +{ + long flags; + + if (fd == -1) + return -1; + + flags = fcntl(fd, F_GETFD); + if (flags == -1) + goto err; + + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) + goto err; + + return fd; + +err: + close(fd); + return -1; +} +#endif + +#if !(defined(__FreeBSD__) || defined(HAVE_MEMFD_CREATE)) +static int +create_tmpfile_cloexec(char *tmpname) +{ + int fd; + +#ifdef HAVE_MKOSTEMP + fd = mkostemp(tmpname, O_CLOEXEC); +#else + fd = mkstemp(tmpname); +#endif + + if (fd < 0) { + return fd; + } + +#ifndef HAVE_MKOSTEMP + fd = set_cloexec_or_close(fd); +#endif + + unlink(tmpname); + return fd; +} +#endif + +/* + * Create a new, unique, anonymous file of the given size, and + * return the file descriptor for it. The file descriptor is set + * CLOEXEC. The file is immediately suitable for mmap()'ing + * the given size at offset zero. + * + * An optional name for debugging can be provided as the second argument. + * + * The file should not have a permanent backing store like a disk, + * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. + * + * If memfd or SHM_ANON is supported, the filesystem is not touched at all. + * Otherwise, the file name is deleted from the file system. + * + * The file is suitable for buffer sharing between processes by + * transmitting the file descriptor over Unix sockets using the + * SCM_RIGHTS methods. + */ +int +os_create_anonymous_file(off_t size, char *debug_name) +{ + int fd, ret; +#ifdef __FreeBSD__ + (void*)debug_name; + fd = shm_open(SHM_ANON, O_CREAT | O_RDWR | O_CLOEXEC, 0600); +#elif defined(HAVE_MEMFD_CREATE) + if (!debug_name) + debug_name = "mesa-shared"; + fd = syscall(SYS_memfd_create, debug_name, MFD_CLOEXEC); +#else + const char *path; + char *name; + + path = getenv("XDG_RUNTIME_DIR"); + if (!path) { + errno = ENOENT; + return -1; + } + + if (debug_name) + asprintf(&name, "%s/mesa-shared-%s-XXXXXX", path, debug_name); + else + asprintf(&name, "%s/mesa-shared-XXXXXX", path); + if (!name) + return -1; + + fd = create_tmpfile_cloexec(name); + + free(name); +#endif + + if (fd < 0) + return -1; + + ret = ftruncate(fd, size); + if (ret < 0) { + close(fd); + return -1; + } + + return fd; +} +#endif diff --git a/src/util/anon_file.h b/src/util/anon_file.h new file mode 100644 index 00000000000..8bec8d5458b --- /dev/null +++ b/src/util/anon_file.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2012 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _ANON_FILE_H_ +#define _ANON_FILE_H_ + +#include +#include "util/macros.h" + +int os_create_anonymous_file(off_t size, char *debug_name); + +#endif diff --git a/src/util/meson.build b/src/util/meson.build index 95aff3b442f..cf1616e7bc6 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -23,6 +23,8 @@ inc_util = include_directories('.') subdir('xmlpool') files_mesa_util = files( + 'anon_file.h', + 'anon_file.c', 'bigmath.h', 'bitscan.c', 'bitscan.h', -- 2.30.2