util/disk_cache: add support for detecting corrupt cache entries
authorTimothy Arceri <tarceri@itsqueeze.com>
Fri, 24 Feb 2017 04:14:56 +0000 (15:14 +1100)
committerTimothy Arceri <tarceri@itsqueeze.com>
Fri, 3 Mar 2017 01:09:08 +0000 (12:09 +1100)
V2: fix pointer increments for writing/reading crc

Acked-by: Marek Olšák <marek.olsak@amd.com>
Reviewed-by: Grigori Goronzy <greg@chown.ath.cx>
src/util/disk_cache.c

index f5e114513e0e9c4e6c5a57ba1fdc24609826b142..f8e994853c141d817f8f21310e2dac0f0f59285f 100644 (file)
@@ -38,6 +38,7 @@
 #include <errno.h>
 #include <dirent.h>
 
+#include "util/crc32.h"
 #include "util/u_atomic.h"
 #include "util/mesa-sha1.h"
 #include "util/ralloc.h"
@@ -709,6 +710,19 @@ disk_cache_put(struct disk_cache *cache,
    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.
@@ -723,6 +737,7 @@ disk_cache_put(struct disk_cache *cache,
 
    rename(filename_tmp, filename);
 
+   size += crc_size;
    p_atomic_add(cache->size, size);
 
  done:
@@ -765,17 +780,33 @@ disk_cache_get(struct disk_cache *cache, cache_key key, size_t *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;