Instead of writing directly to the desired <filename>, with this patch we instead first write to <filename>.tmp and then use rename() to atomically rename from <filename>.tmp to <filename>. This ensures that any process that opens <filename> for reading will never see any partially written file. --- src/glsl/cache.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-)
diff --git a/src/glsl/cache.c b/src/glsl/cache.c index 0bbf659..e0cdc1a 100644 --- a/src/glsl/cache.c +++ b/src/glsl/cache.c @@ -323,9 +323,9 @@ cache_put(struct program_cache *cache, uint32_t *s = (uint32_t *) key; int i = *s & (INDEX_SIZE - 1); unsigned char *entry; - int fd, ret; + int fd = -1, ret; size_t len; - char *filename; + char *filename = NULL, *filename_tmp = NULL; const char *p = (const char *) data; /* FIXME: We'll need an fsync here and think about races... maybe even need @@ -336,40 +336,49 @@ cache_put(struct program_cache *cache, entry = &cache->index[i * CACHE_KEY_SIZE]; filename = get_cache_file(cache, entry); if (filename == NULL) - return; + goto done; unlink(filename); ralloc_free(filename); + filename = NULL; memcpy(entry, key, CACHE_KEY_SIZE); if (data == NULL) - return; - - /* FIXME: We should write the file to a name like <sha1>-foo, close it and - * then rename(2) it to <sha1> to make sure some other mesa process doesn't - * open it and gets a partial result. Racing with another mesa writing the - * same file is ok, since they'll both write the same contents, and whoever - * finishes first will move the complete file in place. */ + goto done; filename = get_cache_file(cache, key); if (filename == NULL) - return; + goto done; - fd = open(filename, O_WRONLY | O_CLOEXEC | O_CREAT, 0644); - ralloc_free(filename); + filename_tmp = ralloc_asprintf(cache, "%s.tmp", filename); + if (filename_tmp == NULL) + goto done; + + fd = open(filename_tmp, O_WRONLY | O_CLOEXEC | O_CREAT, 0644); if (fd == -1) - return; + goto done; for (len = 0; len < size; len += ret) { ret = write(fd, p + len, size - len); if (ret == -1) { - unlink(filename); - break; + unlink(filename_tmp); + goto done; } } close(fd); + fd = -1; + + rename(filename_tmp, filename); + + done: + if (filename_tmp) + ralloc_free(filename_tmp); + if (filename) + ralloc_free(filename); + if (fd != -1) + close(fd); } void -- 2.1.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev