[Mesa-dev] [PATCH 7/7] glsl/cache: Write newly cached files atomically via rename()

Carl Worth cworth at cworth.org
Wed Feb 4 13:53:01 PST 2015


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



More information about the mesa-dev mailing list