util/disk_cache: separate file reads from cache item validation
authorTimothy Arceri <tarceri@itsqueeze.com>
Wed, 3 Mar 2021 04:12:09 +0000 (15:12 +1100)
committerMarge Bot <eric+marge@anholt.net>
Tue, 16 Mar 2021 23:37:47 +0000 (23:37 +0000)
This will allow us to share validation between the single file cache
and the multifile cache.

It also reduces the number of malloc() calls.

Reviewed-By: Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9443>

src/util/disk_cache_os.c

index c4a0324..aeed1c9 100644 (file)
@@ -57,6 +57,7 @@ struct cache_entry_file_data {
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include "util/blob.h"
 #include "util/crc32.h"
 #include "util/debug.h"
 #include "util/disk_cache.h"
@@ -373,55 +374,33 @@ disk_cache_evict_item(struct disk_cache *cache, char *filename)
       p_atomic_add(cache->size, - (uint64_t)sb.st_blocks * 512);
 }
 
-void *
-disk_cache_load_item(struct disk_cache *cache, char *filename, size_t *size)
+static void *
+parse_and_validate_cache_item(struct disk_cache *cache, void *cache_item,
+                              size_t cache_item_size, size_t *size)
 {
-   int fd = -1, ret;
-   struct stat sb;
-   uint8_t *data = NULL;
    uint8_t *uncompressed_data = NULL;
-   uint8_t *file_header = NULL;
-
-   fd = open(filename, O_RDONLY | O_CLOEXEC);
-   if (fd == -1)
-      goto fail;
-
-   if (fstat(fd, &sb) == -1)
-      goto fail;
-
-   data = malloc(sb.st_size);
-   if (data == NULL)
-      goto fail;
-
-   size_t ck_size = cache->driver_keys_blob_size;
-   file_header = malloc(ck_size);
-   if (!file_header)
-      goto fail;
 
-   if (sb.st_size < ck_size)
-      goto fail;
+   struct blob_reader ci_blob_reader;
+   blob_reader_init(&ci_blob_reader, cache_item, cache_item_size);
 
-   ret = read_all(fd, file_header, ck_size);
-   if (ret == -1)
+   size_t header_size = cache->driver_keys_blob_size;
+   const void *keys_blob = blob_read_bytes(&ci_blob_reader, header_size);
+   if (ci_blob_reader.overrun)
       goto fail;
 
    /* Check for extremely unlikely hash collisions */
-   if (memcmp(cache->driver_keys_blob, file_header, ck_size) != 0) {
+   if (memcmp(cache->driver_keys_blob, keys_blob, header_size) != 0) {
       assert(!"Mesa cache keys mismatch!");
       goto fail;
    }
 
-   size_t cache_item_md_size = sizeof(uint32_t);
-   uint32_t md_type;
-   ret = read_all(fd, &md_type, cache_item_md_size);
-   if (ret == -1)
+   uint32_t md_type = blob_read_uint32(&ci_blob_reader);
+   if (ci_blob_reader.overrun)
       goto fail;
 
    if (md_type == CACHE_ITEM_TYPE_GLSL) {
-      uint32_t num_keys;
-      cache_item_md_size += sizeof(uint32_t);
-      ret = read_all(fd, &num_keys, sizeof(uint32_t));
-      if (ret == -1)
+      uint32_t num_keys = blob_read_uint32(&ci_blob_reader);
+      if (ci_blob_reader.overrun)
          goto fail;
 
       /* The cache item metadata is currently just used for distributing
@@ -430,44 +409,75 @@ disk_cache_load_item(struct disk_cache *cache, char *filename, size_t *size)
        * TODO: pass the metadata back to the caller and do some basic
        * validation.
        */
-      cache_item_md_size += num_keys * sizeof(cache_key);
-      ret = lseek(fd, num_keys * sizeof(cache_key), SEEK_CUR);
-      if (ret == -1)
+      const void UNUSED *metadata =
+         blob_read_bytes(&ci_blob_reader, num_keys * sizeof(cache_key));
+      if (ci_blob_reader.overrun)
          goto fail;
    }
 
    /* Load the CRC that was created when the file was written. */
-   struct cache_entry_file_data cf_data;
-   size_t cf_data_size = sizeof(cf_data);
-   ret = read_all(fd, &cf_data, cf_data_size);
-   if (ret == -1)
+   struct cache_entry_file_data *cf_data =
+      (struct cache_entry_file_data *)
+         blob_read_bytes(&ci_blob_reader, sizeof(struct cache_entry_file_data));
+   if (ci_blob_reader.overrun)
       goto fail;
 
-   /* Load the actual cache data. */
-   size_t cache_data_size =
-      sb.st_size - cf_data_size - ck_size - cache_item_md_size;
-   ret = read_all(fd, data, cache_data_size);
-   if (ret == -1)
-      goto fail;
+   size_t cache_data_size = ci_blob_reader.end - ci_blob_reader.current;
+   const uint8_t *data = (uint8_t *) blob_read_bytes(&ci_blob_reader, cache_data_size);
 
    /* Check the data for corruption */
-   if (cf_data.crc32 != util_hash_crc32(data, cache_data_size))
+   if (cf_data->crc32 != util_hash_crc32(data, cache_data_size))
       goto fail;
 
    /* Uncompress the cache data */
-   uncompressed_data = malloc(cf_data.uncompressed_size);
+   uncompressed_data = malloc(cf_data->uncompressed_size);
    if (!util_compress_inflate(data, cache_data_size, uncompressed_data,
-                              cf_data.uncompressed_size))
+                              cf_data->uncompressed_size))
+      goto fail;
+
+   if (size)
+      *size = cf_data->uncompressed_size;
+
+   return uncompressed_data;
+
+ fail:
+   if (uncompressed_data)
+      free(uncompressed_data);
+
+   return NULL;
+}
+
+void *
+disk_cache_load_item(struct disk_cache *cache, char *filename, size_t *size)
+{
+   uint8_t *data = NULL;
+
+   int fd = open(filename, O_RDONLY | O_CLOEXEC);
+   if (fd == -1)
+      goto fail;
+
+   struct stat sb;
+   if (fstat(fd, &sb) == -1)
+      goto fail;
+
+   data = malloc(sb.st_size);
+   if (data == NULL)
+      goto fail;
+
+   /* Read entire file into memory */
+   int ret = read_all(fd, data, sb.st_size);
+   if (ret == -1)
+      goto fail;
+
+    uint8_t *uncompressed_data =
+       parse_and_validate_cache_item(cache, data, sb.st_size, size);
+   if (!uncompressed_data)
       goto fail;
 
    free(data);
    free(filename);
-   free(file_header);
    close(fd);
 
-   if (size)
-      *size = cf_data.uncompressed_size;
-
    return uncompressed_data;
 
  fail:
@@ -475,10 +485,6 @@ disk_cache_load_item(struct disk_cache *cache, char *filename, size_t *size)
       free(data);
    if (filename)
       free(filename);
-   if (uncompressed_data)
-      free(uncompressed_data);
-   if (file_header)
-      free(file_header);
    if (fd != -1)
       close(fd);