[Mesa-dev] [PATCH V2] util/disk_cache: add support for detecting corrupt cache entries

Timothy Arceri tarceri at itsqueeze.com
Thu Mar 2 01:35:11 UTC 2017


V2: fix pointer increments for writing/reading crc
---
 src/util/disk_cache.c | 37 ++++++++++++++++++++++++++++++++++---
 1 file changed, 34 insertions(+), 3 deletions(-)

diff --git a/src/util/disk_cache.c b/src/util/disk_cache.c
index f5e1145..f8e9948 100644
--- a/src/util/disk_cache.c
+++ b/src/util/disk_cache.c
@@ -31,20 +31,21 @@
 #include <sys/file.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <pwd.h>
 #include <errno.h>
 #include <dirent.h>
 
+#include "util/crc32.h"
 #include "util/u_atomic.h"
 #include "util/mesa-sha1.h"
 #include "util/ralloc.h"
 #include "main/errors.h"
 
 #include "disk_cache.h"
 
 /* Number of bits to mask off from a cache key to get an index. */
 #define CACHE_INDEX_KEY_BITS 16
 
@@ -702,34 +703,48 @@ disk_cache_put(struct disk_cache *cache,
    /* OK, we're now on the hook to write out a file that we know is
     * not in the cache, and is also not being written out to the cache
     * by some other process.
     *
     * Before we do that, if the cache is too large, evict something
     * else first.
     */
    if (*cache->size + size > cache->max_size)
       evict_random_item(cache);
 
+   /* Create CRC of the data and store at the start of the file. We will
+    * read this when restoring the cache and use it to check for corruption.
+    */
+   uint32_t crc32 = util_hash_crc32(data, size);
+   size_t crc_size = sizeof(crc32);
+   for (len = 0; len < crc_size; len += ret) {
+      ret = write(fd, ((uint8_t *) &crc32) + len, crc_size - len);
+      if (ret == -1) {
+         unlink(filename_tmp);
+         goto done;
+      }
+   }
+
    /* Now, finally, write out the contents to the temporary file, then
     * rename them atomically to the destination filename, and also
     * perform an atomic increment of the total cache size.
     */
    for (len = 0; len < size; len += ret) {
       ret = write(fd, p + len, size - len);
       if (ret == -1) {
          unlink(filename_tmp);
          goto done;
       }
    }
 
    rename(filename_tmp, filename);
 
+   size += crc_size;
    p_atomic_add(cache->size, size);
 
  done:
    if (fd_final != -1)
       close(fd_final);
    /* This close finally releases the flock, (now that the final dile
     * has been renamed into place and the size has been added).
     */
    if (fd != -1)
       close(fd);
@@ -758,31 +773,47 @@ disk_cache_get(struct disk_cache *cache, cache_key key, size_t *size)
    if (fd == -1)
       goto fail;
 
    if (fstat(fd, &sb) == -1)
       goto fail;
 
    data = malloc(sb.st_size);
    if (data == NULL)
       goto fail;
 
-   for (len = 0; len < sb.st_size; len += ret) {
-      ret = read(fd, data + len, sb.st_size - len);
+   /* Load the CRC that was created when the file was written. */
+   uint32_t crc32;
+   size_t crc_size = sizeof(crc32);
+   assert(sb.st_size > crc_size);
+   for (len = 0; len < crc_size; len += ret) {
+      ret = read(fd, ((uint8_t *) &crc32) + len, crc_size - len);
       if (ret == -1)
          goto fail;
    }
 
+   /* Load the actual cache data. */
+   size_t cache_data_size = sb.st_size - crc_size;
+   for (len = 0; len < cache_data_size; len += ret) {
+      ret = read(fd, data + len, cache_data_size - len);
+      if (ret == -1)
+         goto fail;
+   }
+
+   /* Check the data for corruption */
+   if (crc32 != util_hash_crc32(data, cache_data_size))
+      goto fail;
+
    free(filename);
    close(fd);
 
    if (size)
-      *size = sb.st_size;
+      *size = cache_data_size;
 
    return data;
 
  fail:
    if (data)
       free(data);
    if (filename)
       free(filename);
    if (fd != -1)
       close(fd);
-- 
2.9.3



More information about the mesa-dev mailing list