187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri/* 287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * Copyright © 2014 Intel Corporation 387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * 487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * Permission is hereby granted, free of charge, to any person obtaining a 587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * copy of this software and associated documentation files (the "Software"), 687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * to deal in the Software without restriction, including without limitation 787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * the rights to use, copy, modify, merge, publish, distribute, sublicense, 887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * and/or sell copies of the Software, and to permit persons to whom the 987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * Software is furnished to do so, subject to the following conditions: 1087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * 1187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * The above copyright notice and this permission notice (including the next 1287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * paragraph) shall be included in all copies or substantial portions of the 1387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * Software. 1487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * 1587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * IN THE SOFTWARE. 2287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 2387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 24acc78377990ba986060214466d44ea364529c363Emil Velikov#ifdef ENABLE_SHADER_CACHE 25acc78377990ba986060214466d44ea364529c363Emil Velikov 2687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include <ctype.h> 2787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include <string.h> 2887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include <stdlib.h> 2987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include <stdio.h> 3087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include <sys/file.h> 3187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include <sys/types.h> 3287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include <sys/stat.h> 3387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include <sys/mman.h> 3487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include <unistd.h> 3587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include <fcntl.h> 3687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include <pwd.h> 3787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include <errno.h> 3887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include <dirent.h> 3987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 4087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include "util/u_atomic.h" 4187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include "util/mesa-sha1.h" 4287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include "util/ralloc.h" 4387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#include "main/errors.h" 4487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 4531727300e177b11c2b2b267838b59b090cb605d0Marek Olšák#include "disk_cache.h" 4687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 4787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri/* Number of bits to mask off from a cache key to get an index. */ 4887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#define CACHE_INDEX_KEY_BITS 16 4987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 5087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri/* Mask for computing an index from a key. */ 5187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#define CACHE_INDEX_KEY_MASK ((1 << CACHE_INDEX_KEY_BITS) - 1) 5287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 5387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri/* The number of keys that can be stored in the index. */ 5487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri#define CACHE_INDEX_MAX_KEYS (1 << CACHE_INDEX_KEY_BITS) 5587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 56a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšákstruct disk_cache { 5787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* The path to the cache directory. */ 5887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri char *path; 5987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 6087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* A pointer to the mmapped index file within the cache directory. */ 6187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri uint8_t *index_mmap; 6287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri size_t index_mmap_size; 6387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 6487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* Pointer to total size of all objects in cache (within index_mmap) */ 6587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri uint64_t *size; 6687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 6787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* Pointer to stored keys, (within index_mmap). */ 6887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri uint8_t *stored_keys; 6987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 7087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* Maximum size of all cached objects (in bytes). */ 7187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri uint64_t max_size; 7287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri}; 7387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 7487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri/* Create a directory named 'path' if it does not already exist. 7587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * 7687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * Returns: 0 if path already exists as a directory or if created. 7787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * -1 in all other cases. 7887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 7987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceristatic int 8087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arcerimkdir_if_needed(char *path) 8187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 8287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri struct stat sb; 8387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 8487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* If the path exists already, then our work is done if it's a 8587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * directory, but it's an error if it is not. 8687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 8787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (stat(path, &sb) == 0) { 8887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (S_ISDIR(sb.st_mode)) { 8987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return 0; 9087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } else { 9131727300e177b11c2b2b267838b59b090cb605d0Marek Olšák fprintf(stderr, "Cannot use %s for shader cache (not a directory)" 9231727300e177b11c2b2b267838b59b090cb605d0Marek Olšák "---disabling.\n", path); 9387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return -1; 9487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 9587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 9687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 9787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri int ret = mkdir(path, 0755); 9887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (ret == 0 || (ret == -1 && errno == EEXIST)) 9987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return 0; 10087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 10131727300e177b11c2b2b267838b59b090cb605d0Marek Olšák fprintf(stderr, "Failed to create %s for shader cache (%s)---disabling.\n", 10231727300e177b11c2b2b267838b59b090cb605d0Marek Olšák path, strerror(errno)); 10387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 10487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return -1; 10587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 10687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 10787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri/* Concatenate an existing path and a new name to form a new path. If the new 10887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * path does not exist as a directory, create it then return the resulting 10987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * name of the new path (ralloc'ed off of 'ctx'). 11087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * 11187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * Returns NULL on any error, such as: 11287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * 11387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * <path> does not exist or is not a directory 11487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * <path>/<name> exists but is not a directory 11587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * <path>/<name> cannot be created as a directory 11687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 11787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceristatic char * 11887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arcericoncatenate_and_mkdir(void *ctx, char *path, char *name) 11987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 12087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri char *new_path; 12187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri struct stat sb; 12287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 12387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (stat(path, &sb) != 0 || ! S_ISDIR(sb.st_mode)) 12487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return NULL; 12587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 12687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri new_path = ralloc_asprintf(ctx, "%s/%s", path, name); 12787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 12887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (mkdir_if_needed(new_path) == 0) 12987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return new_path; 13087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri else 13187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return NULL; 13287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 13387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 134a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšákstruct disk_cache * 135a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšákdisk_cache_create(void) 13687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 13787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri void *local; 138a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšák struct disk_cache *cache = NULL; 13987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri char *path, *max_size_str; 14087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri uint64_t max_size; 14187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri int fd = -1; 14287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri struct stat sb; 14387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri size_t size; 14487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 14587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* A ralloc context for transient data during this invocation. */ 14687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri local = ralloc_context(NULL); 14787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (local == NULL) 14887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 14987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 15087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* At user request, disable shader cache entirely. */ 15187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (getenv("MESA_GLSL_CACHE_DISABLE")) 15287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 15387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 15487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* Determine path for cache based on the first defined name as follows: 15587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * 15687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * $MESA_GLSL_CACHE_DIR 15787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * $XDG_CACHE_HOME/mesa 15887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * <pwd.pw_dir>/.cache/mesa 15987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 16087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri path = getenv("MESA_GLSL_CACHE_DIR"); 16187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (path && mkdir_if_needed(path) == -1) { 16287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 16387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 16487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 16587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (path == NULL) { 16687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri char *xdg_cache_home = getenv("XDG_CACHE_HOME"); 16787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 16887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (xdg_cache_home) { 16987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (mkdir_if_needed(xdg_cache_home) == -1) 17087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 17187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 17287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri path = concatenate_and_mkdir(local, xdg_cache_home, "mesa"); 17387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (path == NULL) 17487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 17587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 17687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 17787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 17887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (path == NULL) { 17987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri char *buf; 18087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri size_t buf_size; 18187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri struct passwd pwd, *result; 18287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 18387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri buf_size = sysconf(_SC_GETPW_R_SIZE_MAX); 18487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (buf_size == -1) 18587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri buf_size = 512; 18687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 18787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* Loop until buf_size is large enough to query the directory */ 18887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri while (1) { 18987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri buf = ralloc_size(local, buf_size); 19087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 19187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri getpwuid_r(getuid(), &pwd, buf, buf_size, &result); 19287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (result) 19387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri break; 19487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 19587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (errno == ERANGE) { 19687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri ralloc_free(buf); 19787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri buf = NULL; 19887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri buf_size *= 2; 19987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } else { 20087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 20187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 20287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 20387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 20487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri path = concatenate_and_mkdir(local, pwd.pw_dir, ".cache"); 20587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (path == NULL) 20687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 20787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 20887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri path = concatenate_and_mkdir(local, path, "mesa"); 20987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (path == NULL) 21087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 21187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 21287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 213a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšák cache = ralloc(NULL, struct disk_cache); 21487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (cache == NULL) 21587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 21687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 21787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri cache->path = ralloc_strdup(cache, path); 21887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (cache->path == NULL) 21987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 22087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 22187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri path = ralloc_asprintf(local, "%s/index", cache->path); 22287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (path == NULL) 22387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 22487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 22587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri fd = open(path, O_RDWR | O_CREAT | O_CLOEXEC, 0644); 22687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (fd == -1) 22787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 22887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 22987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (fstat(fd, &sb) == -1) 23087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 23187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 23287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* Force the index file to be the expected size. */ 23387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri size = sizeof(*cache->size) + CACHE_INDEX_MAX_KEYS * CACHE_KEY_SIZE; 23487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (sb.st_size != size) { 23587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (ftruncate(fd, size) == -1) 23687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 23787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 23887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 23987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* We map this shared so that other processes see updates that we 24087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * make. 24187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * 24287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * Note: We do use atomic addition to ensure that multiple 24387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * processes don't scramble the cache size recorded in the 24487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * index. But we don't use any locking to prevent multiple 24587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * processes from updating the same entry simultaneously. The idea 24687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * is that if either result lands entirely in the index, then 24787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * that's equivalent to a well-ordered write followed by an 24887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * eviction and a write. On the other hand, if the simultaneous 24987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * writes result in a corrupt entry, that's not really any 25087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * different than both entries being evicted, (since within the 25187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * guarantees of the cryptographic hash, a corrupt entry is 25287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * unlikely to ever match a real cache key). 25387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 25487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri cache->index_mmap = mmap(NULL, size, PROT_READ | PROT_WRITE, 25587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri MAP_SHARED, fd, 0); 25687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (cache->index_mmap == MAP_FAILED) 25787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 25887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri cache->index_mmap_size = size; 25987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 26087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri close(fd); 26187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 26287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri cache->size = (uint64_t *) cache->index_mmap; 26387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri cache->stored_keys = cache->index_mmap + sizeof(uint64_t); 26487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 26587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri max_size = 0; 26687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 26787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri max_size_str = getenv("MESA_GLSL_CACHE_MAX_SIZE"); 26887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (max_size_str) { 26987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri char *end; 27087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri max_size = strtoul(max_size_str, &end, 10); 27187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (end == max_size_str) { 27287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri max_size = 0; 27387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } else { 27487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri while (*end && isspace(*end)) 27587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri end++; 27687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri switch (*end) { 27787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri case 'K': 27887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri case 'k': 27987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri max_size *= 1024; 28087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri break; 28187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri case 'M': 28287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri case 'm': 28387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri max_size *= 1024*1024; 28487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri break; 28587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri case '\0': 28687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri case 'G': 28787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri case 'g': 28887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri default: 28987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri max_size *= 1024*1024*1024; 29087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri break; 29187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 29287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 29387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 29487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 29587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* Default to 1GB for maximum cache size. */ 29687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (max_size == 0) 29787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri max_size = 1024*1024*1024; 29887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 29987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri cache->max_size = max_size; 30087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 30187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri ralloc_free(local); 30287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 30387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return cache; 30487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 30587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri fail: 30687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (fd != -1) 30787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri close(fd); 30887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (cache) 30987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri ralloc_free(cache); 31087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri ralloc_free(local); 31187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 31287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return NULL; 31387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 31487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 31587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arcerivoid 316a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšákdisk_cache_destroy(struct disk_cache *cache) 31787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 31887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri munmap(cache->index_mmap, cache->index_mmap_size); 31987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 32087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri ralloc_free(cache); 32187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 32287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 32387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri/* Return a filename within the cache's directory corresponding to 'key'. The 32487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * returned filename is ralloced with 'cache' as the parent context. 32587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * 32687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * Returns NULL if out of memory. 32787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 32887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceristatic char * 329a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšákget_cache_file(struct disk_cache *cache, cache_key key) 33087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 33187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri char buf[41]; 33287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 33387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri _mesa_sha1_format(buf, key); 33487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 33587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return ralloc_asprintf(cache, "%s/%c%c/%s", 33687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri cache->path, buf[0], buf[1], buf + 2); 33787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 33887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 33987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri/* Create the directory that will be needed for the cache file for \key. 34087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * 34187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * Obviously, the implementation here must closely match 34287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * _get_cache_file above. 34387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri*/ 34487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceristatic void 345a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšákmake_cache_file_directory(struct disk_cache *cache, cache_key key) 34687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 34787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri char *dir; 34887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri char buf[41]; 34987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 35087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri _mesa_sha1_format(buf, key); 35187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 35287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri dir = ralloc_asprintf(cache, "%s/%c%c", cache->path, buf[0], buf[1]); 35387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 35487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri mkdir_if_needed(dir); 35587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 35687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri ralloc_free(dir); 35787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 35887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 35987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri/* Given a directory path and predicate function, count all entries in 36087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * that directory for which the predicate returns true. Then choose a 36187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * random entry from among those counted. 36287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * 36387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * Returns: A malloc'ed string for the path to the chosen file, (or 36487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * NULL on any error). The caller should free the string when 36587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * finished. 36687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 36787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceristatic char * 36887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arcerichoose_random_file_matching(const char *dir_path, 369269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri bool (*predicate)(struct dirent *, 370269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri const char *dir_path)) 37187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 37287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri DIR *dir; 37387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri struct dirent *entry; 37487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri unsigned int count, victim; 37587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri char *filename; 37687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 37787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri dir = opendir(dir_path); 37887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (dir == NULL) 37987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return NULL; 38087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 38187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri count = 0; 38287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 38387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri while (1) { 38487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri entry = readdir(dir); 38587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (entry == NULL) 38687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri break; 387269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri if (!predicate(entry, dir_path)) 38887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri continue; 38987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 39087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri count++; 39187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 39287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 39387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (count == 0) { 39487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri closedir(dir); 39587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return NULL; 39687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 39787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 39887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri victim = rand() % count; 39987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 40087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri rewinddir(dir); 40187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri count = 0; 40287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 40387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri while (1) { 40487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri entry = readdir(dir); 40587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (entry == NULL) 40687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri break; 407269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri if (!predicate(entry, dir_path)) 40887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri continue; 40987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (count == victim) 41087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri break; 41187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 41287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri count++; 41387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 41487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 41587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (entry == NULL) { 41687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri closedir(dir); 41787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return NULL; 41887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 41987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 420aef7eb4cacbb241dc895f3e08dba4c91052a98a8Nicolai Hähnle if (asprintf(&filename, "%s/%s", dir_path, entry->d_name) < 0) 421aef7eb4cacbb241dc895f3e08dba4c91052a98a8Nicolai Hähnle filename = NULL; 42287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 42387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri closedir(dir); 42487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 42587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return filename; 42687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 42787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 42887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri/* Is entry a regular file, and not having a name with a trailing 42987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * ".tmp" 43087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 43187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceristatic bool 432269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceriis_regular_non_tmp_file(struct dirent *entry, const char *path) 43387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 434269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri char *filename; 435269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri if (asprintf(&filename, "%s/%s", path, entry->d_name) == -1) 436269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri return false; 437269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri 438269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri struct stat sb; 439269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri int res = stat(filename, &sb); 440269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri free(filename); 44187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 442269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri if (res == -1 || !S_ISREG(sb.st_mode)) 44387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return false; 44487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 445269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri size_t len = strlen (entry->d_name); 44687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (len >= 4 && strcmp(&entry->d_name[len-4], ".tmp") == 0) 44787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return false; 44887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 44987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return true; 45087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 45187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 45287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri/* Returns the size of the deleted file, (or 0 on any error). */ 45387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceristatic size_t 45487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceriunlink_random_file_from_directory(const char *path) 45587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 45687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri struct stat sb; 45787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri char *filename; 45887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 45987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri filename = choose_random_file_matching(path, is_regular_non_tmp_file); 46087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (filename == NULL) 46187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return 0; 46287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 46387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (stat(filename, &sb) == -1) { 46487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri free (filename); 46587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return 0; 46687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 46787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 46887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri unlink(filename); 46987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 47087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri free (filename); 47187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 47287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return sb.st_size; 47387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 47487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 47587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri/* Is entry a directory with a two-character name, (and not the 47687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * special name of "..") 47787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 47887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceristatic bool 479269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceriis_two_character_sub_directory(struct dirent *entry, const char *path) 48087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 481269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri char *subdir; 482269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri if (asprintf(&subdir, "%s/%s", path, entry->d_name) == -1) 483269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri return false; 484269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri 485269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri struct stat sb; 486269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri int res = stat(subdir, &sb); 487269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri free(subdir); 488269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri 489269266359967be69f39d9aa2cddbe1faeb2eaa36Timothy Arceri if (res == -1 || !S_ISDIR(sb.st_mode)) 49087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return false; 49187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 49287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (strlen(entry->d_name) != 2) 49387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return false; 49487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 49587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (strcmp(entry->d_name, "..") == 0) 49687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return false; 49787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 49887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return true; 49987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 50087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 50187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceristatic void 502a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšákevict_random_item(struct disk_cache *cache) 50387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 50487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri const char hex[] = "0123456789abcde"; 50587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri char *dir_path; 50687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri int a, b; 50787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri size_t size; 50887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 50987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* With a reasonably-sized, full cache, (and with keys generated 51087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * from a cryptographic hash), we can choose two random hex digits 51187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * and reasonably expect the directory to exist with a file in it. 51287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 51387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri a = rand() % 16; 51487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri b = rand() % 16; 51587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 516aef7eb4cacbb241dc895f3e08dba4c91052a98a8Nicolai Hähnle if (asprintf(&dir_path, "%s/%c%c", cache->path, hex[a], hex[b]) < 0) 51787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return; 51887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 51987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri size = unlink_random_file_from_directory(dir_path); 52087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 52187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri free(dir_path); 52287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 52387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (size) { 52487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri p_atomic_add(cache->size, - size); 52587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return; 52687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 52787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 52887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* In the case where the random choice of directory didn't find 52987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * something, we choose randomly from the existing directories. 53087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * 53187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * Really, the only reason this code exists is to allow the unit 53287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * tests to work, (which use an artificially-small cache to be able 53387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * to force a single cached item to be evicted). 53487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 53587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri dir_path = choose_random_file_matching(cache->path, 53687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri is_two_character_sub_directory); 53787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (dir_path == NULL) 53887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return; 53987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 54087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri size = unlink_random_file_from_directory(dir_path); 54187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 54287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri free(dir_path); 54387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 54487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (size) 54587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri p_atomic_add(cache->size, - size); 54687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 54787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 54887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arcerivoid 549a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšákdisk_cache_put(struct disk_cache *cache, 55087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri cache_key key, 55187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri const void *data, 55287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri size_t size) 55387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 55487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri int fd = -1, fd_final = -1, err, ret; 55587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri size_t len; 55687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri char *filename = NULL, *filename_tmp = NULL; 55787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri const char *p = data; 55887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 55987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri filename = get_cache_file(cache, key); 56087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (filename == NULL) 56187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto done; 56287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 56387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* Write to a temporary file to allow for an atomic rename to the 56487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * final destination filename, (to prevent any readers from seeing 56587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * a partially written file). 56687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 56787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri filename_tmp = ralloc_asprintf(cache, "%s.tmp", filename); 56887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (filename_tmp == NULL) 56987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto done; 57087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 57187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri fd = open(filename_tmp, O_WRONLY | O_CLOEXEC | O_CREAT, 0644); 57287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 57387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* Make the two-character subdirectory within the cache as needed. */ 57487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (fd == -1) { 57587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (errno != ENOENT) 57687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto done; 57787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 57887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri make_cache_file_directory(cache, key); 57987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 58087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri fd = open(filename_tmp, O_WRONLY | O_CLOEXEC | O_CREAT, 0644); 58187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (fd == -1) 58287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto done; 58387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 58487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 58587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* With the temporary file open, we take an exclusive flock on 58687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * it. If the flock fails, then another process still has the file 58787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * open with the flock held. So just let that file be responsible 58887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * for writing the file. 58987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 59087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri err = flock(fd, LOCK_EX | LOCK_NB); 59187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (err == -1) 59287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto done; 59387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 59487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* Now that we have the lock on the open temporary file, we can 59587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * check to see if the destination file already exists. If so, 59687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * another process won the race between when we saw that the file 59787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * didn't exist and now. In this case, we don't do anything more, 59887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * (to ensure the size accounting of the cache doesn't get off). 59987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 60087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri fd_final = open(filename, O_RDONLY | O_CLOEXEC); 60187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (fd_final != -1) 60287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto done; 60387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 60487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* OK, we're now on the hook to write out a file that we know is 60587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * not in the cache, and is also not being written out to the cache 60687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * by some other process. 60787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * 60887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * Before we do that, if the cache is too large, evict something 60987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * else first. 61087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 61187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (*cache->size + size > cache->max_size) 61287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri evict_random_item(cache); 61387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 61487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* Now, finally, write out the contents to the temporary file, then 61587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * rename them atomically to the destination filename, and also 61687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * perform an atomic increment of the total cache size. 61787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 61887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri for (len = 0; len < size; len += ret) { 61987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri ret = write(fd, p + len, size - len); 62087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (ret == -1) { 62187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri unlink(filename_tmp); 62287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto done; 62387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 62487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 62587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 62687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri rename(filename_tmp, filename); 62787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 62887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri p_atomic_add(cache->size, size); 62987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 63069cc7d90f9f60d95cd570a4e87755a474554d41fGwan-gyeong Mun done: 63169cc7d90f9f60d95cd570a4e87755a474554d41fGwan-gyeong Mun if (fd_final != -1) 63269cc7d90f9f60d95cd570a4e87755a474554d41fGwan-gyeong Mun close(fd_final); 63387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri /* This close finally releases the flock, (now that the final dile 63487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * has been renamed into place and the size has been added). 63587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 63669cc7d90f9f60d95cd570a4e87755a474554d41fGwan-gyeong Mun if (fd != -1) 63769cc7d90f9f60d95cd570a4e87755a474554d41fGwan-gyeong Mun close(fd); 63887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (filename_tmp) 63987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri ralloc_free(filename_tmp); 64087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (filename) 64187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri ralloc_free(filename); 64287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 64387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 64487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arcerivoid * 645a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšákdisk_cache_get(struct disk_cache *cache, cache_key key, size_t *size) 64687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 64787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri int fd = -1, ret, len; 64887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri struct stat sb; 64987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri char *filename = NULL; 65087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri uint8_t *data = NULL; 65187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 65287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (size) 65387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri *size = 0; 65487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 65587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri filename = get_cache_file(cache, key); 65687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (filename == NULL) 65787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 65887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 65987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri fd = open(filename, O_RDONLY | O_CLOEXEC); 66087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (fd == -1) 66187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 66287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 66387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (fstat(fd, &sb) == -1) 66487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 66587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 66687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri data = malloc(sb.st_size); 66787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (data == NULL) 66887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 66987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 67087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri for (len = 0; len < sb.st_size; len += ret) { 67187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri ret = read(fd, data + len, sb.st_size - len); 67287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (ret == -1) 67387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri goto fail; 67487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri } 67587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 67687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri ralloc_free(filename); 67787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri close(fd); 67887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 67987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (size) 68087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri *size = sb.st_size; 68187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 68287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return data; 68387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 68487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri fail: 68587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (data) 68687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri free(data); 68787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (filename) 68887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri ralloc_free(filename); 68987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri if (fd != -1) 69087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri close(fd); 69187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 69287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return NULL; 69387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 69487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 69587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arcerivoid 696a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšákdisk_cache_put_key(struct disk_cache *cache, cache_key key) 69787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 69887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri uint32_t *key_chunk = (uint32_t *) key; 69987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri int i = *key_chunk & CACHE_INDEX_KEY_MASK; 70087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri unsigned char *entry; 70187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 70287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri entry = &cache->stored_keys[i + CACHE_KEY_SIZE]; 70387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 70487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri memcpy(entry, key, CACHE_KEY_SIZE); 70587ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 70687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 70787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri/* This function lets us test whether a given key was previously 708a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšák * stored in the cache with disk_cache_put_key(). The implement is 70987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * efficient by not using syscalls or hitting the disk. It's not 71087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * race-free, but the races are benign. If we race with someone else 711a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšák * calling disk_cache_put_key, then that's just an extra cache miss and an 71287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri * extra recompile. 71387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri */ 71487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceribool 715a6ff2a3378636f4a261ea32c3dc870b0aeae3c03Marek Olšákdisk_cache_has_key(struct disk_cache *cache, cache_key key) 71687ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri{ 71787ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri uint32_t *key_chunk = (uint32_t *) key; 71887ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri int i = *key_chunk & CACHE_INDEX_KEY_MASK; 71987ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri unsigned char *entry; 72087ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 72187ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri entry = &cache->stored_keys[i + CACHE_KEY_SIZE]; 72287ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri 72387ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri return memcmp(entry, key, CACHE_KEY_SIZE) == 0; 72487ab26b2ab35a29d446ae66f1795d40c184c0739Timothy Arceri} 725acc78377990ba986060214466d44ea364529c363Emil Velikov 726acc78377990ba986060214466d44ea364529c363Emil Velikov#endif /* ENABLE_SHADER_CACHE */ 727