[kernel] Fix block copying in the cache
authorcoderain <coderain@sdf.org>
Wed, 15 Nov 2017 04:31:30 +0000 (05:31 +0100)
committercoderain <coderain@sdf.org>
Wed, 15 Nov 2017 04:31:30 +0000 (05:31 +0100)
kernel/src/cache.c

index 34cb86854c47e3a5633ead00986e932f18742592..fdbed04a7811ec2468f23b4ef8f5673242f70d11 100644 (file)
@@ -65,6 +65,7 @@ dword_t read_cache(cache_descriptor_t *cache, void *context, byte_t *buffer, qwo
     bool_t exclusive = FALSE;
 
     acquire_resource_shared(&cache->resource);
+    *bytes_read = 0;
 
     for (i = first_block; i <= last_block; i++)
     {
@@ -100,10 +101,23 @@ dword_t read_cache(cache_descriptor_t *cache, void *context, byte_t *buffer, qwo
         }
 
         cache_entry_t *entry = CONTAINER_OF(element, cache_entry_t, tree);
-        if (i == first_block) start_offset = (dword_t)(offset % (qword_t)cache->block_size);
-        if (i == last_block) bytes_to_copy = (dword_t)((offset + length - 1) % (qword_t)cache->block_size) - start_offset + 1;
 
-        memcpy(&buffer[(i - first_block) * cache->block_size], &entry->data[start_offset], bytes_to_copy);
+        if (first_block == last_block)
+        {
+            start_offset = (dword_t)(offset % (qword_t)cache->block_size);
+            bytes_to_copy = length;
+        }
+        else if (i == first_block)
+        {
+            start_offset = (dword_t)(offset % (qword_t)cache->block_size);
+            bytes_to_copy -= start_offset;
+        }
+        else if (i == last_block)
+        {
+            bytes_to_copy = length - *bytes_read;
+        }
+
+        memcpy(&buffer[*bytes_read], &entry->data[start_offset], bytes_to_copy);
         *bytes_read += bytes_to_copy;
     }
 
@@ -119,6 +133,7 @@ dword_t write_cache(cache_descriptor_t *cache, void *context, const byte_t *buff
     qword_t last_block = (offset + length - 1) / (qword_t)cache->block_size;
 
     acquire_resource_exclusive(&cache->resource);
+    *bytes_written = 0;
 
     for (i = first_block; i <= last_block; i++)
     {
@@ -149,10 +164,23 @@ dword_t write_cache(cache_descriptor_t *cache, void *context, const byte_t *buff
         }
 
         cache_entry_t *entry = CONTAINER_OF(element, cache_entry_t, tree);
-        if (i == first_block) start_offset = (dword_t)(offset % (qword_t)cache->block_size);
-        if (i == last_block) bytes_to_copy = (dword_t)((offset + length) % (qword_t)cache->block_size) - start_offset;
 
-        memcpy(&entry->data[start_offset], &buffer[(i - first_block) * cache->block_size], bytes_to_copy);
+        if (first_block == last_block)
+        {
+            start_offset = (dword_t)(offset % (qword_t)cache->block_size);
+            bytes_to_copy = length;
+        }
+        else if (i == first_block)
+        {
+            start_offset = (dword_t)(offset % (qword_t)cache->block_size);
+            bytes_to_copy -= start_offset;
+        }
+        else if (i == last_block)
+        {
+            bytes_to_copy = length - *bytes_written;
+        }
+
+        memcpy(&entry->data[start_offset], &buffer[*bytes_written], bytes_to_copy);
         *bytes_written += bytes_to_copy;
 
         if (cache->flags & CACHE_WRITE_THROUGH)